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.


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.


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”.


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.

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.


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))

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.