10.3. Asignari de nume pentru tipuri de date (declaratii de tip)

2019/03/25 in Programare in C

Tipurile predefinite se identifica printr-un cuvant cheie. In cazul tipurilor utilizator in locul cuvantului cheie se utilizeaza constructia:

struct nume

unde nume este introdus printr-o declaratie de forma:

struct nume {
...
};

In limbajul C se poate atribui un nume unui tip, indiferent ca el este un tip predefinit sau unul utilizator.

In acest scop se utilizeaza o constructie de forma:

(1)

typedef tip nume_tip;

unde:

tip este fie un tip predefinit, fie un tip utilizator;
nume_tip este numele care se atribuie tipului definit de tip.

Dupa ce s-a atribuit un nume unui tip, numele respectiv poate fi utilizat pentru a declara date de acel tip, exact la fel cum se utilizeaza in declaratii cuvinte cheie ale tipurilor predefinite: int, char, float etc.

De obicei, numele atribuit unui tip se scrie cu litere mari. Constructia (1) de mai sus o vom considera ca fiind o declaratie prin care se atribuie un nume unui tip sau mai scurt declaratie de tip.

Exemple:

  1. Fie declaratia:

    typedef int INTREG;

    Dupa aceasta declaratie, cuvantul INTREG se poate utiliza pentru a defini date de tip int. Deci declaratia:

    INTREG x;

    este identica cu declaratia:

    int x;
  2. Fie declaratia:

    typedef float REAL;

    Datele:

    REAL a, b;

    sunt de tip float.

  3. typedef struct data_calendaristica {
      int zi;
      char luna[11];
      int an;
    } DC;
    

    Declaratia:

    DC data_nasterii, data_angajarii;

    este identica cu declaratia:

    struct data_calendaristica data_nasterii, data_angajarii;
  4. typedef struct {
      double real;
      double imag;
    } COMPLEX;
    

    In continuare se pot declara numere complexe prin declaratii de forma:

    COMPLEX z, tz[10];
  5. typedef struct {
      int x;
      int y;
    } PUNCT;
    PUNCT a, b;
    

    Variabilele a si b sunt structuri de tip PUNCT. Fiecare are o componenta x (abscisa) si y (ordonata).

  6. Un dreptunghi se poate defini prin doua varfuri diametral opuse ale sale. De obicei, se considera varful din coltul stanga sus si cel din dreapta jos.

    Definim tipul utilizator DREPTUNGHI:

    typedef struct {
      PUNCT stanga_sus;
      PUNCT dreapta_jos;
    } DREPTUNGHI;
    

    In continuare se pot defini date de tip DREPTUNGHI:

    DREPTUNGHI d, td[10];
  7. typedef int *PINT;

    PINT este numele atribuit pentru tipul pointer spre int.

    Declaratia:

    PINT p, t[100];

    este identica cu declaratia:

    int *p, *t[100];

    Constructia:

    tip (*p)(lista de tipuri);

    se poate folosi in antetul unei functii si cu ajutorul ei, parametrul p se declara ca fiind pointer spre o functie care returneaza o valoare de tipul tip, iar lista de tipuri defineste tipurile parametrilor functiei spre care pointeaza p. La tipul parametrului p de mai sus se poate atribui un nume printr-o constructie de forma:

    (2)

    typedef tip(*nume_tip)(lista tipurilor);

    Exemple:

    1. Fie functia de antet:

      void f(int(*p)(float, char, long, int))

      Declaratia:

      typedef int(*PF)(float, char, long, int);

      ne permite sa rescriem mai simplu antetul functiei f:

      void f(PF p)
    2. Folosind declaratia:

      typedef double(*PDF)(double);

      putem rescrie antetul functiei itrapez din exercitiul 8.25., in felul urmator:

      double itrapez(double a, double b, int n, PDF p)

Din cele de mai sus se observa ca declaratiile typedef ne permit adesea sa facem simplificari la scrierea antetelor si prototipurilor functiilor. Acestea devin substantiale mai ales atunci cand apar expresii complicate cu pointeri.

Sensul unei expresii cu pointeri se poate stabili daca se exprima prin cuvinte efectul fiecarui operator, tinand seama de regulile de prioritate si asociativitate.

Un exemplu de expresie complicata cu pointeri ar fi urmatoarea declaratie:

int *(*(*x)[6])();

Sensul lui x se determina astfel:

int * defineste un pointer spre int, deci:

