Índex

 
Capítol08.zip Exercicis08.zip
Capítol 8

Matrius. Estructures. Unions

  1. Les matrius de dues dimensions.
  2. El pas de matrius de dues dimensions a funcions
  3. Les estructures.
  4. Variables vector d'estructures
  5. Estructures niades
  6. Exercicis
  7. Les unions

 

8.1. Les matrius de dues dimensions.

Si mirem el quadre següent veiem que té 3 files de 5 columnes cadascuna. Es a dir que és una matriu 3X5.

Així l'element (0,4) és 23 i l'element (2,3) és 178.
 

  0 1 2 3 4
0 123 265 1 438 23
1 234 12 13 14 15
2 23 56 -12 178 2

Les matrius de tires de caràcters son en realitat matrius bidimensionals com pots observar a la figura següent:
 

  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
0 J i m e n e z , L o p e z ; M i g u e l \0          
1 B a s , O l i v a ; A n n a \0                      
2 Z a m o r a , R i v e r a ; R a m o n \0            
3 P u i g , A d a m s ; R i c a r d \0                
4 C a b a l l e r o , M o n t a n c h e z ; P e p e \0
5 L l u c h , P i ; A l b e r t \0                    
6 \0                                                  
7 \0                                                  
8 \0                                                  

En el programa següent vueràs com es declara una matriu de dues dimensions i com s'assignen i usen les dades d'aquestes matrius.
 

#include <stdio.h>
#include <conio.h> 

