Jaka jest różnica pomiędzy
char* name
co wskazuje na stały literał ciągu i
const char* name
Jaka jest różnica pomiędzy
char* name
co wskazuje na stały literał ciągu i
const char* name
Odpowiedzi:
char*
jest zmiennym wskaźnikiem do zmiennego znaku / łańcucha.
const char*
jest zmiennym wskaźnikiem do niezmiennego znaku / ciągu. Nie można zmienić zawartości lokalizacji (miejsc), na które wskazuje ten wskaźnik. Ponadto kompilatory są zobowiązane do przekazywania komunikatów o błędach, gdy próbujesz to zrobić. Z tego samego powodu konwersja z const char *
na char*
jest przestarzała.
char* const
jest niezmiennym wskaźnikiem (nie może wskazywać na żadną inną lokalizację), ale zawartość lokalizacji, na którą wskazuje, jest zmienna .
const char* const
jest niezmiennym wskaźnikiem do niezmiennego znaku / ciągu.
char const *
char *
błędu segmentacji podczas pracy?
const
jeśli chcę, aby kompilator dał błąd, jeśli zapomniałem i przez pomyłkę zmieniłem dane, prawda?
char *name
Możesz zmienić znak, na który name
wskazuje, a także znak, na który wskazuje.
const char* name
Możesz zmienić znak, na który name
wskazuje, ale nie możesz zmodyfikować znaku, na który wskazuje.
korekta: Możesz zmienić wskaźnik, ale nie znak, który name
wskazuje na ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , zobacz „Przykłady” ). W tym przypadku const
specyfikator dotyczy char
, a nie gwiazdki.
Zgodnie ze stroną MSDN i http://en.cppreference.com/w/cpp/language/declarations , const
przed *
jest częścią sekwencji specyfikatora deklaracji , podczas gdy const
po *
jest częścią deklaratora.
Po sekwencji specyfikatora deklaracji może następować wiele deklaratorów, dlatego const char * c1, c2
deklaruje się c1
jako const char *
i c2
as const char
.
EDYTOWAĆ:
Z komentarzy wynika, że twoje pytanie dotyczy różnicy między tymi dwiema deklaracjami, gdy wskaźnik wskazuje na literał ciągu.
W takim przypadku nie należy modyfikować znaku, do którego name
wskazuje, ponieważ może to spowodować niezdefiniowane zachowanie . Literały łańcuchowe mogą być alokowane w regionach pamięci tylko do odczytu (zdefiniowane w implementacji) i program użytkownika nie powinien w żaden sposób ich modyfikować. Każda taka próba skutkuje niezdefiniowanym zachowaniem.
Więc jedyną różnicą w tym przypadku (użycia z literałami łańcuchowymi) jest to, że druga deklaracja daje niewielką przewagę. Kompilatory zazwyczaj dają ostrzeżenie w przypadku próby zmodyfikowania literału ciągu w drugim przypadku.
#include <string.h>
int main()
{
char *str1 = "string Literal";
const char *str2 = "string Literal";
char source[] = "Sample string";
strcpy(str1,source); //No warning or error, just Undefined Behavior
strcpy(str2,source); //Compiler issues a warning
return 0;
}
Wynik:
cc1: ostrzeżenia traktowane jako błędy
prog.c: W funkcji „main”:
prog.c: 9: error: przekazanie argumentu 1 z „strcpy” usuwa kwalifikatory z typu docelowego wskaźnika
Zauważ, że kompilator ostrzega przed drugim przypadkiem, ale nie w pierwszym.
name
wskazują punkty w obu przypadkach, może to spowodować UB.
char mystring[101] = "My sample string";
const char * constcharp = mystring; // (1)
char const * charconstp = mystring; // (2) the same as (1)
char * const charpconst = mystring; // (3)
constcharp++; // ok
charconstp++; // ok
charpconst++; // compile error
constcharp[3] = '\0'; // compile error
charconstp[3] = '\0'; // compile error
charpconst[3] = '\0'; // ok
// String literals
char * lcharp = "My string literal";
const char * lconstcharp = "My string literal";
lcharp[0] = 'X'; // Segmentation fault (crash) during run-time
lconstcharp[0] = 'X'; // compile error
// *not* a string literal
const char astr[101] = "My mutable string";
astr[0] = 'X'; // compile error
((char*)astr)[0] = 'X'; // ok
char *
wartości powoduje błąd segmentacji, ponieważ próbujemy zmodyfikować literał ciągu (który jest obecny w pamięci tylko do odczytu)
W żadnym przypadku nie można modyfikować literału ciągu, niezależnie od tego, czy wskaźnik do tego literału ciągu jest zadeklarowany jako char *
czy const char *
.
Jednak różnica polega na tym, że jeśli wskaźnik jest, const char *
kompilator musi podać diagnostykę, jeśli spróbujesz zmodyfikować wskazywaną wartość, ale jeśli wskaźnik jest, char *
to nie.
extern ... name
i mieć *name = 'X';
. Na „odpowiednim systemie operacyjnym” może to się nie powieść, ale w systemach wbudowanych spodziewałbym się, że zrobi coś specyficznego dla platformy / kompilatora.
PRZYPADEK 1:
char *str = "Hello";
str[0] = 'M' //Warning may be issued by compiler, and will cause segmentation fault upon running the programme
Powyższe ustawia str tak, aby wskazywało na wartość literału „Hello”, która jest zakodowana na stałe w binarnym obrazie programu, która jest oznaczona jako tylko do odczytu w pamięci, co oznacza, że każda zmiana w tym literale String jest niedozwolona i powodowałaby błędy segmentacji.
PRZYPADEK 2:
const char *str = "Hello";
str[0] = 'M' //Compile time error
PRZYPADEK 3:
char str[] = "Hello";
str[0] = 'M'; // legal and change the str = "Mello".
Pierwszą możesz zmienić, jeśli chcesz, drugą nie możesz. Przeczytaj o const
poprawności (jest kilka fajnych poradników na temat różnicy). Jest też miejsce, w char const * name
którym nie możesz go zmienić.
Pytanie brzmi, jaka jest różnica między
char *name
co wskazuje na stały literał ciągu i
const char *cname
To znaczy dane
char *name = "foo";
i
const char *cname = "foo";
Nie ma dużej różnicy między 2 i oba można uznać za poprawne. Ze względu na długą tradycję kodu C, literały łańcuchowe mają typ char[]
, nie const char[]
, i istnieje wiele starszych kodów, które podobnie akceptują char *
zamiast const char *
, nawet jeśli nie modyfikują argumentów.
Zasadnicza różnica między 2 w ogólności polega na tym, że *cname
lub cname[n]
będzie oceniać do lwartości typu const char
, podczas gdy *name
lub name[n]
będzie oceniać do lwartości typu char
, które są modyfikowalnymi poziomami . Kompilator zgodny jest wymagany do wygenerowania komunikatu diagnostycznego, jeśli cel przypisania nie jest modyfikowalną lwartością ; nie musi generować żadnego ostrzeżenia o przypisaniu do lwartości typu char
:
name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostics message
W żadnym przypadku kompilator nie musi zatrzymywać kompilacji; wystarczy, że wygeneruje ostrzeżenie przed przydziałem cname[0]
. Wynikowy program nie jest poprawnym programem. Zachowanie konstrukcji jest nieokreślone . Może się zawiesić lub co gorsza, może się nie zawiesić i może zmienić literał ciągu w pamięci.
W rzeczywistości char* name
nie jest wskaźnikiem do stałej, ale wskaźnikiem do zmiennej. Możesz mówić o tym innym pytaniu.