Po co deklarować strukturę, która zawiera tylko tablicę w języku C?

131

Natknąłem się na kod zawierający:

struct ABC {
    unsigned long array[MAX];
} abc;

Kiedy stosowanie takiej deklaracji ma sens?

Joe.Z
źródło

Odpowiedzi:

184

Umożliwia przekazanie tablicy do funkcji przez wartość lub pobranie jej przez wartość z funkcji.

Struktury mogą być przekazywane przez wartość, w przeciwieństwie do tablic, które w tych kontekstach rozpadają się na wskaźnik.

Blagovest Buyukliev
źródło
1
Uważaj na robienie tego z tablicami, więcej niż powiedzmy 16 lub 32 bajtów, dla funkcji, które nie są wbudowane: bardziej wydajne jest przekazywanie ich przez stałą referencję, chyba że wywoływany już potrzebuje kopii tmp, którą może zniszczyć. Jeśli wywołanie / zwrot nie zostaną zoptymalizowane, średnie lub duże tablice (tysiące bajtów) są okropną rzeczą do przekazywania wartości.
Peter Cordes,
85

Kolejną zaletą jest to, że abstrahuje rozmiar, więc nie musisz używać [MAX]całego kodu wszędzie tam, gdzie deklarujesz taki obiekt. Można to również osiągnąć za pomocą

typedef char ABC[MAX];

ale wtedy masz znacznie większy problem: musisz być świadomy, że ABCjest to typ tablicowy (nawet jeśli nie możesz tego zobaczyć, kiedy deklarujesz zmienne typu ABC), inaczej zostaniesz ukąszony faktem, że ABCbędzie to oznaczać coś innego na liście argumentów funkcji a w deklaracji / definicji zmiennej.

Kolejną zaletą jest to, że struktura pozwala później dodać więcej elementów, jeśli zajdzie taka potrzeba, bez konieczności przepisywania dużej ilości kodu.

R .. GitHub PRZESTAŃ POMÓC LODOWI
źródło
45

Możesz skopiować strukturę i zwrócić strukturę z funkcji.

Nie możesz tego zrobić z tablicą - chyba że jest częścią struktury!

Bo Persson
źródło
26

Możesz to skopiować w ten sposób.

struct ABC a, b;
........
a = b;

W przypadku tablicy należałoby użyć funkcji memcpy lub pętli do przypisania każdego elementu.

MetallicPriest
źródło
6
(więc pozwala na czystszy kod - nie spowoduje żadnej różnicy w szybkości itp.)
John Carter,
3
To przydatne. Niestety nie możesz tego zrobić, jeśli (a == b)!?! jakie to niespójne. W C ++ szuka operatora ==. W C mówi "nieprawidłowe operandy do binarnego ==".
Matt
11

Możesz użyć struct, aby utworzyć nowy typ danych, taki jak ciąg . możesz zdefiniować:

struct String {
    char Char[MAX];
};

lub możesz utworzyć Listę danych, których możesz użyć jako argument funkcji lub zwrócić ją w swoich metodach. Struktura jest bardziej elastyczna niż tablica, ponieważ może obsługiwać niektóre operatory, takie jak =, i możesz zdefiniować w niej niektóre metody.

Mam nadzieję, że to Ci się przyda :)

