Programarea Calculatoarelor, seria CC

Laborator 10

Structuri, uniuni, enumerări. Pointeri la funcții. Directive de preprocesare. Operatori pe biți

În acest laborator veţi învăţa să:



Structuri

Definirea unei structuri:

struct A {
    int a, b, c;
}; // se va folosi: "struct A x" pentru a declara o variabila de acest tip

typedef struct A B; // asa se poate folosi "B x"

// intr-un singur pas:
typedef struct C {
    int x, y;
} C;

Membrii unei structuri se accesează folosind .. Pentru pointerii la structuri, se poate folosi mai întai * pentru a accesa structura și apoi . sau folosind direct ->. Exemplu:

typedef struct {
    int x, y, z;
} POINT;

int main()
{
    POINT p, *pp;
    pp = &p; // pp va fi un pointer catre p
    p.x = 1;
    (*pp).y = 2;
    pp->z = 3;
    printf("%d %d %d\n", pp->x, p.y, p.z
    return 0;
}

Uniuni

Uniunile permit accesarea aceleiași zone din memorie ca fiind de mai multe tipuri de date. Toate elementele declarate într-o uniune ocupă aceeași zonă de memorie, dimensiunea ei fiind maximul dintre dimensiunile membrilor. Declararea unei uniuni are aceeași sintaxă cu declararea unei structuri.
Exemplu:

union number {
    long int l;
    struct {
        short int lo;
        short int hi;
    }
}; // permite accesarea acelorasi 4 bytes fie ca un intreg lung, fie ca 2 short int, prin obtinerea celor 2 jumatati componente

Enumerări

Folosite pentru a da nume simbolice. Sintaxa:

enum nume_enumeratie { val1, val2, val3, ... };

Exemplu:

int main()
{
    int a, b, rez;
    enum operatii { adunare, scadere, inmultire } op;
    scanf("%d%d%d", &a, &b, &op);
    switch (op) {
        case adunare: rez = a + b; break;
        case scadere: rez = a - b; break;
        case inmultire: rez = a * b; break;
    }
    printf("%d\n", rez);
    return 0;
}

Pointeri la funcții

Declararea unei variabile de tip pointer la funcție are următoarea sintaxă: tip_returnat (*nume_pointer) (lista_argumente).
Exemplu de utilizare:

#include <stdio.h>;

int cmp_cresc ( const int x, const int y )
{
    if ( x == y )
        return 0;
    return x > y ? 1 : -1;
}

int cmp_desc ( const int x, const int y )
{
    if ( x == y )
        return 0;
    return x > y ? -1 : 1;
}

void swap ( int *x, int *y)
{
    int aux;
    aux = *x;
    *x = *y;
    *y = aux;
}

void sort(int v[], int n, int (*cmp) ( const int x, const int y) )
{
    int i, j;
    for ( i = 0; i < n - 1; i++ )
        for ( j = i + 1; j < n; j++ )
            if ( cmp ( v[i], v[j] ) == 1 )
                swap( &v[i], &v[j] );
}

int main()
{
    int v[100], n, ord;
    int (*cmps[2]) ( const int, const int ) = { cmp_cresc, cmp_desc };
    // citire n si vector ...
    printf("Alegeti tipul de sortare: 0 - crescator; 1 - descrescator.\n");
    scanf("%d", &ord);
    sort(v, n, cmps[ord]);
    // afisare vector sortat ...
    return 0;
}

Directive de preprocesare

Sunt precedate întotdeauna de # și se termină la sfârșitul liniei. Pentru a extinde o directivă și pe linia următoare se folosește \. Preprocesarea se execută înainte de compilarea efectivă a programului.

Exemple directive de preprocesare: #define, #include, #if, #ifdef, #else, #line, #error

Exemple macrodefiniții (#define):

#define N 100
#define MAX( a , b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )

int main()
{
    int v[N], n, i, max;
    // citire vector
    max = v[0];
    for ( i = 1 ; i < n ; i++ )
        max = MAX ( max, v[i] );
    // ...
}

Operatori pe biți


Problema 1.

A.

Fie tipul struct multime:

struct multime {
    unsigned char a;
};
ce poate reprezenta mulțimi cu numere din intervalul [0..7] astfel: bitul i din a este 1 dacă numărul face parte din mulțime și 0 altfel. Considerăm biții numerotați de la dreapta spre stânga.

De exemplu, dacă a = 99 = (01100011)2 atunci mulțimea va fi {0, 1, 5, 6}.

Să se scrie următoarele funcții (0 <= x <= 7): Să se scrie un program ce testează funcțiile definite mai sus.

B.

Să se modifice structura și funcțiile definite anterior pentru a putea reprezenta mulțimi de numere întregi, din intervalul [0, n], n întreg.

Se va folosi un vector de unsigned char, fiecare reprezentând câte 8 numere din mulțime: v[0] - [0..7], v[1] - [8..15] etc. Va trebui să modificați struct multime astfel încât să se poată aloca dinamic memorie pentru vector, de exemplu:

struct multime {
    unsigned int n; // numărul maxim de elemente
    unsigned char *a;
};


Problema 2.

Să se scrie o funcție pentru calculul integralei definite, pe un interval dat [a,b] a unei funcții oarecare (cu rezultat real) f(x), prin metoda trapezelor, cu un număr dat de pași n.

Funcția primește ca argument adresa funcției de integrat și numărul de pași și va avea antetul double integrala( double (*func) (double x), double a, double b, int n );.

Programul principal va apela funcția de calcul a integralei pentru două funcții diferite și un n suficient de mare. Se pot integra functiile sin(x) si cos(x) pe intervalul [0, PI].


Problema 3.

Să se definească tipul structură MATERIA care conține cămpurile:

Scrieți funcția citire_MAT, care citește informațiile despre o variabilă de tip MATERIA.

Se va face validarea tuturor câmpurilor: Definiți tabloul PROGRAMA de MAX elemente de tip MATERIA, MAX fiind o constantă predefinită.

Scrieți funcția citire_PROGRAMA, de tip void, care inițializează tabloul PROGRAMA, prin apelul funcției citire_MAT.

Scrieți funcția afișare care primește ca parametru un caracter, un întreg și tabloul PROGRAMA și tipărește informațiile despre materiile din PROGRAMA care au tip_examen corespunzător caracterului și ore_curs egal cu întregul primit.

Scrieți un program care apelează funcțiile de mai sus.


Problema 4.

Să se definească o structură MATRICE care să conţină următorii membrii:

Se vor scrie următoarele funcţii: