Poprawny sposób deklarowania zmiennych wskaźnikowych w C / C ++ [zamknięte]

92

Zauważyłem, że niektórzy używają następującej notacji do deklarowania zmiennych wskaźnikowych.

(a) char* p;

zamiast

(b) char *p;

Używam (b). Jakie jest uzasadnienie zapisu (a)? Notacja (b) ma dla mnie większy sens, ponieważ wskaźnik znaku sam w sobie nie jest typem. Zamiast tego typ jest znakowy, a zmienna może być wskaźnikiem do znaku.

char* c;

Wygląda na to, że istnieje typ char *, a zmienna c jest tego typu. Ale w rzeczywistości typ to char, a * c (miejsce w pamięci wskazywane przez c) jest tego typu (char). Jeśli zadeklarujesz wiele zmiennych naraz, to rozróżnienie stanie się oczywiste.

char* c, *d;

To wygląda dziwnie. Zarówno c, jak i d są tego samego rodzaju wskazówkami, które wskazują na znak. W tym od następnego wygląda bardziej naturalnie.

char *c, *d;

Dzięki.

keeda
źródło
7
Co masz na myśli mówiąc, że wskaźnik znaku nie jest typem? Czy mówisz, że wskaźnik nie jest typem?
Benjamin Lindley,
1
Uważam, że to kwestia preferencji, chyba że patrzysz na konkretny przewodnik po stylu (tj. Twoja firma może mieć określony standard kodowania, którego musisz przestrzegać). Mam tendencję do mieszania tego między wyborem b a niektórymi miejscami pośrodku. Czasami czuję, że nie char *twygląda dobrze, więc char * t;zamiast tego mogę to zrobić . Jednak ja też często widziałem char* t;.
RageD,
1
Również twoje rozumowanie „typ to char, a * c (miejsce w pamięci wskazywane przez c) jest tego typu (char)” wydawałoby się wskazywać, że jest zadeklarowany znak char, podczas gdy w rzeczywistości go nie ma. Jeśli tak jest traktowany, jak to bywa czasami przez początkujących, z pewnością doprowadzi to do naruszenia dostępu do pamięci.
Benjamin Lindley,
1
Oba są wciąż wystarczająco opisowe, (b) pokazuje * p jest typu charoraz (a) pokazuje p jestpointer to a char
osoba
1
Dzięki ponad dziesięcioletniemu doświadczeniu w branży, dziś po raz pierwszy pojawiło się to i tylko podczas czytania artykułów innych specjalistów z branży. Oczywiście, więc nigdy nie rozmawiałem na ten temat z religijną rozmową, tak jak to robiłem z tabulatorami i spacjami, komentarzami według definicji lub decyzyjnymi lub jakimikolwiek innymi „dobrze jest nie mieć nic ważniejszego do dyskusji”. . Z tego punktu widzenia wolałem, tak późno w mojej karierze, częściej niż nie chodzić z char * p. Tak, przestrzeń przed, przestrzeń po. Przede wszystkim, jak uważam, zmniejsza błędy, ponieważ sprawia, że ​​wskaźnik jest bardziej oczywisty.
Kit10

Odpowiedzi:

102

Bjarne Stroustrup powiedział:

Wybór między "int * p;" i „int * p;” nie chodzi o dobro i zło, ale o styl i nacisk. C podkreślone wyrażenia; deklaracje często uważano za coś więcej niż zło konieczne. Z drugiej strony C ++ kładzie duży nacisk na typy.

„Typowy programista C” pisze „int * p;” i wyjaśnia to „* p jest tym, czym jest int”, podkreślając składnię i może wskazywać na gramatykę deklaracji C (i C ++), aby argumentować za poprawnością stylu. Rzeczywiście, * wiąże się z imieniem p w gramatyce.

„Typowy programista C ++” pisze „int * p;” i wyjaśnia to „p jest wskaźnikiem do typu podkreślającego int”. Rzeczywiście typ p to int *. Wyraźnie wolę ten nacisk i uważam, że jest to ważne dla dobrego korzystania z bardziej zaawansowanych części C ++.

Źródło: http://www.stroustrup.com/bs_faq2.html#whitespace

Poleciłbym ten drugi styl, ponieważ w sytuacji, gdy deklarujesz wiele wskaźników w jednej linii (Twój czwarty przykład), gwiazdka ze zmienną będzie tym, do czego jesteś przyzwyczajony.

Maczuga
źródło
34
Inni zalecają, aby nigdy nie deklarować kilku obiektów w tej samej deklaracji. :-)
Bo Persson
5
Podkreślam logikę składni, dlatego wolę:, int *pco oznacza: kiedy pjest dereferencjonowany, otrzymuję plik int. Wtedy wiele deklaracji rozdzielonych przez ,ma sens: int *p, *q, r(gdy dereferencja plub qjest dereferencjonowana, otrzymuję int, kiedy rjest odwołanie, otrzymuję int). Również składnia wskaźnika funkcji ma sens: int (*f)()(kiedy fjest wyłuskiwany i nazywany, otrzymuję int). I to ma sens: int *p, (*f)().
Druesukker
2
To pomogło mi uświadomić sobie, że druga strona argumentacji jest słuszna. Będąc głównie programistą wysokiego poziomu, kładę nacisk na typ; i wolę int*. Dla mnie int *p, (*f)()nie ma to większego sensu, ale w pewnym sensie widzę, jak by to było dla niektórych ludzi w niektórych sytuacjach.
Assimilater
1
@Druesukker, myślę, że twoje stwierdzenie ma więcej sensu niż którekolwiek z powyższych.
Muntashir Akon
1
@Druesukker Ale logika nie działa dokładnie dla void*(i nie działa w ogóle dla referencji C ++).
jamesdlin
58

