Recursos:
En C no hi ha un tipus de dades per als booleans i se solen implementar utilitzant enters i utilitzant constants predefinides:
# ifndef TRUE # define TRUE 1 # define FALSE 0 #endif typedef int boolean;
Depenent de la plataforma, els diferents tipus de dades bàsics poden tenir diferents mides físiques. Amb el següent programa, podeu comprovar quina és la mida de les vostres variables:
#include <stdio.h> int main() { printf("size of a char is %d\n", sizeof(char)); printf("size of a short is %d\n", sizeof(short)); printf("size of a int is %d\n", sizeof(int)); printf("size of a long is %d\n", sizeof(long)); }
$ gcc -Wall -g -o sizeof sizeof.c sizeof.c: In function ‘main’: sizeof.c:8: avís: control reaches end of non-void function $ ./sizeof size of a short is 2 size of a int is 4 size of a long is 4
NOTA: sizeof torna un enter que és el nombre de chars que ocupa la variable (típicament un char es 1 byte).
Definició de variable a punter
int *ptr;
Operacions d'assignació possibles
Assigna el punter
ptr = &k;
Assigna el valor:
*ptr = 7;
Exemple:
#include <stdio.h> int j, k; int *ptr; int main(void) { j = 1; k = 2; ptr = &k; printf("\n"); printf("j has the value %d and is stored at %p\n", j, (void *)&j); printf("k has the value %d and is stored at %p\n", k, (void *)&k); printf("ptr has the value %p and is stored at %p\n", ptr, (void *)&ptr); printf("The value of the integer pointed to by ptr is %d\n", *ptr); return 0; }
Recursos:
Les matrius o vectors es declaren de la següent forma:
tipusBaseDades nom[enter][enter];
Per exemple un vector d'enters:
int enters[10];
O una cadena de caràcters:
char nom[10];
Es pot declarar un cadena com una constant amb:
static char nom[10];
Es poden utilitzar matrius multidimensionals amb:
int matriu[10][10];
Inicialialització d'arrays:
int my_array[] = {1,23,17,4,-5,100};
Accés als valors d'un array:
int *ptr; ptr = &my_array[0];
my_array[0] és equivalent a *(ptr) my_array[1] és equivalent a *(ptr + 1) my_array[2] és equivalent a *(ptr + 2) ...
L'array és sempre un punter a la primera posició de l'array. Per tant:
ptr = &my_array[0];
és equivalent a
ptr = my_array;
És el que en altres llenguatges de programació coneixem com enter. En C les cadenes de caràcters són vectors de caràcters que finalitzen amb el caràcter especial null (\0). El llenguatge C permet l'assignació de cadenes sense la necessitat d'especificar la seva mida de form explícita:
static char nom[5]="SERGI"
On
nom[0]="S" nom[1]="E" nom[2]="R" nom[3]="G" nom[4]="I"
També es pot declarar de la següent forma:
static char nom[5]="SERGI"
O declarar més espai i no utilitzar-lo tot:
char my_string[40] = "Pep";
No és fàcil operar directament amb cadenes de caràcters i per aquesta raó C incorpora una sèrie de funcions de manipulació de cadenes de caràcters a les seves llibreries estàndard.
Exemple:
#include <stdio.h> char strA[80] = "A string to be used for demonstration purposes"; char strB[80]; int main(void) { char *pA; /* a pointer to type character */ char *pB; /* another pointer to type character */ puts(strA); /* show string A */ pA = strA; /* point pA at string A */ puts(pA); /* show what pA is pointing to */ pB = strB; /* point pB at string B */ putchar('\n'); /* move down one line on the screen */ while(*pA != '\0') /* line A (see text) */ { *pB++ = *pA++; /* line B (see text) */ } *pB = '\0'; /* line C (see text) */ puts(strB); /* show strB on screen */ return 0; }
Igual que passa amb les estructures, les cadenes de caràcters no es poden assignar/copiar directament. Cal utilitzar strcpy:
#include <string.h> char *strcpy(char *dest, const char *src);
#define ROWS 5 #define COLS 10 int multi[ROWS][COLS];
Hi ha 2 formes d'accedir als valors de la matriu:
multi[row][col]
o
*(*(multi + row) + col)
Exemple (inicialitzar una matriu):
void set_value(int m_array[][COLS]) { int row, col; for (row = 0; row < ROWS; row++) { for (col = 0; col < COLS; col++) { m_array[row][col] = 1; } } }
Podem cridar a la funció amb:
set_value(multi);
Exemple 1:
#include <stdio.h> int my_array[] = {1,23,17,4,-5,100}; int *ptr; int main(void) { int i; ptr = &my_array[0]; /* point our pointer to the first element of the array */ printf("\n\n"); for (i = 0; i < 6; i++) { printf("my_array[%d] = %d ",i,my_array[i]); /*<-- A */ printf("ptr + %d = %d\n",i, *(ptr + i)); /*<-- B */ } return 0; }
és equivalent a:
#include <stdio.h> int my_array[] = {1,23,17,4,-5,100}; int *ptr; int main(void) { int i; ptr = my_array; /* point our pointer to the first element of the array */ printf("\n\n"); for (i = 0; i < 6; i++) { printf("my_array[%d] = %d ",i,my_array[i]); /*<-- A */ printf("ptr + %d = %d\n",i, *(ptr + i)); /*<-- B */ } return 0; }
Exemple 2:
#include <stdio.h> #include <stdlib.h> #define COLS 5 typedef int RowArray[COLS]; RowArray *rptr; int main(void) { int nrows = 10; int row, col; rptr = malloc(nrows * COLS * sizeof(int)); for (row = 0; row < nrows; row++) { for (col = 0; col < COLS; col++) { rptr[row][col] = 17; } } return 0; }
Exemple 3:
#include <stdio.h> #include <stdlib.h> int main(void) { int nrows = 5; /* Both nrows and ncols could be evaluated */ int ncols = 10; /* or read in at run time */ int row; int **rowptr; rowptr = malloc(nrows * sizeof(int *)); if (rowptr == NULL) { puts("\nFailure to allocate room for row pointers.\n"); exit(0); } printf("\n\n\nIndex Pointer(hex) Pointer(dec) Diff.(dec)"); for (row = 0; row < nrows; row++) { rowptr[row] = malloc(ncols * sizeof(int)); if (rowptr[row] == NULL) { printf("\nFailure to allocate for row[%d]\n",row); exit(0); } printf("\n%d %p %d", row, rowptr[row], rowptr[row]); if (row > 0) printf(" %d",(int)(rowptr[row] - rowptr[row-1])); } return 0; }
Ateneció: s'assumeix un compilador ANSI. Si s'utilitza el C original de K&R cal fer :
rptr = (RowArray *)malloc(.... etc.
int tauler[MAX_FILES][MAX_COLUMNES]; for (x = 0; x < MAX_FILES; ++x) { for (y = 0; y < MAX_COLUMNES; ++y) { tauler[x][y]=0; } } visualitza(MAX_FILES,MAX_COLUMNES,&tauler[0][0]); //visualitza2(MAX_FILES,MAX_COLUMNES,&tauler[0][0]); //1a opció void visualitza(int files,int columnes,int *p) { int i=0; int j=0; for (i=0;i<files;i++) { for(j=0;j<columnes;j++) { printf("\t%d",*p); if((i!=files) && (j!=columnes)) { p++; } } printf("\n"); } void visualitza2(int files, int columnes,int *p) { int i; int j; for(i=0; i<files; i++) { for(j=0; j<columnes; j++) { printf("\t%d",p[i*columnes+j]); } printf("\n"); } } }
Consulteu Pas d'arrays a funcions.
Permet definir llistes de valors.
Exemple:
# ifndef TRUE # define TRUE 1 # define FALSE 0 #endif enum esquerreDreta {esq,dret}; typedef int boolean; typedef int tipusDada; boolean inserirNode (arbreBinari &ar,tipusDada e, esquerreDreta subarbre) { boolean resultat)= FALSE; if (!arbreNoBuit(ar)) { if (esquerreDreta==esq) { ar->esquerre= construir(NULL, NULL, e); } else { ar->dreta= construir(NULL, NULL, e); } resultat=TRUE; } return resultat; }
Declaració de l'estructura:
struct nomEstructura { tipus_de_dades variable1; tipus_de_dades variable2; ... tipus_de_dades variableN; };
Declaració d'una variable d'una estructura:
struct nomEstructura nomVariable;
Accés als valors d'una estructura:
var_struct.campo1 = 10; var_struct.campo2 = var_struct.campo1 * 3.1415;
Exemple:
struct Persona { /* Edat de la persona */ int edat; /* DNI */ char DNI[20]; /* Nom */ char nom[20]; }; /* Declarem dos variables del tipus Persona */ struct Persona membre1; struct Persona membre2; /* Asignamos algunos valores */ miembre1.edat = 21; miembre2.edat = 23;
Exemple 3:
struct Data { int dia; int mes; int any; }
struct Persona { char *nom; Data dataNaixement; } void main () { Persona *persona; Persona persones[100]; Persona sergi={"Sergi Perez",{2,4,1800}}; empleats[1].dataNaixement.dia=3; empleats[1].dataNaixement.mes=3; empleats[1].dataNaixement.any=1976; }
Quan es tracta d'un punter a una estructura es pot utilitzar l'operador -> per accedir al valor d'un membre de l'estructura. Per tant:
(*punterEstructura).membre=valor;
És equivalent a :
punterEstructura->membre=valor;
Exemple:
Vegeu l'ús de -> en la següent funció que inicialitza un arbre binari:
//Definició de l'estructura struct arbreBinari { int valor; arbreBinari *esquerre; arbreBinari *dreta; }; typedef arbreBinari *arbre; arbreBinari construir(arbreBinari esquerre, arbreBinari dret, int valor) { arbre ar; if ((ar= (arbre) malloc(sizeof(arbreBinari))) == NULL) { //Mostrar un error printf("Error al cridar a malloc"); exit(1); } ar->valor=valor; ar->esquerre=esquerre; ar->dret=esquerre; return ar; }
Un altre exemple:
#include <stdio.h> #include <string.h> struct tag{ /* the structure type */ char lname[20]; /* last name */ char fname[20]; /* first name */ int age; /* age */ float rate; /* e.g. 12.75 per hour */ }; struct tag my_struct; /* define the structure */ void show_name(struct tag *p); /* function prototype */ int main(void) { struct tag *st_ptr; /* a pointer to a structure */ st_ptr = &my_struct; /* point the pointer to my_struct */ strcpy(my_struct.lname,"Jensen"); strcpy(my_struct.fname,"Ted"); printf("\n%s ",my_struct.fname ); printf("%s\n",my_struct.lname); my_struct.age = 63; show_name(st_ptr); /* pass the pointer */ return 0; } void show_name(struct tag *p) { printf("\n%s ", p->fname); /* p points to a structure */ printf("%s ", p->lname); printf("%d\n", p->age); }
Veiem un exemple amb una estructura de dades dinàmica típica: arbre binari
Definició de l'estructura
struct arbreBinari { int valor; arbreBinari *esquerre; arbreBinari *dreta; }; typedef arbreBinari *arbre;
Reserva dinàmica de memòria
arbre ar; if ((ar= (arbre) malloc(sizeof(arbreBinari))) == NULL) { //Mostrar un error printf("Error al cridar a malloc"); exit(1); }
Es pot combinar l'ús de typedef amb:
typedef struct posicio POSICIO; struct posicio{ int x; int y; }posicio;
o de forma equivalent:
typedef struct{ int x; int y; }POSICIO;
Les estructures no es poden copiar/assignar directament. El següent codi no és vàlid:
struct { int x,y,z; } pixel1, pixel2; pixel2 = pixel1; // INCORRECTE!
Cal utilitzar memcpy:
#include <string.h> void *memcpy(void *dest, const void *src, size_t n);
Exemple:
memcpy(&pixel2, &pixel1, sizeof(pixel2));
D'aquesta manera es copien els continguts mitjançant els punters a les estructures.
Permet definir nous tipus de dades. Per exemple en C no hi ha booleans, però els podem definir amb:
#ifndef TRUE #define TRUE 1 #define FALSE 0 #endif typedef int boolean; ... if (condicio) return TRUE; else return FALSE;
Es passen per referència (punter) si es vol modificar valors de l'estructura o es poden passar per valor si només es faran operacions de consulta.
Consulteu:
Declaració de la funció:
void prova(POSICIO *pos);
Definició de la funció:
void prova(POSICIO *pos) { }
Crida:
prova(&pos_inicial);
Exemple:
#include <stdlib.h> #include <stdio.h> typedef struct{ int x; int y; }POSICIO; void prova(POSICIO *pos); int main(int argc, char **argv) { //inicialització //Paràmetres // argv[1] --> x inicial // argv[2] --> y inicial POSICIO pos_inicial;
pos_inicial.x=atoi(argv[1]); pos_inicial.y=atoi(argv[2]);
prova(&pos_inicial); return 0;
} void prova(POSICIO *pos) { printf("x=%d\n",pos->x); printf("y=%d\n",pos->y); }
Exemple 2. Pas per valor:
#include <stdio.h> typedef struct robot ROBOT; struct robot { char *name; int energy; int IQ; float velocity; }; void info(ROBOT r); /* declare function */ int main() { ROBOT r1 = {"Earthling Ed", 100, 231, 4.1}; /* initialize 2 ROBOTs */ ROBOT r2 = {"Toxic Tom", 150, 254, 2.5}; info(r1); info(r2); return 0; } void info(ROBOT r) { printf("%s has %d units of energy, an IQ of %d...\n", r.name, r.energy, r.IQ); printf("... and a velocity of %0.1f metres per second.\n", r.velocity); }
En aquest pas el que es passa és un punter al primer element del vector
Declaració de la funció
int addNumbers(int fiveNumbers[]);
Definició de la funció:
int addNumbers(int fiveNumbers[]) { ... }
O equivalentment:
int addNumbers(int *fiveNumbers); /* declare function */ int addNumbers(int *fiveNumbers) { /* define function */ ... }
Crida de la funció:
int array[5]; addNumbers(array);
NOTA IMPORTANT: Cal tenir en compte que no hi ha CAP MANERA de saber la mida del vector dins la funció i que per tant o es coneix a priori aquesta mida (p.ex. és fixa i donada per una constant), o cal passar el nombre d'elements del vector com a paràmetre de la funció
L'exemple més clar d'això és la funció main:
int main(int argc, char *argv[]) { }
Exemple 1
#include <stdio.h> int addNumbers(int fiveNumbers[]); /* declare function */ int main() { int array[5]; int i; printf("Enter 5 integers separated by spaces: "); for(i=0 ; i<5 ; i++) { scanf("%d", &array[i]); } printf("\nTheir sum is: %d\n", addNumbers(array)); return 0; } int addNumbers(int fiveNumbers[]) { /* define function */ int sum = 0; int i; for(i=0 ; i<5 ; i++) { sum+=fiveNumbers[i]; /* work out the total */ } return sum; /* return the total */ }
Exemple 2 amb nombre elements
#include <stdio.h> #include <stdlib.h> int addNumbers(int fiveNumbers[], int num_numbers); /* declare function */ int main(int argvc, char *argv[]) { int num_elements=atoi(argv[1]); int array[num_elements]; int i; printf("Enter %d integers separated by spaces: ",num_elements); for(i=0 ; i<num_elements ; i++) { scanf("%d", &array[i]); } printf("\nTheir sum is: %d\n", addNumbers(array,num_elements)); return 0; } int addNumbers(int fiveNumbers[], int num_numbers) { /* define function */ int sum = 0; int i; for(i=0 ; i<num_numbers ; i++) { sum+=fiveNumbers[i]; /* work out the total */ } return sum; /* return the total */ }
Recursos:
Es passen igual que si el vector fos de un tipus de dades bàsic.
typedef struct posicio POSICIO; struct posicio{ int x; int y; }; ... POSICIO recorregut[MAX_FILES*MAX_COLUMNES]; //o struct posicio recorregut[MAX_FILES*MAX_COLUMNES]; recorregut[0].x=1; recorregut[0].y=1; recorregut[1].x=2; recorregut[1].y=2; recorregut[2].x=3; recorregut[2].y=3; recorregut[3].x=3; recorregut[3].y=3; recorregut[4].x=4; recorregut[4].y=4; mostrarsolucio2(recorregut,1,5); void mostrarsolucio2(POSICIO recorregut[],int nelements) { int i; for (i = 0; i < nelements ++i) { printf("(%d,%d) ",recorregut[i].x,recorregut[i].y); } }
Definició de la funció:
void function(int *aaa, int r, int c) { for(int i=0; i<r; i++) { for(int j=0; j<c; j++) { aaa[i*c+j] = i*j; } } }
Crida a la funció:
int a[6][6]; // pass a pointer to the first element function(&a[0][0], 6, 6); // or alternately use a cast function((int*)a, 6, 6); // or alternately use array row dereferencing function(a[0], 6, 6); // or alternately use dereferencing (I find this a bit weird that *a == a && a == &a) function(*a, 6, 6);
Recursos:
struct aaa { int value[10][20]; } int function (struct aaa *parameter) { for(int i=0; i<10; i++) { for (int j=0; i<20; j++) { parameter[i][j] = i*j; } } }
Recursos:
void function(int *aaa[][], int 1d, int 2d) { for(int i=0; i<1d; i++) { for(int j=0; j<2d; j++) { aaa[i][j] = i*j; } } }
switch (expressió) { case valor1: sentencia1; ... break; case valor2: sentencia1; ... break; ... default: sentenciaN; } }
int main (void) { arbreBinari ar; int opcio; do { printf("Arbre binari de cerca\n") printf("1 Inserir element\n"); printf("2 Buscar un element\n"); ... printf("9 Finalitzar\n"); opcio = getc(0); switch (op) { case 1: inserirElement(arbre); break; case 2: buscarElement(arbre); break; ... } } while (opcio!='9'); }