a. (*(*x)[6])() este pointer spre int
b. (*(*x)[6]) este o functie si tinand seama de afirmatia de la pct. a., rezulta ca aceasta functie returneaza un pointer spre int
c. *(*x)[6] are acelasi sens cu cel de la pct. b.
d. (*x)[6] pointer spre constructia definita precedent, deci pointer spre o functie care returneaza un pointer spre int
e. (*x) tablou de 6 elemente, fiecare element este un pointer spre o functie care returneaza un pointer spre int
f. *x constructie identica cu cea de la pct. e.
g. x este pointer spre un tablou de 6 elemente, fiecare element fiind un pointer spre o functie care returneaza un pointer spre int

Un alt exemplu este declaratia:

char (*(*y())[])();

Aceasta declaratie se interpreteaza astfel:

a. (*(*y())[])() defineste o valoare de tip char
b. (*(*y())[]) este o functie si tinand seama se afirmatia de la pct. a., rezulta ca aceasta functie returneaza un pointer spre char
c. *(*y())[] este aceeasi constructie ca cea de la pct. b.
d. (*y())[] pointer spre o functie care returneaza o valoare de tip char
e. (*y()) este un tablou de pointeri spre functii care returneaza o valoare de tip char
f. *y() constructie identica cu cea de la pct. e.
g. y() este pointer spre un tablou de pointeri spre functii care returneaza o valoare de tip char
h. y este o functie care returneaza un pointer spre un tablou de pointeri spre functii care returneaza o valoare de tip char

Declaratiile de acest gen pot fi simplificate folosind declaratii de tip (intermediare).

Exercitii:

10.1. Sa se scrie o functie care calculeaza si returneaza modulul unui numar complex.

Daca z = x + iy, atunci modulul numarului complex este radacina patrata din x*x + y*y

double dmodul(COMPLEX *z)
{
  return sqrt(z -> x * z -> x + z -> y * z -> y);
}

10.2. Sa se scrie o functie care calculeaza si returneaza argumentul unui numar complex.

Daca z = x + iy, atunci arg z se calculeaza astfel:

  1. Daca x = y = 0, atunci arg z = 0.

  2. Daca y = 0 si x este diferit de zero, atunci:

    • daca x > 0, atunci arg z = 0;

    • altfel, arg z = pi = 3.14159265358979;

  3. Daca x = 0 si y este diferit de zero, atunci:

    • daca y > 0, atunci arg z = pi/2;

    • altfel, arg z = 3*pi/2;

  4. Daca x si y sunt diferiti de zero, atunci fie a = arctg(y/x).

    • daca x > 0 si y > 0, atunci arg z = a;

    • daca x > 0 si y < 0, atunci arg z = 2*pi + a;

    • daca x < 0 si y > 0, atunci arg z = pi + a;

    • daca x < 0 si y < 0, atunci arg z = pi + a.

    Se observa ca pentru x < 0 si y diferit de zero arg z = pi + a.

    Altfel, daca x > 0 si y < 0, atunci arg z = 2*pi + a.

double darg(COMPLEX *z)
{
  double a;

  if(z->x == 0 && z->y == 0)
    return 0.0;
  if(z->y == 0)
    if(z->x > 0)
      return 0.0;
  else
    return PI;
  if(z->x == 0)
    if(z->y > 0)
      return PI/2;
  else
    return (3*PI)/2;

  a = atan(z->y / z->x);
  if(z->x < 0)
    return a + PI;
  else
    if(z->y < 0)
      return 2*PI + a;

  return a;
}

10.3. Sa se scrie un program care citeste numere complexe si le afiseaza impreuna cu modulul si argumentul lor.

#include <stdio.h>
#include <math.h>

#define PI 3.14159265358979

typedef struct {
  double x;
  double y;
} COMPLEX;

#include "FUNCTIA113A.C"
#include "FUNCTIA113B.C"

main()
{
  COMPLEX complex;

  while(scanf("%lf %lf", &complex.x, &complex.y) == 2) {
    printf("a + bi = %g + i*(%g)\n", complex.x, complex.y);
    printf("modul = %g\targ = %g\n", dmodul(&complex), darg(&complex));
  }
}

10.4. Sa se scrie o functie care afiseaza un caracter intr-un punct de coordonate date.

Ecranul, in mod text, poate fi gestionat folosind functii care au prototipul in fisierul conio.h. Astfel, pentru a pozitiona cursorul in punctul de coordonate (x,y), se va apela functia gotoxy. Prototipul acestei functii este:

