2016-03-13 13 views
11

Rozumiem podstawy działania wskaźników, ale następujący przykład wprowadza mnie w błąd.Jaka jest różnica w wskaźnikach podczas definiowania char i int?

int *myNum = 10; // Produces an error 

char *myChar = "Something"; // Works fine 

Dlaczego przypisywanie funkcji char, ale liczba całkowita nie powoduje (może powodować, że znak char jest traktowany jako tablica)?

Co mi nie pasuje, gdy bezpośrednio przypisuję zmienną wskaźnika, czy automatycznie otrzymuje adres?

char *myChar = "Something"; 

i

char myChar = "Something"; 
char *charAddr = &myChar; 

Jaki byłby różnicy tutaj, lub równa?

+3

'char myChar =" Something ";' nie działa, ponieważ '" Something "' nie jest char. – immibis

+0

To, czego szukasz, to [Tablica do konwersji wskaźnika] (http://en.cppreference.com/w/c/language/conversion) – hgiesel

+0

@immibis ITYM '" Coś "' nie jest niejawnie przekształcalne w 'char' . 'char myChar = 5.5;' is legal –

Odpowiedz

19
"Something" 

jest w istocie skrót:

static const char some_hidden_array[] = {'S', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', '\0'}; 
some_hidden_array 

Oznacza to, że kiedy piszesz "Something" kompilator generuje tablicę za kulisy, i daje wskaźnik na początek tej tablicy. Ponieważ jest to już wskaźnik do znaku, nie będziesz miał problemu z przypisaniem go do zmiennej typu "wskaźnik do znaku" (zapisanej jako char*).

10 

jest nie krótki niczego podobnego. Jest to po prostu numer 10 - nie jest wskaźnikiem do tablicy zawierającej cyfrę 10 lub coś w tym stylu.

Uwaga że char jest pojedynczy znak, a nie ciąg, dlatego składnia ciąg jest niezwykłe w porównaniu do większości innych typów - ciąg jest kilka znaków, a nie tylko jeden.Jeśli spróbujesz użyć zwykły stary char, zobaczysz to samo:

char *myChar = 'a'; // error 

lub jakiegokolwiek innego typu:

float *myFloat = 42.1f; // error 

Innymi słowy, to nie dziwne, że 10 daje błąd - jeśli cokolwiek, to dziwne, że "Something"nie jest. (Przynajmniej jest to dziwne, dopóki nie wiesz, jak działają ciągi literałów)

10

To samo (nie ma żadnej magii z kompilatora). Domyślnie literały takie jak 10 są wartościami int, a nie int *.

Trzeba obsada:

int *myNum = (int*)10; // Need to cast 
char *myChar = "Something"; // No need to cast "..." is already a char* 

Zauważ, że to niebezpieczne, aby odwoływać się wskaźnik do wartości bezwzględnej jak ten, bo skończy się z adresem 10 w pamięci procesora.

Jeśli chodzi o drugie pytanie, "..." jest traktowane jako ciągła sekwencja znaków w pamięci podobna do tablicy i równoważna znakowi *.

Aby uzyskać przemyślane zrozumienie C, wskazówki i różnice między tablicami a wskaźnikami, należy przeczytać: Programowanie C Expert: Sekretne C z głębokim C przez Petera van der Lindena.

+0

Dziękujemy! Co do drugiego pytania, miałem na myśli bardziej, jeśli te 2 są równe? Czy pierwszym przykładem jest krótszy sposób uzyskania adresu? Dzięki! –

+1

Pamiętaj, aby wybrać tę odpowiedź jako zaakceptowaną, jeśli odpowiedziała na Twoje pytanie. –

+1

Zrobione, dziękuję :) –

2

Po utworzeniu char *myChar = "Something";, tworzysz literał ciągu tylko do odczytu gdzieś w pamięci, który kończy się znakiem pustym. Teraz jest to coś specjalnego dla kompilatora, który interpretuje fragment zmiennych "char" przechowywanych w sposób ciągły i kończących się znakiem null jako ciągiem znaków. Zasadniczo stworzyłeś tablicę znaków, a kiedy wykonasz *myChar*, zwraca ciąg znaków.

W przypadku liczb całkowitych lub dowolnych innych typów danych, rozróżnia się między int *ptr jako wskaźnikiem na liczbę całkowitą, a int ptr jako liczbą całkowitą. Otrzymujesz błąd prawdopodobnie dlatego, że podany adres może nie być prawidłowy/dostępny dla ciebie.

Również robi

char myChar = "Something"; //this is an error, since char can hold one character 
char *charAddr = &myChar; 

Zauważ, że myChar i &myChar są takie same, ponieważ myChar jest wskaźnik!

Edit: sprawdź tutaj o napisowych: Is it possible to modify a string of char in C?

+0

Dziękuję za wyjaśnienia, więc wpisujemy * var = something, zawsze tworzymy zmienną tylko do odczytu w pamięci? I jak na pytanie drugie, bardziej mi chodziło, jakby te 2 były równe (krótsza droga) :) Dzięki! –

