Scrieți un program care citește cuvinte, presupuse de cel mult 50 de caractere, până la sfârșitul intrării, și le afișează, fiecare pe câte un rând.
while (apel citire cu rezultat corect) prelucreazăExemple (fragmente de cod, se folosesc în funcția care face prelucrarea)
#define LEN 128 char line[LEN]; while (fgets(line, LEN, stdin)) { // prelucrează linia }Prelucrarea unui șir de cuvinte (de dimensiune limitată), separate prin spații
char cuv[64]; while (scanf("%63s", cuv) == 1) { // prelucreaza cuvântul }Prelucrarea unui șir de numere, separate prin spații:
int n; while (scanf("%d", &n) == 1) { // prelucrează numărul n }Exercițiul 1 Citiți într-un tablou de caractere două cuvinte de maxim 20 caractere (separate prin spații albe în intrare), și plasați-le în tablou unite printr-o liniuță. Exemplu: din Ana Maria în intrare construim șirul Ana-Maria în tablou.
Tabloul trebuie declarat de minim 20 + 1 (liniuța) + 20 + 1 (pentru \0) caractere. Cuvintele nu trebuie citite în tablouri separate, ci direct acolo unde trebuie plasate: după citirea primului cuvânt calculăm lungimea lui, și plasăm o liniuță la sfârșit. Apoi, citim al doilea cuvânt la adresa caracterului următor în tablou. Pentru a citi un cuvânt trebuie să dăm funcției scanf adresa la care se va citi cuvăntul. Nu trebuie ca această adresă să fie neapărat începutul unui tablou (parametrii în C se transmit prin valoare, deci o funcție nu are cum "să-și dea seama" că adresa e început de tablou sau nu), ci trebuie doar ca de la acea adresă începând să rămână suficient de mult loc pentru a citi cuvântul.
#include <stdio.h> #include <string.h> int main(void) { char s[42]; printf("Introduceti doua cuvinte de max. 20 caractere: "); if (scanf("%20s", s) == 1) { unsigned len = strlen(s); // afla lungimea cuvantului citit s[len++] = '-'; // adauga liniuta, creste lungimea if (scanf("%20s", &s[len]) == 1) // citeste unde trebuie, pune si \0 printf("Cuvintele legate: %s\n", s); else printf("lipseste cuvantul 2\n"); } else printf("nu s-au introdus cuvinte\n"); return 0; }Este important să facem verificările la citire; altfel, dacă utilizatorul nu introduce cele solicitate, programul va afișa conținutul întâmplător al tabloului s (neinițializat!); sau programul poate fi abandonat forțat dacă apelul de tipărire sau de calcul al lungimii șirului nu întâlnește la timp caracterul nul și continuă accesul într-o zonă de memorie invalidă.
Exercițiul 2 Citiți o propoziție (șir de caractere care se termină cu '.') de maxim 80 de caractere (inclusiv punctul) și afișați în caz contrar un mesaj de eroare.
#include <stdio.h> #define LEN 80 int main(void) { char p[LEN+1]; for (int i = 0; i < LEN; ++i) { // citim direct in tablou int c = getchar(); if (c == EOF) { printf("propozitie neterminata, EOF\n"); return 1; } else if (c == '.') { p[i++] = c; p[i] = '\0'; // termină șirul printf("propozitia: %s\n", p); return 0; } else p[i] = c; } p[LEN] = '\0'; // termină șirul printf("propozitie prea lunga: %s", p); return 2; }Problema e simplă, dar trebuie tratate atent diversele situații în care se poate încheia citirea:
Întrucât șirul nu e citit cu funcții standard (fgets, scanf, etc.) trebuie să introducem terminatorul '\0' pentru a-l putea folosi ulterior (de exemplu în printf).
Problema se poate rezolva și altfel, citind max. 79 de caractere în afară de punct cu scanf(p, "%79[^.]"). Trebuie verificată citirea corectă, și dacă următorul caracter e punct, apare EOF, sau au fost citite 79 de caractere și apoi nu apare punctul (propoziție prea lungă).
Exercițiul 3. Căutarea de tipare în texte.
Scrieți un program care citește de la intrare un text și
tipărește acele fragmente aflate între
șirurile begin și end (nu neapărat de sine
stătătoare).
Problema seamănă cu cea rezolvată la curs, în care se tipărește orice text care nu e inclus între < și >, dar textul interesant nu mai e delimitat de o pereche de caractere, ci de șiruri (cuvinte).
Pentru început, trebuie să găsim în text șirul begin. Dacă s-ar fi căutat cuvinte de sine stătătoare, s-ar putea citi textul cuvânt cu cuvânt, și compara fiecare cuvânt cu cel căutat (tratând însă și cuvintele foarte lungi care s-ar putea să fie despărțite prin citirea pe lungime limitată).
În acest caz, putem căuta întâi primul caracter, și apoi verifica dacă urmează restul șirului. Putem citi până la b cu secvența (unde nu trebuie uitat testul de EOF):
int c; do c = getchar(); while (c != EOF && c != 'b)';
char incep[5] = ""; // initializat scanf("%4[^b]", incep); // max. 4 caractere fara 'b' if (strcmp(incep, "egin") == 0) // ... s-a potrivit ...Mai simplu, în formatul din scanf, caracterele obișnuite trebuie să se potrivească exact În intrare, și putem folosi formatul %n pentru a afla numărul caracterelor citite:
int matchbegin(void) { int nrc = 0; do { scanf("%*[^b]"); if (scanf("begin%n", &nrc) == EOF) return 0; } while (nrc == 0); return 1; }Primul apel, scanf("%*[^b]") citește fără a memora (modificatorul *) oricâte caractere din mulțimea (specificatorul [ ]) care NU include (descrierea începe cu ^) caracterul b, și se oprește fără să-l consume pe b.
Pentru copierea până la end procedăm similar: un ciclu de copiere caracter cu caracter pana la e, după care verificăm dacă apare nd, citind un șir de două caractere, dar fără să permitem e (o altă variantă ar fi scanf("%2[dn]", care permite doar caracterele d și n). Dacă șirul citit e chiar nd, am încheiat, altfel șirul (împreună cu 'e' inițial) e tipărit, și reluăm căutarea. Testul și ieșirea la EOF se face în ciclul care caută litera e, ciclul exterior poate fi reluat necondiționat: for (;;), sau while (1) .
void copyend(void) { for (;;) { int c; while ((c = getchar()) != 'e') if (c == EOF) return; else putchar(c); char w[3] = ""; scanf("%2[^e]", w); if (strcmp(w, "nd") == 0) return; else { putchar('e'); printf("%s", w); } } }Programul principal se scrie atunci foarte simplu:
int main(void) { while (matchbegin()) copyend(); }
Andrei Ionascovici,8, 7.5, 5 Vlad Prisacescu,5 ,,6.5Eventualele spații de ambele părți ale virgulelor nu contează.
<student> <prenume>Ion</prenume> <nume>Iovanescovici</nume> <nota>9</nota> <nota>8</nota> <nota>10</nota> </student>
\begin{center} \begin{verbatim} int main(void) { return 0; } \end{verbatim} Cel mai simplu program C \end{center}are o astfel de secțiune (verbatim) împreună cu alt text obșnuit (dedesubt), ambele făcând parte dintr-o altă secțiune (center).
Scrieți un program care citește de la intrare un text cu structura respectivă și afișează doar textul propriu-zis din secțiuni, semnalând dacă apar erori de formatare (etichete nepereche).
Soluția e recursivă, observând că textul are structura:
secțiune ::= eticheta-inceput repetiție de text obișnuit și secțiuni eticheta-sfarșit
La întâlnirea unei etichete de început, se apelează
funcția de prelucrare a unei secțiuni, cu parametru numele
etichetei. Funcția se încheie la întâlnirea etichetei de
sfârșit cu același nume; ea prelucrează (tipărește)
textul obișnuit, și la întâlnirea altei etichete de
început, se apelează recursiv.