void gotoxy(int x, int y);

Pentru a afisa, incepand cu punctul pozitionat cu ajutorul functiei gotoxy, se pot folosi diferite functii, ca de exemplu putch sau cprintf in locul functiei printf. Functia cprintf are aceeasi parametri ca si functia printf. Prototipul ei se afla in fisierul conio.h spre deosebire de al functiei printf care se afla in stdio.h.

O diferenta a functiei cprintf fata de functia printf consta in aceea ca '\n' se interpreteaza diferit. Astfel, apelul:

cprintf("\n");

trece cursorul pe randul urmator lasandu-l in aceeasi coloana. De aceea, apelul:

printf("\n");

se echivaleaza cu apelul:

cprintf("\n\r");

daca cursorul nu este pe ultimul rand (25).

Functia cprintf nu realizeaza defilarea ecranului si de aceea, caracterul '\n' se neglijeaza daca cursorul se afla pe ultimul rand.

void afiscar(PUNCT *p, char c)
{
  gotoxy(p->x, p->y);
  putch(c);
}

10.5. Sa se scrie o functie care verifica daca un punct are coordonatele in limitele ecranului (25 de linii a 80 de coloane).

Functia returneaza valoarea 1 daca punctul se afla in limitele ecranului si 0 in caz contrar.

void limecr(PUNCT *p)
{
  if(p->x <= 0 || p->x >= 80);
    return 0;
  if(p->y <= 0 || p->x >= 25);
    return 0;
  return 1;
}

10.6. Sa se scrie o functie care traseaza un segment de dreapta orizontal afisand repetat un acelasi caracater dat.

Se presupune ca limitele segmentului se afla pe ecran.

void segoriz(PUNCT *a, PUNCT *b, char c)
/* - traseaza un segment de dreapta orizontal prin afisarea repetata a caracterului c; */
/* - se presupune ca punctul a precede pe b si ca a->y = b->y. */
{
int i;
PUNCT crt;

  crt.y = a->y;
  for(i = a->x; i <= b->x; i++) {
    crt.x = i;
    afiscar(&crt, c);
  }
}

10.7. Sa se scrie o functie care traseaza un segment de dreapta vertical afisand repetat un acelasi caracater dat.

Se presupune ca limitele segmentului se afla pe ecran.

void segvert(PUNCT *a, PUNCT *b, char c)
/* - traseaza un segment de dreapta vertical prin afisarea repetata a caracterului c; */
/* - se presupune ca punctul a este deasupra punctului b si ca a->x = b->x. */
{
int i;
PUNCT crt;

  crt.x = a->x;
  for(i = a->y; i <= b->y; i++) {
    crt.y = i;
    afiscar(&crt, c);
  }
}

10.8. Sa se scrie o functie care traseaza un segment de dreapta oblic de 45 de grade sexagesimale afisand repetat un acelasi caracater dat.

Se presupune ca limitele segmentului se afla pe ecran.

void segoblic(PUNCT *a, PUNCT *b, char c)
/* - traseaza un segment de dreapta oblic de panta 45 grade sexagesimale 
prin afisarea repetata a caracterului c; */
/* - se presupune ca punctele a si b permit trasarea unui astfel de segment 
de dreapta si ca ele au coordonate ce apartin ecranului. */
{
  int i, j, k, l;
  int pasi, pask;

  i = a->x;
  j = b->x;
  k = a->y;
  l = b->y;
  if(i < j) /* a in stanga lui b */
    pasi = 1;
  else /* a in dreapta lui b */
    pasi = -1;
  if(k < l) /* a deasupra lui b */
    pask = 1;
  else /* b deasupra lui a */
    pask = -1;
	
  /* trasarea segmentului */
  for( ; (j-i)*pasi >= 0; i += pasi, k += pask) {
    gotoxy(i, k);
    putch(c);
  }
}

Observatie: Segmentul se traseaza de la punctul a spre punctul b. De exemplu, daca punctul a este deasupra lui b (pask = 1) si in dreapta lui b (pasi = -1), atunci se observa ca i descreste pana cand i < j. In acest moment produsul (j-i)*pasi < 0 si deci ciclul for se termina.

De fiecare data cand i s-a micsorat cu o unitate, k a crescut cu o unitate. De aceea, pozitia caracterului curent fata de cel precedent se afla in coloana din stanga si cu o linie mai jos.

