Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Arrayn char:n muuttaminen

Markulasot [31.01.2015 09:03:02]

#

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".

Eki++ [31.01.2015 09:38:10]

#

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 charin mutta annat parametriksi osoittimen chariin.

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().

Metabolix [31.01.2015 09:39:21]

#

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.

Markulasot [31.01.2015 11:58:17]

#

Miksi tuo ensimmäinen koodi on sallittu? tai ainakin minulla se muuttaa stringin ab -> lo, jos nuo tulkitaan const char*.

Metabolix [31.01.2015 12:14:55]

#

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ä.

Markulasot [31.01.2015 17:03:31]

#

Kiitos vastauksista!

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta