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?
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.
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.
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);
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.
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); }
No, miten siitä otetaan toinen sana O_o
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.
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);
Aihe on jo aika vanha, joten et voi enää vastata siihen.