Punctele a si b trebuie sa satisfaca relatia:

(j-i)*pasi = (l-k)*pask

si de aceea, cand i = j, vom avea si k = l, adica se ajunge in punctul b.

10.9. Sa se scrie un program care traseaza un dreptunghi.

Laturile orizontale se traseaza folosin carcaterul minus (-), iar cele verticale folosind caracterul bara vericala (|).

// Functioneaza doar cu compilatorul Turbo C
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

typedef struct {
int x;
int y;
} PUNCT;

#include "FUNCTIA114A.C" /* afiscar */
#include "FUNCTIA114C.C" /* segoriz */ 
#include "FUNCTIA114D.C" /* segvert */
#include "FUNCTIA094B.C" /* pcit_int */
#include "FUNCTIA094C.C" /* pcit_int_lim */

main()
{
  PUNCT v1, v2, v;
  char er[] = "S-a tastat EOF\n";
  
  /* citeste coordonatele celor doua colturi ale dreptunghiului */
  /* coltul stanga sus */
  if(pcit_int_lim("x stanga sus: ", 1, 79, &v1.x) == 0) {
    printf(er);
    exit(1);
  }
  if(pcit_int_lim("y stanga sus: ", 1, 24, &v1.y) == 0) {
    printf(er);
    exit(1);
  }
  /* coltul dreapta jos */
  if(pcit_int_lim("x dreapta jos: ", v1.x+1, 80, &v2.x) == 0) {
    printf(er);
    exit(1);
  }
  if(pcit_int_lim("y dreapta jos: ",  v1.y+1, 25, &v2.y) == 0) {
    printf(er);
    exit(1);
  }

  /* sterge ecranul */
  clrscr();

  /* trasarea laturilor dreptunghiului */
  /* laturile orizontale */
  /* latura de sus */
  v.x = v2.x;
  v.y = v1.y;
  segoriz(&v1, &v, '-');

  /* latura de jos */
  v.x = v1.x;
  v.y = v2.y;
  segoriz(&v, &v2, '-');

  /* laturile verticale */
  v1.y++;
  v2.y--;
  if(v1.y > v2.y)
    exit(0); /* nu sunt laturi verticale */

  /* latura din stanga */
  v.x = v1.x;
  v.y = v2.y;
  segvert(&v1, &v, '|');

  /* latura din dreapta */
  v.x = v2.x;
  v.y = v1.y;
  segvert(&v, &v2, '|');

  getch();
}

10.10. Sa se scrie un program care afiseaza figura de mai jos.


     *
    ***
   * * *
  *  *  *
 *   *   *
***********
**   *   **
* *  *  * *
*  * * *  *
*   ***   *
*    *    *
***********
*   ***   *
*  * * *  *
* *  *  * *
**   *   **
***********
 *   *   *
  *  *  *
   * * *	
    ***
     *

Aceasta figura se compune din segmente de dreapta orizontale, verticale si oblice cu panta de 45 de grade sexagesimale. De aceea, ea se poate afisa folosind functiile segoriz, segvert si segoblic.

Varful de sus are coordonatele A(40, 1). Segmentul vertical din stanga are extremitatile B(35, 6) si C(45, 16).

Varful de jos are coordonatele D(40, 21). Segmentul vertical din dreapta are extremitatile F(45, 6) si E(45, 16).

Segmentul orizontal de sus are extremitatile B si F, iar cel de jos extremitatile C si E.

Segmentul orizontal care este axa de simetrie a figurii are extremitatile G(35, 11) si H(45, 11).

In afara de aceste segmente, figura mai contine urmatoarele segmente oblice: AB, AF, BE, FC, CD si ED.

// Functioneaza doar cu compilatorul Turbo C
#include <conio.h>

typedef struct {
int x;
int y;
} PUNCT;

#include "FUNCTIA114A.C" /* afiscar */
#include "FUNCTIA114C.C" /* segoriz */ 
#include "FUNCTIA114D.C" /* segvert */
#include "FUNCTIA114E.C" /* segoblic */

#define C '*'

