IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

Tipus de dades bàsics

Recursos:

Booleans

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;

Mida real de les variables

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).

Punters

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:

Tipus de dades compostes

Arrays (vectors i matrius)

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;

Cadenes de caràcters

É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;
}

Copiar dues cadenes de caràcters (strcpy)

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);

matrius

#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);


Exemples d'arrays

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.

Visualitzar una matriu

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");
  }
}

}

Passar arrays a funcions

Consulteu Pas d'arrays a funcions.

enum

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;
}

Estructures

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;
 
}

Treball amb punters a estructures

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);
}

Reserva de memòria de memòria dinàmica en estructures

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);
}

Estructures i typedef

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;

Copiar/assignar estructures (memcpy)

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.

Unions

typedef

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;

Funcions

Pas d'estructures a funcions

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:

gif_1.gif

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);
}

Pas d'arrays a funcions

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:

Pas d'arrays d'estructures

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);
 }
}

Pas de matrius

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:

Utilitzant estructures

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:

Passant les dimensions de la matriu

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;
  }
 }
}

argv a la funció main

Estructures de control

if

switch

switch (expressió) {
 case valor1:
      sentencia1;
      ...
      break;
 case valor2:
      sentencia1;
      ...
      break;
 ...
 default: sentenciaN;
}
}

Exemple menú principal

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'); 

}

while

Llibreries

Entrada/sortida

Gestió de memòria

malloc()

free()

Recursos