Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: strcmp:stä huomattua

Sivun loppuun

Kray [24.11.2007 15:27:25]

#

Niin, grafiikoita kokeiltuani palasin alkulähteilleni ohjelmoinnissa, yksinkertaisiin tekstipohjaisiin ohjelmiin. Kun tuollaista omaan tarkoitukseeni tulevaa commandlineä koodailin, huomasin, että kun char -merkkijonoa vertailee strcmp:llä, se lopettaa väliin, ja kun vertaili seuraavassa kohdassa, se luki joka tapauksessa loppuosan siitä merkkijonosta. Sillä sain mukavasti otettua parametrit suoraan, ja toimii ihan hyvin. Nyt mietin, että miten se on toteutettu, muistin manipuloinnilla? Tai jos joku osaisi laittaa koodinpätkän, joka osaa jatkaa siitä strcmp:n kohdasta ja tulostaisi näytölle sen jatkon?

Antti Laaksonen [24.11.2007 17:36:44]

#

Voisitko vielä selventää viestiäsi esim. lyhyen koodin avulla?

Funktio strcmp toimii niin, että se vertailee kahden merkkijonon merkkejä ja palauttaa positiivisen tai negatiivisen luvun sen mukaan, kumpi merkkijono tulee ensin aakkosjärjestyksessä, tai nollan, jos merkkijonot ovat samat. En nyt ainakaan heti keksi, miten sillä funktiolla voisi poimia ohjelmalle annettuja komentoriviparametreja.

Kray [25.11.2007 12:58:02]

#

Niin, siis en tiedä toimintatapaa, mutta jotain tälläistä:

char komento[100];
char polku[100];

scanf("%s",&komento);
if(strcmp(komento,"avaatiedosto")==0){
scanf("%s",&polku);
//tässä avataan tiedosto polku:n osoitteesta
}

tuossa jos on kirjoittanut komentoon välin jälkeen tiedoston polun, se hyppää tuon toisen scanf:n yli ja avaa komennon välin jälkeisen osan avulla tiedoston.

Legu [25.11.2007 13:32:43]

#

No tuossa on nyt se virhe, että scanf:lle pitäisi antaa scanf("%s", komento); ilman tuota viittausta (&), koska tuo "komento" on jo osoitin. Nyt yrität lukea komentoa tuohon "komento"-osoittimen osoitteeseen, jolloin ohjelmasi yrittää kirjoittaa/lukea vähän mitä sattuu muistista, mikä saattaa kaataa ohjelman.

EDIT: No tuossa sillä nyt ei sinänsä ole väliä, mutta jos olisi vaikkapa tällainen tilanne:

char *komento = (char*)malloc(100);

scanf("%s", komento); //oikein, toimii
scanf("%s", &komento); //väärin, ohjelma kaatuu (segfault)

free(komento);

Antti Laaksonen [25.11.2007 13:54:35]

#

Määritys %s tulkitsee merkkijonon päättyvän välilyöntiin, joten jos kirjoittaa monta merkkijonoa, joiden välissä on välilyönti, määritys %s poimii niistä vain ensimmäisen. Muut merkkijonot jäävät kuitenkin muistiin, ja niitä yritetään sovittaa mahdollisiin seuraaviin scanf-lukuihin. Funktio strcmp ei liity tähän asiaan mitenkään, esim. seuraavassa koodissa esiintyy sama ilmiö.

char etunimi[30];
char sukunimi[30];
printf("Kirjoita etunimesi: ");
scanf("%s", etunimi);
printf("Kirjoita sukunimesi: ");
scanf("%s", sukunimi);
printf("\nNimesi on %s %s.\n", etunimi, sukunimi);

Nyt jos etunimeksi ilmoittaa saman tien koko nimen, käy näin:

Kirjoita etunimesi: Antti Laaksonen
Kirjoita sukunimesi:
Nimesi on Antti Laaksonen.

Metabolix [25.11.2007 15:33:34]

#

Jos haluat yhden sanan jälkeen tyhjentää puskurin rivin loppuun asti, se onnistuu scanf-formaatilla "%*[^\n]", joka siis lukee kaikkia muita merkkejä kuin \n eikä tallenna niitä minnekään. Formaattiin "%s" kannattaa lisätä tekstin maksimipituus, jottei mene puskurin yli. Seuraavassa esimerkissä tulostetaan käyttäjän antaman rivin ensimmäinen "sana", kuitenkin enintään 15 merkkiä.

char sana[15 + 1]; // Huomaa %15s myöhemmin.
while (1) {
  printf("Kirjoitapa rivi.\n");
  if (scanf("%15s%*[^\n]", sana) != 1) {
    break;
  }
  printf("Syöttämäsi tekstin ensimmäinen sana oli %s.\n", sana);
}

Kray [25.11.2007 16:17:58]

#

No, miten siitä otetaan toinen sana O_o

Legu [25.11.2007 16:36:02]

#

Edellisen esimerkin pohjalta näin:

char sana1[15 + 1], sana2[15 + 1]; // Huomaa %15s myöhemmin.
while (1) {
  printf("Kirjoitapa rivi.\n");
  if (scanf("%15s%15s%*[^\n]", sana1, sana2) != 2) {
    break;
  }
  printf("Syöttämäsi tekstin ensimmäinen sana oli %s ja toinen oli %s.\n", sana1, sana2);
}

Tuossa tosin voi nyt tehdä niin, että kirjoittaa "testataan<enter>tätä<enter>" "testataan tätä<enter>":n sijaan.

Antti Laaksonen [25.11.2007 16:48:59]

#

Ensimmäisen sanan voi myös heittää menemään, jotta se ei suotta täytä muistia:

char toinen[30];
printf("Kirjoita sanoja: ");
scanf("%*s %s", toinen);
printf("Toinen sana: %s", toinen);

Sivun alkuun

Vastaus

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

Tietoa sivustosta