Jestem trochę zdezorientowany. Miałem wrażenie, że poprawny sposób odczytu napisu C scanf()
przebiega zgodnie z liniami
(nieważne możliwe przepełnienie bufora, to tylko prosty przykład)
char string[256];
scanf( "%s" , string );
Jednak wydaje się, że działa też:
scanf( "%s" , &string );
Czy to tylko mój kompilator (gcc), szczęście czy coś innego?
scanf
, a zarówno pytanie, jak i zaakceptowana odpowiedź skupiają się na to i pomiń krytycznie ważne ograniczenia dotyczące maksymalnej długości danych wejściowych, które powinny być używane w rzeczywistym kodzie (ale poza tym, o co chodzi w tym pytaniu).Odpowiedzi:
Tablica „rozpada się” na wskaźnik do swojego pierwszego elementu, więc
scanf("%s", string)
jest równoważnascanf("%s", &string[0])
. Z drugiej stronyscanf("%s", &string)
przekazuje wskaźnik-do-char[256]
, ale wskazuje to samo miejsce.Następnie
scanf
, podczas przetwarzania końca listy argumentów, spróbuje wyciągnąć plikchar *
. To jest właściwa rzecz, kiedy zdałeśstring
lub&string[0]
, ale kiedy zdałeś&string
, jesteś zależny od czegoś, czego standard językowy nie gwarantuje, a mianowicie, że wskaźniki&string
i&string[0]
- wskazują na obiekty różnych typów i rozmiarów, które rozpocząć w tym samym miejscu - są reprezentowane w ten sam sposób.Nie wierzę, że kiedykolwiek spotkałem system, w którym to nie działa, aw praktyce prawdopodobnie jesteś bezpieczny. Niemniej jednak jest to błąd i może zawieść na niektórych platformach. (Hipotetyczny przykład: implementacja "debugowania", która zawiera informacje o typie przy każdym wskaźniku. Myślę, że implementacja C w Symbolics "Lisp Machines" zrobiła coś takiego.)
źródło
&string
tym samym działaniemstring
(zamiast powodować przypadkowe uszkodzenie pamięci, jak twierdzą inne odpowiedzi):printf("%x\n%x\n", string, &string);
string
jest wskaźnikiem i&string
jest adresem tego wskaźnika, więc te dwa elementy NIE są zamienne. Jak wyjaśnia Gareth, nawet w przypadku zaniku tablicystring
i&string
technicznie nie są tego samego typu (nawet jeśli zdarza się, że są wymienne dla większości architektur), a gcc wyświetli ostrzeżenie dla drugiego przykładu, jeśli włączysz-Wall
.Myślę, że to poniżej jest dokładne i może pomóc. Jeśli znajdziesz jakieś błędy, możesz je poprawić. Jestem nowy w C.
w tym znak zerowy zakończenia
'\0'
&str
,&str[0]
astr
wszystkie trzy reprezentują to samo miejsce w pamięci, które jest adresem pierwszego elementu tablicystr
char * strPtr = & str [0]; // deklaracja i inicjalizacja
alternatywnie możesz podzielić to na dwie części:
strPtr
jest wskaźnikiem dochar
strPtr
punkty w szykustr
strPtr
jest zmienną z własnym adresem w pamięcistrPtr
to zmienna przechowująca wartość adresu&str[0]
strPtr
własny adres w pamięci różni się od adresu pamięci, który przechowuje (adres tablicy w pamięci, czyli & str [0])&strPtr
reprezentuje adres samego strPtrMyślę, że możesz zadeklarować wskaźnik do wskaźnika jako:
deklaruje i inicjalizuje z adresem wskaźnika strPtr
Alternatywnie możesz podzielić na dwie części:
*vPtr
wskazuje na wskaźnik strPtr*vPtr
jest zmienną z własnym adresem w pamięci*vPtr
to zmienna przechowująca wartość adresu & strPtrstr++
,str
adres to aconst
, ale możesz to zrobićstrPtr++
źródło