main()
{
static PUNCT a = (40, 1);
static PUNCT b = (35, 6);
static PUNCT c = (35, 16);
static PUNCT d = (40, 21);
static PUNCT e = (45, 16);
static PUNCT f = (45, 6);
static PUNCT g = (35, 11);
static PUNCT h = (45, 11);

clrscr();

segvert(&b, &c, C);
segvert(&a, &d, C);
segvert(&f, &e, C);

segoriz(&b, &f, C);
segoriz(&c, &e, C);
segoriz(&g, &h, C);

segoblic(&a, &b, C);
segoblic(&a, &f, C);
segoblic(&b, &e, C);
segoblic(&f, &c, C);
segoblic(&c, &d, C);
segoblic(&e, &d, C);

getch();
}

10.11. Sa se scrie un program care realizeaza urmatoarele:

La inceputul programului se citeste un intreg ce reprezinta numarul examenelor sustinute, apoi se citesc denumirile materiilor la care s-au sustinut examene. In continuare, pentru fiecare candidat, se citesc:

Daca un candidat are mai multe prenume, acestea se concateneaza prin liniuta de unire, nu se vor separa prin spatii. In felul acesta, chiar daca sunt mai multe prenume, ele se pot citi prin scanf, ca si cum ar fi un singur prenume.

Data nasterii se tasteaza printr-un sir de 6 cifre: zzllaa, primele 2 cifre reprezinta ziua, urmatoarele 2 luna, iar ultimele 2 anul.

Adresa este o succesiune de caractere care nu contine caractere albe. Spatiile din cadrul unei adrese se vor inlocui cu caracterul subliniere. In felul acesta, adresa poate fi citita ca un singur element.

Programul utilizeaza urmatoarele functii definite in exercitiile precedente:

pcit_int_lim pentru a citi date de tip int care se afla intr-un interval precizat (exercitiul 8.3.);
pcit_data_calend pentru a citi si valida o data calendaristica (exercitiul 8.4.);
pcit_int functie apelata de pcit_int_lim (exercitiul 8.2.);
v_calend functie apelata de pcit_data_calend (exercitiul 6.5.).

Programul mai apeleaza functia pcit_sir definita in acest exercitiu, care realizeaza urmatoarele:

Programul se executa conform pasilor de mai jos:

  1. Citeste pe n, numarul examenelor (se apeleaza pcit_int_lim).
  2. Citeste denumirile celor n materii care se examineaza (se apeleaza pcit_sir de n ori);
  3. i = 0 (numarator pentru candidati);
  4. Se citesc datele de identificare ale unui candidat si notele acestuia.
    Se pastreaza datele citite, apoi se trece la pasul 5.
    Citirile se realizeaza apeland functiile indicate mai sus.
    Daca nu mai sunt date de citit se trece la punctul 7;
  5. i = i + 1
  6. Se reia de la punctul 4;
  7. Se fac initializari pentru calculele de medii pe materii si a mediei generale;
  8. Se afiseaza antetul listei;
  9. Pentru fiecare candidat se afiseaza:
    • lista cu datele de identificare, notele obtinute la fiecare materie (nota 0 se considera neprezentare la examen) si media notelor respective;
    • dupa ce s-au listat toate datele pentru toti candidatii se trece la punctul 10.
  10. Se afiseaza mediile pe materii;
  11. Se afiseaza media generala.

In programul de fata se presupune ca sunt cel mult 5 examene.

Datele relative la un candidat si denumirile materiilor de examinat se pastreaza in memoria heap.

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "FUNCTIA094B.C" /* pcit_int */
#include "FUNCTIA094C.C" /* pcit_int_lim */
#include "FUNCTIA092C.C" /* v_calend */
#include "FUNCTIA094D.C" /* pcit_data_calend */

#define MAX 100


int nrzile[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};

int pcit_sir(char *, char **);

