Łatwiutkie pytanko: przekazywanie danych i wyświetlanie struktur

0

Witam, mam pytanie dotyczące struktur w C. Załóżmy, że mam program z taką strukturą:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    struct osoba
    {
        char imie[10];
        char nazwisko[10];
        int wiek;

    };

    struct osoba xyz;


    printf("Podaj swoje imie, nazwisko oraz wiek:\nPodaj imie: ");
    scanf("%s", xyz.imie);
    printf("Podaj nazwisko: ");
    scanf("%s", xyz.nazwisko);
    printf("Podaj wiek: ");
    scanf("%d", &xyz.wiek);

    printf("\nPodales nst. dane:\n");
    printf("Imie: %s\n", xyz.imie);
    printf("Nazwisko: %s\n", xyz.nazwisko);
    printf("Wiek: %d\n", xyz.wiek);


    return 0;
}

Jest jakiś szybszy sposób no to, żeby wczytać dane do struktury, a potem je wyświetlić? Tutaj jeszcze nie jest to problemem, bo mamy tylko 3 elementy struktury, ale gdyby było ich 10, to musiałbym tyle razy napisać printf/scanf. Od biedy można jeszcze zrobić takie coś:

printf("Imie: %s\nNazwisko: %s\nWiek: %d",xyz.imie, xyz.nazwisko, xyz.wiek);

Ale i tak muszę wypisać wszystkie zmienne, a czy można np. wrzucić to w pętle i poprzez iteracje zmieniać pola w strukturze?
Pozdrawiam.

0

Raczej nie, bo pakujesz dane prosto do pól struktury.

0

Czyli co? Jakbym miał strukturę, w której byłoby 20 pól, to każde pole muszę wyświetlać oddzielnie? Naprawdę nie da rady tego zrobić jakoś szybciej poprzez pętle? xd
I jeszcze takie pytanko: skoro nie można tego zrobić w C, to czy jest no to jakiś sposób w C++?

1

Ani w C ani w C++ (bez dodatkowych bibliotek) tego nie zrobisz.

2
kario97 napisał(a):

Czyli co? Jakbym miał strukturę, w której byłoby 20 pól, to każde pole muszę wyświetlać oddzielnie? Naprawdę nie da rady tego zrobić jakoś szybciej poprzez pętle? xd

Do takich rzeczy potrzebne jest RTTI.

I jeszcze takie pytanko: skoro nie można tego zrobić w C, to czy jest no to jakiś sposób w C++?

Nom, zobacz tutaj – https://stackoverflow.com/questions/19059157/iterate-through-struct-and-class-members.

1

Jest jeszcze jeden sposób – wskaźniki. ;)

Warunek jest taki, że liczba pól, ich typy danych oraz rozmiar muszą być znane podczas pisania kodu. Drugi warunek to sensowny ich rozkład – np. pogrupowanie pól o takim samym typie, jedna grupa po drugiej.

O co chodzi – należy pobrać adres pierwszego pola danego typu i w pętli wyświetlać dane na jakie wskazuje nasz pointer oraz inkrementować jego adres o rozmiar tego pola. Kolejna grupa pól to kolejna pętla i kolejny wskaźnik (chyba że użyjesz jednego wskaźnika dla wszystkich pętli i posłużysz się rzutowaniem).

Pozostaje tylko kwestia wyrównywania zawartości struktur – trzeba wiedzieć ile konkretnie zajmują pola, aby móc poprawnie inkrementować adres wskaźnika wewnątrz pętli.

0

Jeśli miałbyś dane jednego typu byloby łatwe, jeśli różnych trypów, toż można to zrobić, ale wymaga to dodatkowych zmiennych/danych, więc nie zawsze jest opłacalne....

0

Nie da się i nie powinno się dać. Różne typy. Jeśli chciałbyś pętli, to powinieneś użyć tab;icy -- a jeśli się nie da użyć tablicy, to używanie pętli byłoby szkodliwe.

0
koszalek-opalek napisał(a):

Nie da się i nie powinno się dać. Różne typy.

No właśnie da się i powinno się dać – bo niby czemu nie? ;)

Posłużę się tutaj przykładem w Pascalu, dlatego że to w sumie ”ta sama liga” co C, ale też dlatego, że chwilę by mi zajęło przypomnienie sobie składni dla wskaźników. Prosta struktura z kilkoma polami, dwa różne typy:

type
  TRecString = String[20];
  PRecString = ^TRecString;

type
  TSomeRecord = packed record
    Name: String[20];
    Surename: String[20];
    Address: String[20];
    Age: UInt8;
    Sex: UInt8;
    ID: UInt8;
  end;

I procedurka wyświetlająca jej zawartość, bez odwoływania się do pól po identyfikatorach. Jeden wskaźnik typu ogólnego plus rzutowanie, dwie pętle (bo dwie grupy pól tego samego typu danych):

procedure PrintRecord(const ARect: TSomeRecord);
var
  Ptr: Pointer;
  I: Integer;
begin
  Ptr := @ARect;

  for I := 0 to 2 do
  begin
    WriteLn('"', PRecString(Ptr)^, '"');
    Ptr += SizeOf(TRecString);
  end;

  for I := 0 to 2 do
  begin
    WriteLn('"', PUInt8(Ptr)^, '"');
    Ptr += SizeOf(UInt8);
  end;
end;

I tak jak wspomniałem wcześniej – jest to możliwe pod warunkiem, że znana jest liczba pól, ich kolejność oraz typ danych, a także sposób w jaki kompilator wyrównuje pola w strukturze. Ja posłużyłem się packed record-em, aby zlikwidować wyrównywanie.

No dobrze, na koniec przykład wykorzystania:

var
  Some: TSomeRecord;
begin
  Some.Name := 'furious';
  Some.Surename := 'programming';
  Some.Address := '4programmers.net';
  Some.Age := 64;
  Some.Sex := 1;
  Some.ID := 128;

  PrintRecord(Some);
end.

Na wyjściu otrzymamy prawidłowe dane:

"furious"
"programming"
"4programmers.net"
"64"
"1"
"128"

Do potestowania tutaj jest wrzutka: https://ideone.com/mBKXVk

Oczywiście bez problemu można to wykonać w C. Dla małych struktur oraz takich, w których dane nie są jakoś sensownie poukładane, funkcja wyświetlająca będzie dość długa.

1

@furious programming: Wersja C

#include <stdio.h>

struct Test
{
    char* name;
    char* surname;
    char* address;
    int age;
    int sex;
    int id;
};

int main()
{
    struct Test test = {"furious", "programming", "4programmers.net", 64, 1, 128};

    char *c_pntr = test.name;
    char c;
    for(int i = 0; i < 3; i++)
    {
        while((c = *c_pntr++) != '\0')
            printf("%c", c);
        printf("\n");
    }

    int *i_pntr = &test.age;
    for(int i = 0; i < 3; i++)
    {
        printf("%d\n", *i_pntr++);
    }
    return 0;
}

Wyjście oczywiście takie same.

0

@furious programming: Da się, to prawda. :) Ale trzeba wiedzieć dużo o strukturze i nie powinno tak się robić, naprawdę... To proszenie się o kłopoty.

W ten sposób da się też zajrzeć do prywatnego pola klasy... Ale nie o to chodzi w programowaniu struktur...

No i Twój sposób jest nieprzenośny.

0

Pytanie brzmiało czy się da, a nie czy ma to sens. Najwyżej ten przykład stanie się tylko ciekawostką. ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1