Limbaje de programare: Laborator 7

Tablouri. Șiruri de caractere

Exerciții pregătitoare

În curs sunt date exemple cu traversarea unui tablou pentru a da valori elementelor, și pentru a prelucra iterativ elementele fără a calcula un rezultat (tipărire).

Un tipar des folosit e traversarea unui tablou calculând un rezultat din toate elementele, de exemplu suma:

double sumtab(double a[], unsigned len)
{
  double sum = 0;
  for (unsigned i = 0; i < len; ++i)
    sum += a[i];
  return sum;
}
Atenție: trebuie inițializată variabila care acumulează rezultatul (sum), altfel pornește de la o valoare necunoscută. Compilarea cu gcc și opțiunile -O -Wall (optimizare și avertismente) va genera un mesaj dacă uităm inițializarea.

Un alt tipar este căutarea în tablou după un element care îndeplinește o condiție:

int findneg(int a[], unsigned len)
{
  for (unsigned i = 0; i < len; ++i)
    if (a[i] < 0) return i;
  return -1;
}
Funcția dată returnează primul indice din tablou la care apare un element negativ, sau -1 dacă nu se găsește un astfel de element. Tabloul nu e parcurs complet, ci doar până e îndeplinită condiția. Ciclul se termină cu instrucțiunea break;

Un alt tipar este cel de filtrare sau prelucrare selectivă doar a elementelor care satisfac o condiție. Următorul exemplu copiazădintr-un tablou în altul doar anumite elemente (cele negative).

#include <stdio.h>

unsigned selectodd(int src[], int dest[], unsigned len)
{
  unsigned si, di;
  for (si = di = 0; si < len; ++si)
    if (src[si] % 2) dest[di++] = src[si];
  return di;
}

#define LEN 10

int main(void)
{
  int a[LEN] = {1, 4, 5, 6, -5, 7, 10, 9, 9, -5}, b[LEN];
  unsigned lenb = selectodd(a, b, LEN);	// returneaza nr. elem. copiate
  for (unsigned i = 0; i < lenb; ++i)
    printf("%d ", b[i]);
  return 0;
}
Ciclul din funcția scrisă actualizează la fiecare iterație indicele din tabloul sursă; indicele destinație se incrementează doar când se găsește un element care trebuie copiat (în acest caz, impar). Post-incrementarea di++ asigură că elementul e copiat la vechea valoare a indicelui (pornind de la 0), incrementarea având loc ulterior. Pentru a ști câte elemente au fost copiate în destinație, funcția returnează această valoare. În programul principal, tablourile sunt declarate cu aceeași dimensiune, ceea ce ne asigură că în destinație e loc. În alte cazuri ciclul care completează tabloul destinație trebuie să aibe dimensiunea acestuia ca limită (vezi exemplul cu numere prime de la curs).

Pentru funcțiile care lucrează cu șiruri de caractere nu trebuie transmisă și dimensiunea lor, dacă se respectă convenția că un șir se termină cu caracterul '\0'.

#include <ctype.h>
#include <stdio.h>
void dotCaps(char s[])
{
  for (unsigned i = 0; s[i]; ++i)
    if (s[i] == '.') s[i+1] = toupper(s[i+1]);
}
int main(void)
{
  char sir[] = "citius.altius...fortius.";
  dotCaps(sir);
  printf("%s\n", sir);
}
Funcția scrisă parcurge scrisul până la sfârșit (s[i] nenul în testul din for) și transformă în literă mare orice caracter de după un punct. Cum toupper returnează caracterul nemodificat dacă nu e literă mică, codul funcționează corect și dacă după punct urmează punct sau sfârșitul șirului.

Probleme propuse

  1. Implementați câteva funcții simple pentru lucru cu șiruri de caractere:
  2. Scrieți o funcție care ia ca parametru un șir și returnează numărul de cuvinte din șir (cuvintele sunt șiruri care nu conțin spații albe).
  3. Scrieți o funcție care ia ca parametru un șir și returnează șirul modificat astfel încât fiecare cuvânt începe cu literă mică, în afară de primul cuvânt și următorul cuvăt care începe după un punct care nu e în interiorul unui cuvânt.
    Variantă: ca mai sus, dar toate celelalte cuvinte sunt scrise integral cu litere mici, în afară de cele care erau formate doar din majuscule.
  4. Scrieți o funcție care ia ca parametru un șir de caractere și îl modifică înlocuind orice spații albe consecutive cu un singur spațiu.
  5. Scrieți o funcție care ia ca parametru un șir de caractere și returnează valoarea numărului aflat în porțiunea inițială a șirului.
    Funcția acceptă ca șirul să conțină un număr arbitrar de spații albe inițiale, opțional semnul (+ sau -), și apoi cifre în baza 10. Conversia se oprește la întâlnirea primului caracter necorespunzător. Dacă până în acel punct nu s-a întâlnit un număr valid, funcția returnează zero.
    Observație: O astfel de funcție standard există: int atoi(const char *s) și e declarată în stdlib.h.
    Funcția va construi numărul similar cu cele de citire de numere întregi (readnat, readint) scrise anterior, cu deosebirea că numărul e conținut în șir. Funcția nu va citi pe rând caractere de la intrare, ci va avansa cu indicele în șir.
    Variantă: scrieți o funcție care se comportă similar, dar acceptă un șir reprezentând un număr într-o bază arbitrară (între 2 și 36), dată ca al doilea parametru. Cifrele cu valori începând de la 10 sunt reprezentate prin litere mari sau mici.
  6. Scrieți o funcție care ia ca parametri un tablou cu coeficienții (reali) ai unui polinom, gradul lui, și o valoare x și returnează valoarea în punctul x a polinomului.
  7. Scrieți o funcție simplă de sortare a unui tablou (de întregi sau reali).
    Scrieți întâi o funcție care returnează indicele elementului maxim din tablou. Interschimbați maximul cu ultimul element, a[len-1] (dacă maximul nu e deja chiar pe această poziție). Acum ultimul element e cel bun în ordinea de sortare, și repetați sortarea pentru tabloul de la a[0] la a[len-2].
  8. Fiind dat un număr prim p și un număr 1 < a < p afișați toate numerele din intervalul (1, p) care nu pot fi scrise sub forma ak(mod p).
    Indicație: calculați valorile ak(mod p), k ≥ 1 până cănd apare valoarea 1 (șirul e periodic). Folosiți un tablou cu indici resturile modulo p (0 până la p-1), inițializat cu 0, în care treceți 1 când întâlniți restul respectiv.
  9. Scrieți o funcție care afișează rezultatul împărțirii a două numere naturale m/n, incluzând perioada (dacă există) între paranteze. Exemplu: 5/28 = 0.17(857142)
    Indicație: perioada începe când la împărțirea lui m cu n apare un rest care a mai fost întâlnit. Procedați ca la problema anterioară.
  10. Scrieți o funcție care realizează adunarea/înmulțirea/împărțirea a două polinoame, date prin tabloul cu coeficienți și gradul lor.

Marius Minea
Last modified: Mon Oct 31 21:00:00 EET 2011