main()
{
    typedef struct {
        int zi;
        int luna;
        int an;
    } DC;

    typedef struct {
        char *nume;
        char *prenume;
        DC data_nasterii;
        char *adresa;
        int nrex;
        int nota[5];
    } CAND;

    CAND *tcand[MAX];
    char *denex[5];
    int nex;
    char er[]="s-a citit EOF\n";
    int i, j, k;
    char *temp;
    float tmed[5];
    float medgen;
    float med;

    /* citeste numarul examenelor */
    if(pcit_int_lim("numarul examenelor: 1-5: ", 1, 5, &nex) == 0) {
        printf(er);
        exit(1);
    }

    /* citeste denumirile materiilor si le pastreaza in memoria heap */
    for(i=0; i < nex; i++)
    if(pcit_sir("denumire materie: ", &denex[i]) == 0) {
        printf(er);
        exit(1);
    }

    /* se citesc datele de identificare ale elevilor si notele */
    i = 0;
    while(i < MAX) {
        printf("se citesc datele elevului nr: %d\n", i+1);
    /* citeste numele candidatului */
        if(pcit_sir("nume: ", &temp) == 0)
            break; // nu mai sunt alti candidati
        /* rezerva zona pentru o data de tip CAND */
        if((tcand[i] = (CAND *)malloc(sizeof(CAND))) == 0) {
            printf("memorie insuficienta\n");
            exit(1);
        }
    /* tcand[i] are ca valoare adresa de inceput a zonei din
    memoria heap in care se pastreaza o data structurata
    de tip CAND */

    /* se pastreaza pointerul spre numele candidatului curent citit,
    neme pastrat de functia pcit_sir in memoria heap */
        tcand[i] -> nume = temp;

    /* se citeste prenumele */
        if(pcit_sir("prenume: ", tcand[i] -> prenume) == 0) {
            printf(er);
            exit(1);
        }
    /* citeste data nasterii */
        if(pcit_data_calend(&tcand[i] -> data_nasterii.zi,
                            &tcand[i] -> data_nasterii.luna,
                            &tcand[i] -> data_nasterii.an) == 0) {
            printf(er);
            exit(1);
        }
    /* citeste adresa */
        if(pcit_sir("adresa: ", &tcand[i] -> adresa) == 0) {
            printf(er);
            exit(1);
        }
    /* pastreaza numarul examenelor */
        tcand[i] -> nrex = nex;

    /* se citesc notele,
    se tasteaza in ordinea citirii denumirilor materiilor */
        for(j=0; j < nex; j++)
        if(pcit_int_lim(denex[j], 0, 10, &tcand[i] -> nota[j]) == 0) {
            printf(er);
            exit(1);
        }
    /* s-au citit toate datele pentru un candidat */
    i++;
    }

    /* initializari pentru calculul mediilor pe materii */
    for(j=0; j < nex; j++)
        tmed[j] = 0.0;
    medgen = 0;

    /* afiseaza antetul */
    printf("\n\n\tNotele de la examenul de admitere din 25 martie 2019\n");
    printf("\n\n\n");
    printf("%20s", " "); // 20 de spatii pentru nume prenume

    /* se scriu denumirile examenelor */
    for(j=0; j < nex; j++) {
        printf("%10s", denex[j]);
        printf(" " ); // cel putin un spatiu dupa fiecare denumire
    }
    printf("Media\n\n");

    /* lista cu datele de identificare,
    notele si media pentru fiecare candidat */
    for(j=0; j < i; j++) {
        // date de identificare
        printf("%25s %25s %02d/%02d/%02d\n",
               tcand[j] -> nume,
               tcand[j] -> prenume,
               tcand[j] -> data_nasterii.zi,
               tcand[j] -> data_nasterii.luna,
               tcand[j] -> data_nasterii.an);
        // adresa
        printf("\t%s\n", tcand[j] -> adresa);
        // note
        printf("%20s"," ");
        for(k=0, med=0.0; k < nex; k++) {
            printf("%10d ", tcand[j] -> nota[k]);
            med += tcand[j] -> nota[k];
            tmed[k] += tcand[j] -> nota[k];
        }
        printf("%6.2f\n", med/nex);
    }

    /* afisare medii pe materii */
    printf("\n\n Media pe materii ");
    for(j=0; j < nex; j++) {
        printf("%11.2f", tmed[j]/i);
        medgen += tmed[j]/i;
    }

    /* afisare media generala */
    printf("\n\n Media generala: %10.2f", medgen/nex);
}

int pcit_sir(char *text, char **sir)
/* - afiseaza text si citeste o succesiune de caractere;
   - pastreaza succesiunea citita in memoria heap si
   atribuie adresa acestei zone pointerului sir;
   - returneaza:
        0 - la sfarsitul de fisier;
        1 - in caz contrar;
   - intrerupe executia programului daca nu exista
   memorie heap suficienta pentru a pastra
   sirul de caractere citit. */
{
    char t[255];
    char *p;

    printf(text);
    if(gets(t) == 0)
        return 0;

    // rezerva zona in memoria heap
    if((p = (char *)malloc(strlen(t) + 1)) == 0) {
        printf("memorie insuficienta\n");
        exit(1);
    }

    // transfera sirul din t la adresa continuta in p
    strcpy(p, t);
    *sir = p;
    return 1;
}

10.4. Reuniune