Zmiana elementu w tablicy znaków

0

Witam.

Dlaczego jak robię :
char a[] = "eeeeddffeee";
a[3] = 'X';
to program działa poprawnie, a jak zrobię:
char* a = "eeeeddffeee";
a[3] = 'X';
to dostaje Segmentation fault (core dumped) ?

Myślałem że char a[] i char* a jest tym samym typem.

Kod kompiluje tak g++ -lstdc++ -std=c++17 -D_GLIBCXX_DEBUG -o example example.cpp

3
Chce_byc_programista napisał(a):

Myślałem że char a[] i char* a jest tym samym typem.

w drugim przypadku wskazujesz na niezmienny literał "eeeeddffeee"
jakby było

char a[] = "eeeeddffeee";
char* b=a;
b[3] = 'X';

to tak by przeszo

4

@Chce_byc_programista:

Dopowiem do @Miang

W pierwszym
"zarezerwuj mi tablicę na tyle, aby się zmieściła inicjacja" oraz "zainicjuj mi z pamięci tylko do odczytu" (przy czym zainicjowanie odbywa się zanim się zacznie wykonywać main())

W drugim
"użyj napisu z pamięci tylko do odczytu"
Ścisła deklaracja na ten przypadek to by była

const char* a = "eeeeddffeee";

Różnią się zużyciem pamięci, na współczesnym kompie nie ma to żadnego znaczenia, ale na jakimś chudopachołku ? Albo mikrokontrolerze?
W pierwszym N+1 pamięci RAM oraz N+1 pamięci ROM (umownie, co by to znaczyło *)

W drugim wskażnik, np 4 bajty (albo 8 lub 2) i N+1 w pamięci ROM.

*) Ten "ROM" to na pecetowskich jest część pliku EXE, która zawiera stałe załadowana jako chroniony segment do RAM, ale na mikrokontrolerach to prawdziwy ROM / flash / co tam mają (opowieść ma więcej komplikacji, na popularnych AVR które sa silnikiem najbardziej popularnych Arduino, jest jeszcze bardziej skomplikowane, ale nie o tym wątek)
Zwykle na takich maluchach z pamięcią RAM jest bardzo cienko (256bajtów - 1-2-4 kB), z ROM nieco lepiej (najmniej 2-4kB, do 32kB), ale tam siedzi też kod programu.

Miang napisał(a):

jakby było

char a[] = "eeeeddffeee";
char* b=a;
b[3] = 'X';

to tak by przeszo

Przeszło lub nie. To że się da oszukać kompilatorowi rzutowanie const na zwykłe (a ono tam jest ukryte), to nie znaczy ze to 100% niezawodne. Chyba jest to listowane jako UB. Na uK by było kiszka

2

Myślałem że char a[] i char* a jest tym samym typem.

To są różne typy, tyle, że w C tablice degradują (decay) do wskaźników jak tylko jest to potrzebne.
To jest jeden z tych odziedziczonych feature'ów C, które powodują więcej zamieszania niż to potrzebne.

Inny problem to jeszcze fakt że ten zapis jest zaproszeniem do błędów:

char* a = "eeeeddffeee";

https://godbolt.org/z/Eos8WYzbb

Jak widać clang i gcc mają na to warning (msvc ignoruje problem):

error: ISO C++ forbids converting a string constant to 'char*' [-Werror=write-strings]

To powoduje, że a wskazuje na stały napis (literał). IMO powinno zgłąszać błąd, o brakującym const.

W wersji:

char a[] = "eeeeddffeee"

tworzona jest tablica, do której jest skopiowany stały literał, więc wykonując a[3]='x'; nie modyfikuje się literału, ale tablicę zawierającą kopię literału.

0

Wielkie dzięki za pomoc. Już rozumiem dlaczego Rust jest tak popularny :-)

2
MarekR22 napisał(a):

Jak widać clang i gcc mają na to warning (msvc ignoruje problem):

MSVC przestaje ignorować problem jak mu się zapoda /Zc:strictStrings, albo /permissive- (które robi więcej).

1 użytkowników online, w tym zalogowanych: 0, gości: 1