AED 2003/2004 p.1/37 Ponteiros e Tabelas Endereços e ponteiros Ponteiros e argumentos de funções Ponteiros e tabelas Aritmética de endereços Ponteiros para caracteres Tabelas de ponteiros e ponteiros para ponteiros Tabelas multi-dimensionais Inicialização de tabelas de ponteiros Argumentos da linha de comandos Ponteiros para funções
AED 2003/2004 p.2/37 Ponteiros e Endereços Um ponteiro representa um endereço de memória O operador unário & aplicado a x representa o endereço de x #include <stdio.h> main () int y,x=3; int *px = &x; y = *px; *px = 0; printf("%d %d\n",x,y);
AED 2003/2004 p.3/37 Utilização de Ponteiros *px pode ser usado em vez de x A declaração int *xpto() significa que xpto() retorna um ponteiro para um inteiro A declaração void abcd(char *) significa que a função abcd aceita como argumento um ponteiro para caracteres A prioridade de & e * é superior à dos operadores aritméticos y = *px + 1 funciona como esperado ++*px incrementa o valor de x (*px)++ (os parênteses são necessários)
AED 2003/2004 p.4/37 Passagem de Parâmetros para Funções Em C, os parâmetros são passados por valor swap(int a, int b) int aux; aux = a; a = b; b = aux; Não funciona como pretendido
AED 2003/2004 p.5/37 Passagem de Parâmetros por Referência Passagem por referência consegue-se enviando os endereços swap(int *a, int *b) int aux; aux = *a; *a = *b; *b = aux; Chamada deverá ser swap(&x, &y)
/* getint: get next integer from input into *pn */ int getint(int *pn) int c, sign; while (isspace(c = getch())) ; /* skip white space */ if (!isdigit(c) && c!= EOF && c!= + && c!= - ) ungetch(c); /* it is not a number */ return 0; sign = (c == - )? -1 : 1; if (c == + c == - ) c = getch(); for (*pn = 0; isdigit(c); c = getch()) *pn = 10 * *pn + (c - 0 ); *pn *= sign; if (c!= EOF) ungetch(c); return c; AED 2003/2004 p.6/37 Leitura de um Inteiro #include <ctype.h> #include <stdio.h> int getch(void); void ungetch(int);
AED 2003/2004 p.7/37 Ponteiros e Tabelas Em C, existe uma relação entre ponteiros e tabelas int a[10]; int *pa; int x; int i = 3; pa = &a[0]; /* pa fica a apontar para a[0] */ x = *pa; /* Copia o conteúdo de a[0] para x */ x = *(pa+1); /* Copia para x o conteúdo de a[1] */ x = *(pa+i); /* Copia para x o conteúdo de a[i] */ strlen( Hello world ); /* string constant */ strlen(arr); /* char array[100] */ strlen(ptr); /* char *ptr */
AED 2003/2004 p.8/37 Exemplo /* strlen: return length of string s */ int strlen(char *s) int n; for (n = 0; *s!= \0 ; s++) n++; return n;
AED 2003/2004 p.9/37 Representação do Endereço Zero Ponteiro especial para representar zero. int *y; y = NULL;... if (!y) /* problem handling code */...
AED 2003/2004 p.10/37 Ponteiros e Tabelas Nos argumentos de uma função, a declaração int *p; declara o mesmo que int p[]; A declaração int p[100]; declara uma tabela com 100 inteiros; A declaração int *p não aloca qualquer espaço; A função malloc(int size) aloca um espaço de dimensão size A declaração int *p = malloc(100*sizeof(int)); é equivalente a int p[100]; O espaço pode ser libertado com a chamada free(p);
AED 2003/2004 p.11/37 Ponteiros para Caracteres Uma constante do tipo string "Hello world" é uma tabela de caracteres char *pmessage; pmessage = "Hello world"; /* Copia apenas os ponteiros */ As declarações char amessage[] = "Hello world"; char *pmessage = "Hello world"; São diferentes. Porquê?
AED 2003/2004 p.12/37 Ponteiros para Caracteres /* strcpy: copy t to s; array subscript version */ void strcpy(char *s, char *t) int i; i = 0; while ((s[i] = t[i])!= \0 ) i++; /* strcpy: copy t to s; pointer version */ void strcpy(char *s, char *t) while ((*s = *t)!= \0 ) s++; t++;
AED 2003/2004 p.13/37 Strcpy: Versão 3 /* strcpy: copy t to s; pointer version 2 */ void strcpy(char *s, char *t) while ((*s++ = *t++));
AED 2003/2004 p.14/37 Mais Funções para Strings /* strcmp: return <0 if s<t, 0 if s==t, >0 if s>t */ int strcmp(char *s, char *t) for ( ; *s == *t; s++, t++) if (*s == 0) return 0; return *s - *t;
AED 2003/2004 p.15/37 Aritmética de Endereços Operações válidas sobre ponteiros: Adição/subtração de inteiro: p1 + k; p1 - k; Subtração de ponteiros (numa mesma tabela): p1 - p2; Atribuição de 0 ou de ponteiro: p1 = 0; p1 = p2; Comparação com 0 ou com ponteiro: p1 == 0; p1 == p2;
AED 2003/2004 p.16/37 Tabelas de Ponteiros Exemplo: ordenação de cadeias de caracteres Usa-se mesmo algoritmo que para ordenação de inteiros Evita-se copiar strings usando tabelas de ponteiros int i; /* Representa uma tabela de ponteiros para caracteres */ char *lineptr[maxlines]; readlines(lineptr,maxlines); for (i=0; i< MAXLINES; i++) printf("linha %d é %s\n",i,lineptr[i]);
AED 2003/2004 p.17/37 Ler e Guardar Linhas /* readlines: lê linhas de entrada */ int readlines(char *lineptr[], int maxlines) int len, nlines; char *p, line[maxlen]; nlines = 0; while ((len = getline(line, MAXLEN)) > 0) if (nlines >= maxlines (p = malloc(len)) == NULL) return -1; else line[len-1] = \0 ; /* delete newline */ strcpy(p, line); lineptr[nlines++] = p; return nlines;
Ler, Ordenar e Imprimir linhas #include <stdio.h> #include <string.h> #define MAXLINES 5000 char *lineptr[maxlines]; /* Tabela de ponteiros */ int readlines(char *lineptr[], int nlines); void writelines(char *lineptr[], int nlines); void qsort(char *lineptr[], int left, int right); main() int nlines; if((nlines = readlines(lineptr, MAXLINES)) >= 0) qsort(lineptr, 0, nlines-1); writelines(lineptr, nlines); return 0; else printf("error: input too big to sort\n"); return 1; AED 2003/2004 p.18/37
AED 2003/2004 p.19/37 Quicksort para Strings void qsort(char *v[], int left, int right) int i, last; void swap(char *v[], int i, int j); if(left >= right) return; swap(v, left, (left + right)/2); last = left; for(i = left+1; i <= right; i++) if(strcmp(v[i], v[left]) < 0) swap(v, ++last, i); swap(v, left, last); qsort(v, left, last-1); qsort(v, last+1, right);
AED 2003/2004 p.20/37 Troca e Impressão de Linhas /* swap: swap v[i] and v[j] */ void swap(char *v[], int i, int j) char *tmp; tmp = v[i]; v[i] = v[j]; v[j] = tmp; void writelines(char *lineptr[], int nlines) int i; for(i=0; i<nlines; i++) printf("%s\n", lineptr[i]);
AED 2003/2004 p.21/37 Tabelas Multi-Dimensionais A declaração int x[nrows][ncols] declara uma matriz É equivalente a int *x[nrows] Elemento na linha i e coluna j é x[i][j] int x[nrows][ncols] aloca o espaço NROWS*NCOLS int *x[nrows] aloca o espaço para NROWS ponteiros Na prática, ponteiros para tabelas são mais usados Qualquer número de dimensões pode ser usado Primeira dimensão pode não ser especificada
AED 2003/2004 p.22/37 Inicialização de Tabelas de Ponteiros /* month_name: devolve nome do i-ésimo mês */ char *month_name(int n) /* Inicializa tabela de ponteiros */ static char *name[] = "Illegal month", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ; return (n < 1 n > 12)? name[0] : name[n];
AED 2003/2004 p.23/37 Argumentos da Linha de Comandos argv[0] é o nome do programa argv[i] é i-ésimo argumento Programa "echo" echo hello world gera hello world main(int argc, char *argv[]) int i; for(i=1; i<argc; i++) printf("%s ",argv[i]); printf("\n"); return 0;
AED 2003/2004 p.24/37 Ponteiros para Funções É possível declarar ponteiros para funções Uma função pode ser passada como argumento para outra /* Função qsort genérica */ void qsort(char *v[],int left, int right, int (*comp)(char *, char *);... if ((*comp)(v[i],v[j]))... /* Uso da função qsort */ char *lineptr[maxlines]; /* Tabela de ponteiros */ int strcmp(char *, char *);... qsort(lineptr, 0, nlines-1, strcmp); /*Função strcmp como argumento*/
AED 2003/2004 p.25/37 Multiplicação de Matrizes #include <stdlib.h> #define MATDIM 500 int mata[matdim][matdim], matb[matdim][matdim], matc[matdim][matdim]; void init() int i, j; for (i=0; i<matdim; ++i) for (j=0; j<matdim; ++j) mata[i][j] = i+j; matb[i][j] = i-j; void prod() /* função para multiplicar matrizes A e B */ (cont.)
AED 2003/2004 p.26/37 Multiplicação de Matrizes int sum() int i, j, sum = 0; for (i=0; i<matdim; ++i) for (j=0; j<matdim; ++j) sum += matc[i][j]; return sum; main() init(); prod(); printf("soma: %d\n", sum());
AED 2003/2004 p.27/37 Versão 1 void prod() int i, j, k; for (i=0; i<matdim; ++i) for (j=0; j<matdim; ++j) matc[i][j] = 0; for (k=0; k<matdim; ++k) matc[i][j] += mata[i][k] * matb[k][j];
void init() int i, j; for (i=0; i<matdim; ++i) for (j=0; j<matdim; ++j) mata[i][j] = i+j; matb[j][i] = i-j; void prod() int i, j, k; for (i=0; i<matdim; ++i) for (j=0; j<matdim; ++j) int *pc = &(matc[i][j]); int *pa = &(mata[i][0]); int *pb = &(matb[j][0]); *pc = 0; for (k=0; k<matdim; ++k) *pc += *(pa++) * *(pb++); AED 2003/2004 p.28/37 Versão 2 Utilização da Transposta
AED 2003/2004 p.29/37 Versão 3 Optimizar Acessos void prod() int i, j, k, t; int *pa, *pb; for (i=0; i<matdim; ++i) for (j=0; j<matdim; ++j) pa = mata[i]; pb = matb[j]; t = 0; for (k=0; k<matdim; ++k) t += *(pa++) * *(pb++); matc[i][j] = t;
AED 2003/2004 p.30/37 Versão 4 Comparar Ponteiros void prod() int i, j, k, t; int *pa, *pb, *pf; for (i=0; i<matdim; ++i) for (j=0; j<matdim; ++j) pa = &(mata[i][0]); pb = &(matb[j][0]); pf = pa + MATDIM; t = 0; for (; pa<pf; ) t += *(pa++) * *(pb++); matc[i][j] = t;
AED 2003/2004 p.31/37 Tempos de Execução Versão 1: 1.65s Versão 2: 0.61s Versão 3: 0.38s Versão 4: 0.35s
AED 2003/2004 p.32/37 Stack de Inteiros com Tabela Dinâmica Utilizar tabela dinâmica para implementar stack de valores inteiros com tamanho arbitrário
AED 2003/2004 p.33/37 istack.h extern void st_init(); extern void st_push(int value); extern int st_pop(); extern int st_is_empty();
istack.c Versão 1 #include <stdlib.h> #define MAXVALUE 5 static int *st_value; static int st_top; static int st_max; static void increase_stack_size() int i, *ptmp = st_value, *pa, *pb, *pf; st_max = 2 * st_max; st_value = (int*) malloc(st_max * sizeof(int)); for (pa=ptmp, pb=st_value, pf=st_value+st_top; pb<=pf; ) *(pb++) = *(pa++); free(ptmp); (cont.) AED 2003/2004 p.34/37
AED 2003/2004 p.35/37 istack.c Versão 1 void st_init() st_top = -1; st_max = MAXVALUE; st_value = (int*) malloc(st_max*sizeof(int)); void st_push(int value) if (st_top >= st_max-1) increase_stack_size(); st_value[++st_top] = value; int st_pop() if (!st_is_empty()) return st_value[st_top--]; return -1; int st_is_empty() return st_top == -1;
AED 2003/2004 p.36/37 istack.c Versão 2 #include <stdlib.h> #define MAXVALUE 5 static int *st_value; static int *st_sup; static int st_max; static void increase_stack_size() int i, *ptmp = st_value, *pa, *pb; int diff = st_sup - st_value; st_max = 2 * st_max; st_value = (int*) malloc(st_max * sizeof(int)); for (pa=ptmp, pb=st_value; pa<st_sup; ) *(pb++) = *(pa++); free(ptmp); st_sup = st_value + diff;
istack.c Versão 2 void st_init() st_max = MAXVALUE; st_value = (int*) malloc(st_max*sizeof(int)); st_sup = st_value; void st_push(int value) if (st_sup == st_value+st_max) increase_stack_size(); *(st_sup++) = value; int st_pop() if (!st_is_empty()) return *(--st_sup); return -1; int st_is_empty() return st_sup == st_value; AED 2003/2004 p.37/37