Alla oleva on mahdollista:
char *a[]={"ab","cd"}; a[0] = "lo";
eli muuttaa koko stringi. Voiko joku kertoa miksi alla oleva ei ole mahdollista:
char *a[]={"ab","cd"}; *a[0] = 'p';
Miksi ei päästä muuttamaan yksittäistä charria? Vaikka jos laitan printf("%c",*a[0]); niin tulokseksi tulee "a".
Mikäli olen ymmärtänyt asiat oikein, luot tuossa taulukon taulukoita, siis muuttujan tietotyyppiä char**
. Tällöin jos haluat osoittaa tiettyyn merkkiin, täytyy käyttää merkintää *a[0][0]
. Printf-esimerkissäsi tulostetaan vain stringin ensimmäinen merkki, koska käsket tulostaa char
in mutta annat parametriksi osoittimen char
iin.
En ole itsekkään oikein sinut näiden C-merkkijonojen kanssa. Jos käytät C++:aa, käytä standardikirjaston string-luokkaa. Saat siitä C-merkkijonopointterin ulos metodilla c_str().
Koodisi on lähtökohtaisesti väärin: "ab" ei ole tyyypiltään muuttuva char* vaan vakio const char*.
gcc -Wwrite-strings kirjoitti:
tmp.c:3:2: warning: initialization discards ‘const’ qualifier from pointer target type
Ohjelma, joka yrittää muuttaa vakiota, voi kaatua; ainakin Linuxissa jälkimmäinen koodisi kaatuu muutosvaiheessa viestiin Segmentation fault. Ilmeisesti sinulla muutos ei kaada ohjelmaa. Voi olla, että kääntäjä tuottaa tulostettavaksi a-kirjaimen sillä perusteella, että sääntöjen mukaan teksti "ab" on vakio eikä siis ole voinut muuttua.
Muutettava teksti täytyy määritellä taulukkona eikä osoittimena, jolloin "ab":n sisältö kopioidaan taulukkoon eikä se jää virheelliseksi vakio-osoittimeksi.
char a[2][3] = {"ab", "cd"}; // [3], koska "ab" sisältää merkit 'a', 'b', '\0' a[0][0] = 'p'; // selvempi kuin *a[0] puts(a[0]);
Eki++ taas on väärässä sekä taulukon käytön suhteen että sen suhteen, mitä tapahtuu, jos %c-printtaukseen antaa osoittimen.
Miksi tuo ensimmäinen koodi on sallittu? tai ainakin minulla se muuttaa stringin ab -> lo, jos nuo tulkitaan const char*.
Ensimmäisessä koodissa vaihdat koko osoitinta. Siis muistissa oleva teksti "ab" ei muutu miksikään, sitä ei vain enää käytetä. Osoittimen voi ottaa talteen, jolloin näkyy, että "ab" pysyy samana:
const char* a[1] = {"ab"}; const char* tmp = a[0]; printf("%s @ %p, %s @ %p\n", a[0], a[0], tmp, tmp); a[0] = "lo"; printf("%s @ %p, %s @ %p\n", a[0], a[0], tmp, tmp);
ab @ 0x10648, ab @ 0x10648 lo @ 0x10660, ab @ 0x10648
Sen sijaan merkin vaihtaminen ei muuta osoitinta vaan sisältöä. Jos siis tässä osoittimen ottaa talteen, näkyy, että teksti todella vaihtuu:
char a[1][3] = {"ab"}; const char* tmp = a[0]; printf("%s @ %p, %s @ %p\n", a[0], a[0], tmp, tmp); a[0][0] = 'p'; printf("%s @ %p, %s @ %p\n", a[0], a[0], tmp, tmp);
ab @ 0xbeef7b78, ab @ 0xbeef7b78 pb @ 0xbeef7b78, pb @ 0xbeef7b78
Osoitteista myös kivasti nähdään, että ensimmäisessä versiossa data sijaitsee ihan erilaisella muistialueella kuin toisessa. Tämä on vakioille tyypillistä.
Kiitos vastauksista!
Aihe on jo aika vanha, joten et voi enää vastata siihen.