+0

@ J.Doe Tak. Spójrz na to: http://stackoverflow.com/questions/1011455/is-it-possible-to-modify-a-string-of-char-in-c –

+0

Dziękuję, to bardzo pomaga. –

1

Choć teoretycznie pierwsza int *myNum = 10 sens — zwłaszcza jeśli wiedzą, że jest użytecznym int na adres dziesięciu — w ogóle rzadko jest użyteczne i potencjalnie bardzo niebezpieczne.

Jednak istnieją pewne zadania wskaźnik które są powszechnie stosowane i bardzo bezpieczny:

int *myNum = 0; 

Na 99,9% + nowoczesnych architekturach procesora, to jest taki sam jak

int *myNum = NULL; 

Zobacz definicję wartości NULL w <stddef.h>here.

Zasadniczo przypisanie zmiennych wskaźnikowych najlepiej wykonać, ustawiając na adres czegoś innego.

int k, *p = &k; 
+1

Dzięki! Hmm, więc zasadniczo, int * myNum = 10 // Wskaźnik do adresu "10", a nie adres, który zawiera zmienną int o wartości 10? –

+1

'int * myNum = 0;' jest takie samo jak 'int * myNum = NULL;' na wszystkich systemach. Tworzy zerowy wskaźnik. Zaczynasz mieszać się z tym, że zerowy wskaźnik może nie być reprezentowany przez wszystkie bity-zero (co nie ma znaczenia dla tego kodu) –

+0

@ J.Doe Tak, a twoje zamieszanie jest dokładnie tym, dlaczego musisz dodać wyraźna obsada, aby ta kompilacja - prawie zawsze jest * błędem *, a nie zamierzonym zachowaniem. W nowoczesnym systemie desktop/serwer naprawdę nie chcesz używać wskaźników do ręcznie wybranych adresów. Było to jednak przydatne w przeszłości - na przykład dla bezpośredniego dostępu do pamięci graficznej (lub innego urządzenia). Z abstrakcją sprzętu jest bardzo mało legalnych zastosowań (poza dość oczywistym przypadkiem '0' /' NULL', który na C standard * zawsze * działa :)). – Luaan

2

Dlaczego przypisywanie char pracę, ale nie całkowitą (Może powodować char jest traktowany jako tablica)?

Masz rację, "Something" jest literałem ciągowym i może być traktowany jako tablica znaków. Po char *myChar = "Something"; następuje następująca rzecz: przydzielana jest długość + 1 bajtów pamięci, gdzie "Something" zostanie zapisany, myChar zostanie wskazany na adres początkowy tej pamięci. Literały łańcuchowe są nieco wyjątkowe.

Oto ogólny sposób inicjowania tablicę z wartościami stałymi:

// valid initializations; 
char s2[] = { 'a', 'b', 'c' }; 
int a[] = { 1, 2, 3 }; 
char s1[] = "123"; 

Jak dobrze, co mnie dezorientuje gdy bezpośrednio przypisanie zmiennej wskaźnik, to automatycznie uzyskać adres?

Tak.

Spójrz na 8.5.2 Character arrays of c++ docs