Hossein Mobasher
źródło
2
Zasadniczo jest to najbliższa rzecz, jaką C ma do stworzenia klasy. Podoba mi się ta odpowiedź, ponieważ jest najbliżej wskazania tego.
Nate CK
1
Żadne coś takiego jak metoda w C. structs w C nie jest zwykłymi starymi danymi. Ma domyślnie obsługiwany operator = (co wynika z innych odpowiedzi), ale jest to mylące i dotyczy głównie C ++, a nie C.
Jonathan Sternberg
3
@J Sternberg: „Metoda” to tylko sposób myślenia o podprogramach jako powiązanych z „obiektami” danych, na które wpływają. Z pewnością można tworzyć „klasy” „obiektów” i „metod”, które operują na nich w C. Język po prostu formalnie nie definiuje takich rzeczy. Jeśli chcesz tworzyć lepsze abstrakcje w C, upychanie rzeczy do struktury jest zwykle najlepszym sposobem na zrobienie tego.
Nate CK
Ponadto, jeśli naprawdę chciałbyś „stworzyć” metody w C, możesz użyć wskaźników funkcji (tak, tak, skomplikowana składnia, brak ochrony danych itp.) W celu powiązania funkcji z danymi, na których działają. W pierwszym argumencie musisz podać "self" (możesz nawet nazwać to "this", jeśli chcesz), ponieważ nie ma automatycznego tworzenia tego wskaźnika wewnątrz funkcji w C. Oczywiście to wszystko gimnastyka, dostajesz rzeczy takie jak ta domyślnie w C ++, chociaż to prawda, może być ukryty narzut jako bonus ...
BenPen
2

Inną zaletą stosowania takiego znakustruct jest to, że wymusza bezpieczeństwo typu wszędzie tam, gdzie taki structjest używany; zwłaszcza jeśli masz dwa typy składające się z tablic o tym samym rozmiarze używanych do różnych celów, typy te pomogą Ci uniknąć przypadkowego niewłaściwego użycia tablicy.

Jeśli nie zawiniesz tablicy w a struct, nadal możesz zadeklarować typedefdla niej a: ma to pewne zalety struct- • typ jest zadeklarowany raz, • rozmiar jest automatycznie poprawny, • intencja kodu staje się jaśniejsza, • a kod jest łatwiejszy w utrzymaniu - ale tracisz ◦ ścisłe bezpieczeństwo typów, ◦ możliwość kopiowania i zwracania wartości typu oraz ◦ możliwość późniejszego dodawania członków bez niszczenia reszty kodu. Dwie typedefs dla gołych tablic danego typu dają różne typy tylko wtedy, gdy mają różne rozmiary. Co więcej, jeśli użyjesz typedefbez *w argumencie funkcji, jest to równoważne z char *drastycznym zmniejszeniem bezpieczeństwa typów.

Podsumowując :

typedef struct A_s_s { char m[113]; } A_s_t; // Full type safey, assignable
typedef char   A_c_t[113];                   // Partial type-safety, not assignable

A_s_t          v_s(void);     // Allowed
A_c_t          v_c(void);     // Forbidden

void           s__v(A_s_t);     // Type-safe, pass by value
void           sP_v(A_s_t *);   // Type-safe
void           c__v(A_c_t);     // UNSAFE, just means char * (GRRR!)
void           cP_v(A_c_t *);   // SEMI-safe, accepts any array of 113
PJTraill
źródło
1

Struktura może zawierać funkcje inicjalizacji tablicy, kopiowania i fini emulujące niektóre zalety paradygmatów zarządzania pamięcią OOP. W rzeczywistości bardzo łatwo jest rozszerzyć tę koncepcję, aby napisać ogólne narzędzie do zarządzania pamięcią (używając struktury sizeof (), aby dokładnie wiedzieć, ile bajtów jest zarządzanych) w celu zarządzania dowolną strukturą zdefiniowaną przez użytkownika. Wiele inteligentnych baz kodu produkcyjnego napisanych w C używa ich intensywnie i zazwyczaj nigdy nie używa tablic, chyba że ich zakres jest bardzo lokalny.

W rzeczywistości w przypadku tablicy osadzonej w strukturze można wykonać inne „inteligentne rzeczy”, takie jak sprawdzanie powiązań w dowolnym momencie, gdy chciał się uzyskać dostęp do tej tablicy. Ponownie, chyba że zasięg tablicy jest bardzo ograniczony, używanie go i przekazywanie informacji między programami jest złym pomysłem. Wcześniej czy później napotkasz błędy, które nie pozwolą ci zasnąć w nocy i zrujnują twoje weekendy.

Aniket
źródło
Nie odpowiada to na pytanie, dlaczego można by użyć tablicy structzawierającej tylko tablicę.
PJTraill