Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

ANSI C - Dynamiczna tablica wskaźników na strukturę

jowyma 17 Jan 2015 17:27 1623 11
  • #1
    jowyma
    Level 23  
    Proszę o pomoc czy dobrze myślę. Tworzę strukturę która zawiera informacje o jednej osobie. Mam teraz w main stworzyć tablicę 10 struktur. Wydaje mi się na podstawie książek i z google, że należy wykorzystać definicję typu A.

    A->struktura nazwa * tablica
    czy
    B->struktura nazwa ** tablica?

    Jak na toto alokować pamięć?
    A->tablica = malloc(10 * sizeof(struktura))
    czy
    B->
    (*tablica)=malloc(10*sizeof(struktura));
    tablica[0]=malloc(sizeof(struktura));
    tablica[1]=malloc(sizeof(struktura));
    i tak dalej.

    Ale w takim razie kiedy by należało użyć definicji typu B.
  • Helpful post
    #2
    ania13L
    Level 12  
    To co piszesz wyglada jakbys chcial aby jednym z pol Twojej struktury byla tablica? O to Ci chodzi?
    Bo jesli masz stworzyc tablice po prostu 10 struktur to wcale nie musisz mieszac w to wskaznikow. Mozesz to zrobic po prostu:
    struct nazwa tab[10] i pozniej odwolywac sie do elementow tej tablicy nawez przez [] czyli tab[i] np tab[i].pole1 (badz mozesz przez *)
    Mozesz oczywiscie zadeklarowac ta tablice z uzyciem wskaznikow i to bedzie wygladac tak:
    struct nazwa * tab = (struct nazwa *) malloc(sizeof(struct nazwa) * 10);
    Pozniej mozesz sie odwolywac do tab tak jak wyzej: tab[i] lub *tab i tab++ ktore przesunie wskaznik.

    Jesli chodzi jednak o cos innego to wyjasnij dokladnie.
  • Helpful post
    #3
    wondurbm
    Level 16  
    Obie metody są dobre.

    W metodzie A definiujesz wskaźnik na tablicę obiektów typu struktura, a następnie alokujesz pamięć na 10 tego typu obiektów. I to jest metoda prostsza.

    Metoda B jest bardziej złożona. Nie alokujesz od razu jednej tablicy na wszystkie elementy, ale tworzysz tablicę wskaźników, z których każdy dopiero wskazuje na obiekt typu struktura, dla którego pamięć musi być oddzielnie alokowana. Tej metody używa się w przypadku, gdy nie chcemy alokować od razu całej pamięci albo nie wiadomo z góry ile obiektów będzie trzeba utworzyć.

    Jeżeli używasz ANSI C musisz pamiętać, że użycie słowa kluczowego struct jest obowiązkowe (dopiero w C++ można je pominąć).

    Przykłady powinny wyglądać tak:

    A.
    Code: c
    Log in, to see the code


    B.
    Code: c
    Log in, to see the code
  • #4
    jowyma
    Level 23  
    A może mi ktoś pomóc czy dobrze rozumiem jakby potem wyglądało wypełnianie pól struktury.
    Załóżmy, że:

    Code: cpp
    Log in, to see the code


    W układzie B:
    Code: cpp
    Log in, to see the code

    W układzie A:
    ?????
  • Helpful post
    #5
    ania13L
    Level 12  
    W ukladzie A by bylo:
    Code: c
    Log in, to see the code



    Ale w ukladzie A moze byc tez:
    Code: c
    Log in, to see the code


    Ten zwierzchnik jest Ci potrzebny? Bo nie musisz tu uzywac wskaznikow na nastepny element - to gwarantuje tablica.

    Jak cos nie do konca jasne pytaj :)
  • Helpful post
    #6
    wondurbm
    Level 16  
    Po pierwsze proponowałbym w strukturze już nie używać wskaźników tylko od razu tablic typu char o zadanej długości, bo alokacja pamięci dla każdego elementu struktury jest uciążliwa i może prowadzić do błędów. Poza tym w przypadku kopiowania ciągów znaków należy użyć funkcji strcpy() zdefiniowanej w pliku nagłówkowym strings.h. No i po trzecie, w definicja struktury powinna wyglądać nieco inaczej:

    Code: c
    Log in, to see the code


    Wtedy w przypadku A powinno być:

    Code: c
    Log in, to see the code


    Zaś w przypadku B:

    Code: c
    Log in, to see the code
  • #7
    jowyma
    Level 23  
    Zwierzchników nie ma w tej tablicy, będą dołożeni w osobnych strukturach poza tablicą.
    Strcpy można używać i jest to bezpieczniejsze, ale można też zastosować zwykłe przypisanie - u mnie to działa, jeżeli to jest z góry podany konkretny string.
    Co do stringów o stałej długości to mi nie wolno, tak naprawdę to ja robię tak:

    Code: cpp
    Log in, to see the code


    Bardzo dziękuję za wyjaśnienia. Tak z ciekawości, czy dobrze rozumiem, że rozwiązanie B byłoby też użyteczne gdyby było 10 rodzin po 10 członków każda?
  • Helpful post
    #8
    ania13L
    Level 12  
    Tak, bo w rozwiazaniu B masz tablice wskaznikow, i pod kazdy z tych wskaznikow mozesz wstawic jedna strukture (jak masz u siebie w kodzie tablica[0]=malloc(sizeof(osoba)); ) ale nic nie stoi na przeszkodzie aby podstawic tam cala tablice (tablica[0]=malloc(sizeof(osoba) * 10); ).
  • Helpful post
    #9
    wondurbm
    Level 16  
    Tak dla porządku wyjaśnię, że zwykłe przypisanie:
    tablica[i]->imie = "Jan";
    jest błędne i niebezpieczne, ponieważ powoduje nadpisanie wskaźnika do pamięci zaalokowanej wcześniej przez malloc(). Działa tylko z pozoru dobrze, ale może nieźle namieszać.

    Natomiast sposób jaki jest na listingu jest poprawny (z dokładnością do brakujących nawiasów).

    Sposób B jest również użyteczny w przypadku bardziej zagnieżdżonych struktur danych.
  • #10
    jowyma
    Level 23  
    Po zmianie na sposób A program nie zapamiętuje danych osób poza pierwszą. Co robię źle??

    Code: cpp
    Log in, to see the code
  • Helpful post
    #11
    kspro
    Level 27  
    Kopiujesz nazwisko zawsze do zerowego elementu tablicy zamiast do i-tego:

    strcpy(tablica[0].nazwisko, nazw);

    W tej sytuacji zapamiętywane jest tylko ostatnie nazwisko, przy czym może dojść do przekroczenia bufora przydzielonego przez malloc() jeśli jakieś nazwisko jest dłuższe od pierwszego. Wszystkie następne bufory zawierają śmieci, co pewnie jest widoczne podczas wyświetlania w ostatniej pętli.
  • #12
    jowyma
    Level 23  
    Faktycznie, ślepota ze mnie. Wszystko już działa jak powinno. Dziękuję jeszcze raz.