- Per definir un array d'una o vàries dimensions, s'ha d'escriure el tipus i el nom de la taula (com en les variables simples), però després del nom s'han d'escriure uns claudàtors amb un número d'elements per a cada dimensió. Per exemple, es defineix taula (1D, 9 enters), a (2D, 3x80 enters), m (2D, 3x4 reals) i m3 (3D, 6x6x6 reals), més algunes altres variables simples:
int i, j, taula[9], s, a[3][80]; float m[3][4], m3[6][6][6];
- El número d'elements de cada dimensió defineix el rang d'índexs, que sempre és des de 0 fins a n-1, per a cada dimensió. Per exemple, la variable taula té 9 elements, que són:
taula[0], taula[1], ..., taula[8]
- Els arrays de dues dimensions s'emmagatzemen per files, és a dir, el primer índex fa referència a la fila i el segon a la columna. En el cas general (n dimensions), el primer índex és el més significatiu i l'últim índex és el menys significatiu. És a dir, els elements es van emmagatzemant per variació dels índexs de més a la dreta cap als índexs de més a l'esquerra:
m[0][0], m[0][1], m[0][2], m[0][3] m[1][0], m[1][1], m[1][2], m[1][3] m[2][0], m[2][1], m[2][2], m[2][3]
- L'accés als arrays es fa sobre elements individuals. Cada element de la taula es comporta com una variable del tipus que s'ha definit l'array. Per identificar un element, cal posar el nom de l'array seguit d'una expressió entre claudàtors (una per cada dimensió) que calcularà l'índex concret. Aquesta expressió pot ser una constant, una variable o un càlcul. Alguns exemples d'accés a taula i a m:
for(i=0;i<9;i++) taula[i]=0; taula[4]++; taula[i]+= taula[i+1]*16; taula[i*3+2]= taula[(j++)*2+1]; for(i=0;i<3;i++) { s=0; for(j=0;j<3;j++) s+= m[i][j]; m[i][3]=s; }
- Cal anar amb compte quan es posa un càlcul, ja que es podria sortir del rang i accedir a alguna posició de memòria que no correspon a l'array. El compilador no pot donar cap error, ja que és un error d'execució. Sí que es pot, però, generar codi de comprovació per a que cada vegada que es faci un accés es verifiqui un possible mal funcionament del programa (opció de compilació que es pot activar en la fase de proves/depuració);
- El què sí que pot ser molt problemàtic és la modificació d'alguna variable dins l'expressió d'índex (efectes laterals). No és recomanable l'ús d'expressions com "taula[j++]=j;" si no se sap exactament com s'avaluen (la variable s'incrementa abans o després de carregar el seu valor sobre la taula? sobre quin element es carrega realment?).
- Els strings són vectors de caràcters. L'única diferència és que, per conveni, un string sempre s'acaba amb '\0' (ASCII 0). D'aquesta forma es poden definir cadenes de caràcters de longitud variable. L'inconvenient de les cadenes de longitud variable és que sovint desaprofiten alguns bytes de l'espai total reservat per a l'array. Per tant, a l'hora de definir una cadena de caràcters, cal tenir en compte la longitud màxima que es preveu per la cadena, més un element addicional per guardar un 0 de fi de string (cal que existeixi sempre).
Exemples:
ex 2.1: Al subdirectori SEMINARI\SEC2 es troba el fitxer CADENA.C, que correspon al següent codi. Aquest programa defineix un vector de caràcters i l'omple, un per un, amb la cadena "hola", més el corresponent fi d'string '\0':
#include <stdio.h> void main(void) { char sal[5]; /* vector de 5 caràcters */ sal[0]='h'; /* el primer element del vector és sal[0] */ sal[1]='o'; sal[2]='l'; sal[3]='a'; sal[4]='\0'; /* també es pot posar sal[4]=0; */ printf("%s\n",sal); /* %s indica que s'ha d'imprimir un string */ }
cex 2.1: Proveu de compilar i executar el programa CADENA. Després proveu d'eliminar la línia que introdueix el caràcter 0 i torneu a compilar i executar. El resultat és imprevisible, ja que la funció printf rep el punter on comença el vector en memòria, i el va accedint i imprimint de forma seqüencial fins que troba un caràcter 0. Si no s'ha definit, s'imprimiran els bytes que hi hagin emmagatzemats a continuació del vector, fins que algun d'ells sigui 0:
#include <stdio.h> void main(void) { char sal[5]; sal[0]='h'; sal[1]='o'; sal[2]='l'; sal[3]='a'; printf("%s\n",sal); }
ex 2.2: Per copiar un string a sobre d'un altre, no es pot fer servir l'operador d'assignació '=', ja que el C no pot copiar vectors d'aquesta forma (s'han de copiar element a element). Per treballar amb strings, però, es disposa d'unes rutines de llibreria que estan especificades en el Header STRING.H. Així, es pot fer servir la funció strcpy(), que copia el segon string sobre el primer (suposa que el primer sigui prou gran):
#include <stdio.h> #include <string.h> /* defineix la funció strcpy() */ void main(void) { int i; char sa[20]; /* string de 20 caràcters, sentinella inclòs */ strcpy(sa,"hola\tadiós\n"); /* el 2on paràmetre és un string constant */ /* els símbols "\t" i "\n" són un únic caràcter */ for (i=0; i<12; i++) printf("\'%c\'\t%d\n",sa[i],sa[i]); }
cex 2.2: Contraexemple de com no es pot assignar un string:
void main(void) { char sa[20]; sa="hola\tadiós\n"; /* no es copien els caràcters sobre sa */ : :
ex 2.3: Si no es vol (o no es pot) fer servir les rutines estàndard de tractament de strings, sempre es pot copiar-los caràcter a caràcter. Per inicialitzar un string amb una cadena constant, en canvi, es pot fer servir la possibilitat del C d'inicialitzar una variable quan es defineix el seu tipus. En el cas dels strings, fins i tot es pot deixar que el compilador calculi la mida de la cadena, si no es posa el rang:
#include <stdio.h> void main(void) { int i=0; /* defineix i inicialitza l'enter i */ char s1[20]; /* defineix i dimensiona la cadena s1 */ char s2[]="hola\tadiós\n"; /* defineix, inicialitza i dimensiona la cadena s2 (12 caràcters en total) */ do { s1[i]=s2[i]; /* copia la cadena s1 sobre s2, caràcter a caràcter */ i++; }while (s1[i-1]!='\0'); /* fins que s'ha copiat el sentinella */ for (i=0; i<20; i++) /* imprimeix els 20 caràcters de s2 */ printf("\'%c\'\t%d\n",s1[i],s1[i]); }
- Per practicar amb els arrays, es proposa un exercici sobre strings, que consisteix en llegir del teclat una cadena de com a màxim 40 caràcters, i imprimir per pantalla línies que comencin per la primera lletra, i a cada línia afegir una lletra més del string, fins imprimir tot el string. Per llegir la cadena feu servir la funció gets() (Header STDIO.H). El final de cadena és '\0' (ASCII 0).
Algorisme:
importacions (includes) Principal definicions de variables (vector de 40 caràcters, etc.) inicialitzar gets(cadena); /* suposar que s'escriuen menys de 40 caràcters */ per i=1 fins final(cadena[i]) fer guardar caràcter i escriure un fi d'string sobre el caràcter i imprimir l'string recuperar caracter i fiper Fi