Osobiście wolę umieszczać *z resztą typu

char* p;  // p is a pointer to a char.

Ludzie będą się kłócić „ale potem zaczną char* p, q;wprowadzać w błąd”, na co ja mówię „więc nie rób tego”.

ikegami
źródło
Bardzo dobry argument za char * p; wybór :) Nie mam nic przeciwko żadnemu z nich, o ile nie jest to trudne do odczytania, jak pokazałeś przykład, w którym przypadku nie powinni tego robić.
Jesus Ramos,
1
A kiedy chcesz wyprowadzić wartość? Ty tak cout << *p;. Dlaczego więc nie postawić gwiazdki przed p deklaracją *p:? Moim zdaniem byłoby mniej zagmatwane.
user1170330
13
@ user1170330, Ponieważ w jednym miejscu jest to część definicji typu, aw drugim jest operatorem wyłuskiwania. Bez związku. Jeśli już, dobrze, że wyglądają inaczej, ponieważ różne rzeczy powinny wyglądać inaczej.
ikegami
33

Nie ma różnicy, jak pisać. Ale jeśli chcesz zadeklarować dwa lub więcej wskaźników w jednej linii, lepiej użyj wariantu (b), ponieważ jest jasne, czego chcesz. Zobacz poniżej:

int *a;
int* b;      // All is OK. `a` is pointer to int ant `b` is pointer to int
char *c, *d; // We declare two pointers to char. And we clearly see it.
char* e, f;  // We declare pointer `e` and variable `f` of char type.
             // Maybe here it is mistake, maybe not. 
// Better way of course is use typedef:
typedef char* PCHAR;
PCHAR g, h;  // Now `g` and `h` both are pointers.
// If we used define construction for PCHAR we'd get into problem too.
George Gaál
źródło
5
typedefnie jest lepszym sposobem „oczywiście”. Niektórzy ludzie mogą to preferować, ale problematyczne jest, jeśli z kodem pracuje wiele osób. Gdybym nie był do tego przyzwyczajony PCHAR, mógłbym napisać coś w stylu PCHAR *p;, co byłoby char**a nie to, co zamierzam. Ogólnie rzecz biorąc, jeśli chcesz char**, musiałbyś napisać PCHAR*lub zdefiniować nowy typ, a wtedy zaczyna się po prostu głupie.
BlackJack,
3
Jeśli potrzebujesz jakiegoś złożonego typu wskaźnika, takiego jak wskaźnik do funkcji, bardzo dobrym pomysłem jest zrobienie typedef. W tym przypadku znacznie upraszczają kod. Z drugiej strony stosowanie PCHAR jest przykładem bardziej syntetycznym niż codzienna praktyka. Ale wyraźnie robi to, czego chcesz. a potem po prostu zaczyna
robić
Jeśli napisałeś PCHAR * p, aby zdefiniować wskaźnik do char, byłoby oczywiste, że nie wiesz, co robisz i nie przeczytałeś typu def. Odpowiedź jest jego zdaniem. Jest jeszcze jedna korzyść z typedef; w C jest to łatwy sposób na nieprzezroczystość. publicznie mieć symbol zdefiniowany jako VOID ptr, prywatnie typ def jest czymś innym ... Wolałbym raczej modyfikować typedef raz na jakiś czas, a potem dostosowywać wszystko w kodzie, gdy zmieniamy coś w jednym z typów ... C ++ 11 rozwiązuje większość tego
problemu za pomocą automatów
Dla kogoś, kto dopiero pięć lat po college'u próbuje wrócić do zabawy z C ++, to jedna z najlepszych odpowiedzi.
Panzercrisis
10

Kompromis jest

char * p;

K&R używa

char *p;

To zależy od Ciebie, chyba że przestrzegasz standardu kodowania - w takim przypadku powinieneś postępować zgodnie z tym, co robią wszyscy inni.

jnnnnn
źródło
4
Dowiedziałem się na własnej skórze, że char * x, y nie oznacza, że ​​y jest char *. Teraz widzę, dlaczego K&R podąża za tym stylem.
Rahul Kadukar
czym jest K&R i dlaczego ma znaczenie, jakiego używa pojedyncze źródło kodu? Używam char* p;. to kwestia stylu, a nie konwencji czy zasad. dla mnie bardziej sensowne jest to, że p jest typem char*, więc oczywiście * powinno być z typem.
FalcoGer
@FalcoGer Dodałem link do K&R. Nie ma znaczenia, czego używa pojedyncze źródło kodu. Twój zespół może się na Ciebie zdenerwować, jeśli nie będziesz postępować zgodnie z ich standardem, ponieważ zmuszasz ich do cięższej pracy, aby zrozumieć Twój kod. Obecnie mam nadzieję, że zespoły i clang-formattak korzystają .
jnnnnn
2

Wszystko to kwestia preferencji, osobiście w projektach widzę znak * Zwykle deklaruję wiele wskaźników w oddzielnych wierszach. Nie ma prawdziwego „właściwego” sposobu, aby to zrobić i wszystko sprowadza się do preferencji. Niektórzy twierdzą, że łatwiej jest przeczytać (a), podczas gdy inni twierdzą, że (b) łatwiej jest zadeklarować więcej zmiennych tego samego typu w tej samej linii.

Uważam, że (b) jest bardziej powszechne, aw niektórych przypadkach widziałem

char * a;

lub coś w tym stylu. Znowu preferencja. Użyję tego, z czym czujesz się komfortowo lub w jakimkolwiek projekcie, nad którym pracuję (chyba, że ​​napiszę to sam, w takim przypadku użyję (a))

Jesus Ramos
źródło