Vom prezenta in continuare citeva metode de manipulare a tablourilor bidimensionale.
Mai intii vom folosi metoda de alocare statica, punind in evidenta doua moduri de acces (cu formula de acces si cu expresii compacte cu pointeri):
#include <stdio.h>
#define N 10
#define M 20
void main(void)
{
int a[N][M];
int
register int i;
register int j;
for (i=0;i<N;i++)
for (j=0;j<M;j++)
a[i][j]=0;
}
|
#include <stdio.h>
#define N 10
#define M 20
void main(void)
{
int a[N][M];
int
register int *p;
for (p=&a[0][0];p<&a[N][0];p++)
*p=0;
}
|
|
Am declarat cele doua variabile i, j de tip registers pentru o executie mai rapida a programului. |
Programul initializeaza pointerul p cu adresa de inceput a sirului
p=&a[0][0];
si paraseste bucla for cind s-a ajuns la sfirsit
p<&a[N][0]
deoarece ultima adresa valida din sir este
&a[N-1][M-1]
|
Programul in sine nu face mare lucru (initializarea unei matrici), in schimb ceea ce este de retinut sunt modalitatile de manipulare.
In continuare vom folosi alocarea dinamica pentru declararea unui sir bidimensional.
#include <stdio.h>
#include <stdlib.h>
#define N 10
#define M 20
void main(void)
{
int *a;
register int i;
register int j;
a=(int *)malloc(sizeof(int)*N*M);
if (a==NULL){
fprintf(stderr,"Nu avem spatiu!");
exit(1);
};
for (i=0;i<N;i++)
for (j=0;j<M;j++)
a[i*N+j]=0;
}
Acest program aloca o zona liniara pentru o matrice si foloseste o formula pentru accesarea fiecarui element.
Desigur, ca se putea folosi metoda din programul 2, fara a mai fi nevoie de calculul expresiei, dar am vrut punerea in evidenta a unei metode de acces aleator (nu secvential) a elementelor.
#include <stdio.h>
#include <stdlib.h>
#define N 10
#define M 20
void main(void)
{
int **a;
register int **ppi;
register int *pi;
register int i,j;
pi=(int *)malloc(sizeof(int)*N*M);
if (pi==NULL){
fprintf(stderr,"Nu avem spatiu!");
exit(1);
};
ppi=(int **)malloc(sizeof(int *)*N);
if (ppi==NULL){
fprintf(stderr,"Nu avem spatiu!");
exit(1);
};
for (i=0;i<N;i++){
ppi[i]=pi;
pi+=M;
};
a=ppi;
for (i=0;i<N;i++)
for (j=0;j<M;j++)
a[i][j]=0;
}
ppi este un pointer la un pointer la un intreg. Deci il putem interpreta ca un sir de pointeri la intregi. Adica va fi un sir de adrese ale liniilor sirului bidimensional.
Printf este un exemplu de functie al carui numar de argumente nu se stie in momentul compilarii. Pentru a scrie o astfel de functie trebuie sa folosim facilitatile introduse de header-ul stdarg.
Iata in continuare o functie ce concateneaza un numar arbitrar de siruri de caractere.
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
char *vstrcat(char *fmt, ...)
{
size_t len;
char *buf;
va_list argp;
char *p;
if(fmt==NULL)
return NULL;
len = strlen(fmt);
va_start(argp,fmt);
while((p=va_arg(argp, char *)) != NULL)
len+=strlen(p);
va_end(argp);
buf =(char *)malloc(len+1);
if(buf==NULL)
return NULL;
strcpy(retbuf,fmt);
va_start(argp,fmt);
while((p = va_arg(argp, char *)) != NULL)
strcat(buf,p);
va_end(argp);
return buf;
}
Mod de utilizare:
char *sir = vstrcat("Ghici, cine ","vine ","la cina!",(char *)NULL);
Se observa cast-ul de la ultimul argument.
Declaratia
va_list argp;
defineste lista de argumente ce va fi utilizata de macrourile va_arg, va_end.
Inainte de a descarca argumentele din stiva este necesara initializarea listei de argumente:
va_start(argp,fmt);
Initializeaza lista de argumente argp la primul argument fixat din lista variabila (fmt).
Rutina va_arg descarca stiva de argumente. Ea primeste doi parametri: numele listei de argumente si tipul datei care se descarca.
Nu se poate afla numarul de argumente cu care a fost apelata o functie cu numar variabil de astfel de elemente, intr-un program care sa respecte conditia de portabilitate .
De exemplu, printf isi determina numarul de argumente din numarul de % care apar in sirul de formatare. O alta metoda, folosita si in exemplul anterior, este de a folosi o valoare care sa semnifice incheierea listei de argumente (0, -1, NULL).
Nu se pot declara functii
int f(...)
{
}
deoarece standardul C cere existenta cel putin a unui argument fixat (pentru apelul lui va_start()).
Pentru argumentele din partea variabila se aplica regula: argumentele de tip float sunt extinse la double,iar char si short la int. Deci nu este corect apelul va_arg(argp, float);.
Iata in continuare o alta functie care afiseaza un mesaj de eroare, comportindu-de asemanator cu printf.
#include <stdio.h>
#include <stdarg.h>
void error(char *fmt, ...)
{
va_list argp;
fprintf(stderr, "e;eroare: "e;);
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
fprintf(stderr, "e;\n"e;);
}