main(void){
    int i,j; 
    /* Declaració de la variable bidimensional Numero[3][5] de 3 files i 5 columnes. 
        Es dona valor a tots els elements de la matriu. Es poden ometre elements però 
        seguint algunes regles.*/

    int Numero[3][5] =
    {
         {123, 265, 1, 438, 23},
         {234, 12, 13, 14, 15}, 
         { 23, 56, -12, 178, 2}
    }; 

    clrscr(); 

    printf("Treballarem amb els elements d'una matriu (3x5)\n");
    printf("El número (0,4) és %d \n",Numero[0][4]);
    printf("El número (1,2) és %d \n",Numero[1][2]); 

    printf("\nDona'm un número i el posaré al lloc (0,4) ");
    scanf("%d", &Numero[0][4]);
    printf("Ara el número (0,4) és %d\n",Numero[0][4]); 

    printf("\nEl número (2,0) és %d \n",Numero[2][0]);
    Numero[2][0]=-123;
    printf("Ara el número (2,0) és %d\n",Numero[2][0]); 

    printf("\nAqui teniu tots els elements de la matriu\n\n"); 

    for(i=0;i<3;i++)
    {
        for(j=0;j<5;j++) printf("%5d",Numero[i][j]);
        printf("\n");
    }

Un programa que inicialitza la matriu de noms és el següent:

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

main(void) 
{
    int i; 

    /*Declaració i assignació de part dels noms de la variable Nom.*/
    char Nom[9][26]=
    {
        "Jimenez,Lope;Miguel","Bas,Oliva;Anna",
        "Puig,Adams;Ricard","Caballero,Montanchez;Pepe",
        "Lluch,Pi;Albert"
    };

    clrscr(); 

    printf("\nEscriu el teu nom i el posar‚ a la posició 6 ");
    scanf("%[^\n]",Nom[6]);
    printf("El teu nom est en Nom[6]: %s\n",Nom[6]); 

    strcpy(Nom[7],"Riera,Riuet;Reidor");
    printf("\nAra he assignat a Nom[7] %s amb la funció strcpy\n",Nom[7]); 

    printf("Els noms enmagatzemats a la matriu Nom són \n\n");
    for(i=0;i<9;i++) printf("%s \n",Nom[i]);

8.2. El pas de matrius de dues dimensions a funcions

En el programa següent s'incialitza una matriu de dues dimensions i es crea una funció per imprimir. Observa que per cridar la funció es dona cada vegada un vector i el número d'elements d'aquest vector.
 
#include <stdio.h>
#include <conio.h> 

void ImprimeLinea(int Elemento[],int NumElementos);
int main(void)
{
    int Basura[3][4] = 
    {
       { 2, 4, 5, 8},
       { 3, 4, 6, 9},
       {12, 10, 8, 6}
    }; 

    int i,j;

    clrscr(); 

    for(i=0;i<3;i++)
    {
       ImprimeLinea(Basura[i],4);
       printf("\n");
    }

    return 0;

void ImprimeLinea(int Elemento[],int NumElementos)
{
    int i; 
    for(i=0;i<NumElementos;i++) printf("%8d",Elemento[i]);

8.3. Les estructures.

Quan es tracta d'enmagatzemar dades és molt normal utilitzar una representació en format de fitxa, com les Fitxes d'una biblioteca o les dades d'una persona al fitxer de dades personals d'una empresa. Son allò que a las bases de dades es diuen registres.
 
 

A la figura veiem un registre, d'una base de dades que es pot anomenar agenda. És el registre número 123. Els camps són

Nom, Direcció, Telèfon, Ciutat, Província, Codi Postal i Telèfon 2.

El número del registre també és un camp.

En C es poden declarar estructures per simular aquesta situació: Primer es declara un nou tipus de dades i després es poden declarar variables amb aquest nou tipus. El programa següent ens serveix per explicar les estructures amb l'exemple agenda.
 
 

#include <stdio.h> 

/*Defineix el nou tipus d'estructura de dades*/
struct RegistreAgenda 
{
    int Num; 
    char Nom[45];
    char Adreca[35];
    char Telefon[15];
    char Poblacio[20];
    char CodiPostal[5];
    char Telefon2[15];
}; 

/*funció principal*/
main(void) 
{
     /*Declara RegistreDeTreball de tipus RegistreAgenda */ 
    struct RegistreAgenda RegistreDeTreball; 

    printf("Número: "); scanf("%d",&RegistreDeTreball.Num);
    fflush(stdin);
    printf("Nom: ");
    gets(RegistreDeTreball.Nom); 

    printf("Adreça: ");
    gets(RegistreDeTreball.Adreca); 

    printf("Telèfon: ");
    gets(RegistreDeTreball.Telefon); 

    printf("Població: ");
    gets(RegistreDeTreball.Poblacio);
    printf("Codi Postal: ");
    gets(RegistreDeTreball.CodiPostal);
    printf("Telèfon 2: ");
    gets(RegistreDeTreball.Telefon2); 

    printf("\nLes dades que has entrat son:\n"); 

    printf("Registre número %d\n", RegistreDeTreball.Num)
    printf("Nom: %s\n", RegistreDeTreball.Nom);
    printf("Adreça: %s\n", RegistreDeTreball.Adreca);
    printf("Telèfon: %s\n", RegistreDeTreball.Telefon);
    printf("Població: %s\n", RegistreDeTreball.Poblacio);
    printf("Codi Postal: %s\n", RegistreDeTreball.CodiPostal);
    printf("Telèfon 2: %s\n", RegistreDeTreball.Telefon2);

En aquest programa hem definit un nou tipus de dades RegistreAgenda i hem declarat i hem fet ús d'una variable d'aquest tipus RegistreDeTreball. Per accedir a les dades d'una variable de tipus estructura es fa ús del punt per indicar un camp com RegistreDeTreball.Nom.
Milorem ara aquest programa per fer funcions que ens realitzin dues de les tasques més frequents quan es treballa amb dades: Presa de dades de teclat i impressió en pantalla:
 

#include <stdio.h> 

/*Defineix el nou tipus d'estructura de dades*/
struct RegistreAgenda 
{
    int Num; 
    char Nom[45];
    char Adreca[35];
    char Telefon[15];
    char Poblacio[20];
    char CodiPostal[5];
    char Telefon2[15];
}; 

void EntraReg(struct RegistreAgenda *Reg);
void ImprimeReg(struct RegistreAgenda *Reg); 

int main(void)
{
    /*Declara RegistreDeTreball de tipus RegistreAgenda */ 
    struct RegistreAgenda RegistreDeTreball; 

    EntraReg(&RegistreDeTreball);
    printf("\nLes dades que has entrat son:\n");
    ImprimeReg(&RegistreDeTreball);
    return 0;

void EntraReg(struct RegistreAgenda *Reg)
{
    printf("Número: "); scanf("%d",&Reg->Num); 
    fflush(stdin);
    printf("Nom: "); gets(Reg->Nom);
    printf("Adreça: "); gets(Reg->Adreca);
    printf("Telèfon: "); gets(Reg->Telefon);
    printf("Població: "); gets(Reg->Poblacio);
    printf("Codi Postal: "); gets(Reg->CodiPostal);
    printf("Telèfon 2: "); gets(Reg->Telefon2);

void ImprimeReg(struct RegistreAgenda *Reg)
{
    printf("Registre número %d\n", Reg->Num); 
    printf("Nom: %s\n", Reg->Nom);
    printf("Adreça: %s\n", Reg->Adreca);
    printf("Telèfon: %s\n", Reg->Telefon);
    printf("Població: %s\n", Reg->Poblacio);
    printf("Codi Postal: %s\n", Reg->CodiPostal);
    printf("Telèfon 2: %s\n", Reg->Telefon2);

Observa les definicions de pas de paràmetres "struct RegistreAgenda *Reg" en el moment de definir la funció i "&RegistreDeTreball" en el moment de fer-ne ús des-de altra funció.

Aixó fa que en el moment de fer ús de les dades de una variable definida com *Reg la sintaxi sigui de la manera Reg->Num.

8.4. Variables vector d'estructures.

A la figura de la pàgina anterior hi ha 5 registres. Per poder enmagatzemar aquest 5 registres podem definir una variable matriu de manera que cada element de la matriu sigui un registre. Observa el programa següent i veuràs com es declara una matriu d'aquest tipus i com es fa ús de les seves dades.
 
#include <stdio.h>

struct RegistreAgenda
{
    int Num; 
    char Nom[45];
    char Adreca[35];
    char Telefon[15];
    char Poblacio[20];
    char CodiPostal[5];
    char Telefon2[15];
}; 

void main(void)
{
    /*Declara la matriu Agenda de tipus RegistreAgenda */ 
    struct RegistreAgenda Agenda[5]; 
    int i;
    char ch; 

    for(i=0;i<5;i++)
    {
        printf("Número: "); scanf("%d",&RegistreDeTreball.Num);
        printf("\nIntrodueix el registre nº %d\n",i+1);
        printf("Nom: "); gets(Agenda[i].Nom);
        printf("Adreça: "); gets(Agenda[i].Adreca);
        printf("Telèfon: "); gets(Agenda[i].Telefon);
        printf("Població: "); gets(Agenda[i].Poblacio);
        printf("Codi Postal: "); gets(Agenda[i].CodiPostal);
        printf("Telèfon 2: "); gets(Agenda[i].Telefon2);
    } 

    printf("\nLes dades que has entrat són:\n");
    for(i=0;i<5;i++) 
    {
        printf("Registre número %d", RegistreDeTreball.Num); 
        printf("\nAquest ‚s el registre nº %d\n",i+1);
        printf("Nom: %s\n", Agenda[i].Nom);
        printf("Adreça: %s\n", Agenda[i].Adreca);
        printf("Telèfon: %s\n", Agenda[i].Telefon);
        printf("Població: %s\n", Agenda[i].Poblacio);
        printf("Codi Postal: %s\n", Agenda[i].CodiPostal);
        printf("Telèfon 2: %s\n", Agenda[i].Telefon2);
   }

   printf("Prem return per continuar ");
   while(ch = getc(stdin) !='\n'); 

Com veus la instrucció de declaració és molt semblant a la de l'exercici de la pàgina 1 i per fer ús de les dades es posa l'index davant el punt.

Així:

Agenda[1].Nom és el nom de l'element 1 de la matriu.
Agenda[3].Telèfon és el telèfon de l'element 3 de la matriu
Nota: En el moment de declarar una variable estructura o de definir una variable matriu d'estructures es pot assignar valor a les dades de l'estructura. Així podem posar les inicialtzacions del quadre:
 
Variable RegistreDeTreball inicialitzada Matriu Agenda inicialitzada
struct RegistreAgenda RegistreDeTreball = 
{
    123,
    "Riera,Riuet;Reidor",
    "c) Llevador s/n",
    "(93) 7.25.34.23",
    "Sabadell",
    "08230",
    "93.7.25.09.09"
};
struct RegistreAgenda Agenda[5] =
{
    {
        123,
        "Riera,Riuet;Reidor"
        "c) Llevador s/n", 
        "(93) 7.25.34.23",
        "Sabadell",
        "08230",
        "(93) 7.25.0909"
    },
    {
        126,
        "Gozalvez,Lopez;Regidor",
        "c) Lavanderas 123",
        "(93) 7.25.12.92",
        "Sabadell",
        "08231",
        "(93) 7.26.12.12"
    }
}

Així podem entrar en el programa amb les dades de la variable RegistreDeTreball inicialitzades o de la matriu Agenda. Això es fa quan tenim unes dades constants que no s'han de variar al llarg de l'execució del programa. 

8.5. Estructures niades

Si es té definit un nou tipus d'estructura es pot utilitzar dins d'una altra estructura. Un exemple pot ser el següent, en el que el Nom d'una persona és una estructura inclosa dins de l'estructura RegistreAgenda (Fem un versió incompleta).
#include <stdio.h> 

struct Persona
{
    char Nom[15]; 
    char Pcognom[15];
    char Scognom[15];
}; 

struct RegistreAgenda
{
    int Num; 
    struct Persona PersonaRA;
    char Adreca[35];
    char Telefon[15];
    char Poblacio[20];
    char CodiPostal[5];
    char Telefon2[15];
}; 

void main(void)
{
    struct RegistreAgenda RegistreDeTreball; 
    printf("Número ");scanf("%d",&RegistreDeTreball.Num);fflush(stdin);
    printf("Nom: "); gets(RegistreDeTreball.PersonaRA.Nom);
    printf("Primer cognom: "); gets(RegistreDeTreball.PersonaRA.Pcognom);
    printf("Segon cognom: "); gets(RegistreDeTreball.PersonaRA.Scognom);
 

    printf("\nLes dades que has entrat són:\n"); 

    printf("Número %d\n",RegistreDeTreball.Num);
    printf("Nom: %s\n", RegistreDeTreball.PersonaRA.Nom);
    printf("Primer cognom: %s\n", RegistreDeTreball.PersonaRA.Pcognom);
    printf("Segon cognom: %s\n", RegistreDeTreball.PersonaRA.Scognom);

8.6. Exercicis

  1. Un programa ens demana cinc noms i els imprimeix després.

  2.  
  3. Declara una matriu 4x3 de números sencers i escriu els seus elements multiplicats per 5.
  4. Un programa ens demana els 8 elements d'una matriu 4x2. Després ens demana els elements d'una altra matriu 4x2. Per últim ens contesta amb una pantalla com la següent en la que la última matriu és la matriu suma.

  5.  
  6. Un programa ens demana els elements d'una matriu 3x3 i ens escriu a la matriu transposada i a suma de les dues matrius.

  7.  
  8. Un programa ens demana una llista de noms d'un número indeterminat d'elements. Després els escriu tots i ens diu qual és el primer i l'últim per ordre alfabètic i a més ens diu en quina posició es troben.

  9.  
  10. Escriu els programes de les pàgines 4 i 5 a l'ordinador i executa'ls.

  11.  
  12. Fes un programa que declari un vector de com a mínim 19 elements que han de ser els registres d'una base de dades personals de la classe. Aquest programa tindrà les funcions següents:

  13.  

     

    Principal, Demanar(Reg), Imprimir(Reg)

    Com que el programa ens ha de permetre editar tots els registres has de fer un menú d'opcions.
     

  14. Afegeix una opció d'ordenació dels registres.

  15.  
  16. Afegeix l'opció de cerca seqüencial.

  17.  
  18. Afegeix l'opció de cerca dicotòmica.

8.7. Les unions

Una unió és un instrument que permet guardar dades de diferents tipus a la mateixa variable de memòria. Es fa us d'aquest tipus de variable quan no se sap que tipus de dades es guardaran.

Les unions es preparen d'una manera molt semblant a les estructures. Es defineix un nou tipus de dades i després es creen les variables d'aquest tipus.

Nou tipus:
 
 

union Dat 
{
    int Petit; 
    doubel Gros;
    char Lletra;
 Possibles declaracions de variables:
                union Dat Dia;
                union Dat Dies[100];
                union Dat *Dia;
La primera declara la variable Mida del tipus union Dat, la segona és una matriu del mateix tipus i la tercera un punter.

Quan el compilador es troba la instrucció union Dat Mida reserva una zona de memòria del màxim número de bytes dels tipus inclosos a la definició de la unió; Així un char necessita un byte, un int 2 bytes y un double necessita 8. Per tant es farà una reserva de vuit bytes.

Per assignar dades a la variable Dia hem de fer ús de l'operador . al igual que en una estructura:

                Dia.Petit=25;
                Dia.Gros=3333333;
                Dia.Lletra='h';
Hem de pensar que només pot aparèixer una informació, així que la primera instrucció posa a Dia un 25. La segona treu aquesta informació i la substitueix per 3333333. Al final queda una h.

Quan es treballa amb punters es fa ús dels operadors & (direcció) i ->.