W C++ jaka jest różnica (jeśli jest) między używaniem char i char [1].Różnica między char i char [1]
przykładów:
struct SomeStruct
{
char x;
char y[1];
};
Czy te same powody naśladowania dla unsigned char?
W C++ jaka jest różnica (jeśli jest) między używaniem char i char [1].Różnica między char i char [1]
przykładów:
struct SomeStruct
{
char x;
char y[1];
};
Czy te same powody naśladowania dla unsigned char?
Główną różnicą jest tylko składnia, której używasz, aby uzyskać dostęp do jednego znaku.
Przez "dostęp" mam na myśli, działać na nim za pomocą różnych operatorów w języku, z których większość lub wszystkie robią różne rzeczy po zastosowaniu do char
w porównaniu z tablicą char
. To sprawia, że brzmi to tak, jakby x
i y
były prawie całkowicie inne. Jeśli tak, to oba składają się z "jednego znaku", ale ten znak został przedstawiony w zupełnie inny sposób.
Może to spowodować inne różnice, na przykład może wyrównać i podparć konstrukcję w różny sposób, zgodnie z tym, którego używasz. Ale wątpię, że tak będzie.
Przykładem operatora różnic jest to, że znak jest przypisywany i tablica nie jest:
SomeStruct a;
a.x = 'a';
a.y[0] = 'a';
SomeStruct b;
b.x = a.x; // OK
b.y = a.y; // not OK
b.y[0] = a.y[0]; // OK
Jednak fakt, że nie jest przypisywane y
nie zatrzymuje SomeStruct
być przypisane:
b = a; // OK
Wszystko to niezależnie od typu, char
lub nie. Obiekt typu i tablica tego typu o rozmiarze 1 są prawie takie same, jeśli chodzi o to, co jest w pamięci.
Na marginesie, istnieje kontekst, w którym robi wielką różnicę, którą "używasz" z char
i char[1]
, a która czasami pomaga mylić ludzi z myślą, że tablice są naprawdę wskazówkami. Nie był to przykład, ale jako parametr funkcji:
void foo(char c); // a function which takes a char as a parameter
void bar(char c[1]); // a function which takes a char* as a parameter
void baz(char c[12]); // also a function which takes a char* as a parameter
Liczby podane w deklaracjach bar
i baz
są całkowicie ignorowane przez język C++. Najwidoczniej ktoś w pewnym momencie uznał, że programistom będzie przydatna jako forma dokumentacji, wskazując, że funkcja baz
spodziewa się, że argument wskaźnika wskaże pierwszy element tablicy złożonej z 12 znaków.
W barach i bazach, c
nigdy nie ma typu tablicy - wygląda na typ tablicy, ale nie jest, jest to po prostu wyjątkowa składnia o tym samym znaczeniu co char *c
. Dlatego umieszczam znaki cudzysłowu na "użytek" - w rzeczywistości tak naprawdę nie używasz char[1]
, tylko tak to wygląda.
+1, Jestem zmęczony wszystkimi odpowiedziami mówiącymi, że 'y' jest wskaźnikiem. – casablanca
Ładna i przejrzysta odpowiedź. Inną rzeczą, która będzie inna, jest inicjalizacja z konstruktorami (jeśli miałby ją dodać), co niestety nie działa w obecnym C++ z tablicami (innymi niż wartościowanie-inicjowanie ich). –
Główna różnica to tak naprawdę * typ * przypisany przez system typów. 'x' jest typu' char', a 'y' jest typu' char [1] '. Wiem, że to brzmi jak stwierdzenie oczywistości, ale to naprawdę główna różnica. Nie możesz przekazać 'y' do funkcji, która oczekuje na przykład' char' jako parametru. Ale ostatecznie zarówno x, jak i y zwrócą tę samą wartość po przekazaniu do operatora 'sizeof' i prawdopodobnie będą reprezentowane w ten sam sposób w pamięci. Również "y" może ulec degradacji do wskaźnika, co oznacza, że możesz przekazać go do czegoś takiego jak "strcpy", ale nie możesz tego zrobić z 'x' –
Jeśli faktycznie widziałeś konstrukt char y[1]
jako ostatniego członka struct w kodzie produkcyjnym, to jest całkiem prawdopodobne, że napotkasz wystąpienie struct hack.
Ta krótka tablica jest stand-inem dla prawdziwej, ale zmiennej długości tablicy (pamiętaj, że przed c99 nie było czegoś takiego w standardzie c). Programista zawsze przypisywałby takie struktury do sterty, upewniając się, że alokacja była wystarczająco duża dla faktycznego rozmiaru macierzy, której chciał użyć.
A jeśli zobaczysz strukturę hack w kodzie C++, martw się ... –
Steve: O ile ten kod C++ nie wymaga rozmowy z kodem C. Na przykład kod C++ zużywający Win32APIs –
@Billy: oczywiście, jeśli hack pojawia się w strukturze zdefiniowanej przez niektóre API C, to jest w porządku. Domyślam się, że hack jest nadal "w C++", w tym sensie, że nagłówek staje się C++, gdy tylko "# include" to w programie C++, więc w porządku, to wyjątek od mojej reguły. –
Oprócz notacyjnych różnic w użyciu podkreślanych przez Steve'a, char [1] można przekazać np. template <int N> void f(char(&a)[N])
, gdzie char x = '\0'; f(&x);
nie pasuje. Rzetelne przechwytywanie wielkości argumentów tablicowych jest bardzo wygodne i uspokajające.
Może to również sugerować coś innego: albo faktyczna długość może być dłuższa (jak wyjaśniono przez dmckee), albo że treść jest logicznie ciągiem ASCIIZ (który w tym przypadku jest pusty) lub tablicą postacie (które mają jeden element). Jeśli struktura była jedną z kilku powiązanych struktur (np. Wektor matematyczny, w którym rozmiar tablicy był argumentem szablonu lub kodowanie układu pamięci potrzebnej do operacji we/wy), to jest całkowicie możliwe, że pewne podobieństwo z innymi polami gdzie tablice mogą być większe, sugerowałoby preferencję dla tablicy jednoliterowej, umożliwiając uproszczenie kodu pomocniczego i/lub bardziej uniwersalne zastosowanie.
Ilość błędnych odpowiedzi na to pytanie jest zdumiewająca. +1 za to, że pytasz o coś, co ludzie często nie rozumieją. –
Przeczytałem to pytanie i prawie w tym momencie setki klawiatur wściekle pisząc, by jako pierwsza odpowiedziały. – Anthony
@Billy, @Duracell: Niestety większość programistów C i C++ tak naprawdę nie rozumie tablic. Z jednej strony jest to nieco zaskakujące, biorąc pod uwagę ich fundamentalne znaczenie; z drugiej strony rozpad tablic i sposób, w jaki działa indeksowanie, ułatwia początkującym myślenie, że tablice są tym samym co wskaźniki. –