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.1/37

Ponteiros e Tabelas - fenix.tecnico.ulisboa.pt · Ponteiros e Tabelas Endereços e ponteiros Ponteiros e argumentos de funçıes Ponteiros e tabelas AritmØtica de endereços Ponteiros

  • Upload
    vuanh

  • View
    227

  • Download
    0

Embed Size (px)

Citation preview

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.1/37

Ponteiros e Endereços

Um ponteiro representa um endereço de memória

O operador unário & aplicado a x representa oendereç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.2/37

Utilização de Ponteiros

*px pode ser usado em vez de x

A declaração int *xpto() significa que xpto() retorna umponteiro para um inteiro

A declaração void abcd(char *) significa que a função abcdaceita como argumento um ponteiro para caracteres

A prioridade de & e * é superior à dos operadoresaritmé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.3/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.4/37

Passagem de Parâmetros por Referência

Passagem por referência consegue-se enviando osendereços

swap(int *a, int *b)

{

int aux;

aux = *a;

*a = *b;

*b = aux;

}

Chamada deverá ser swap(&x, &y)

AED 2003/2004 – p.5/37

Leitura de um Inteiro#include <ctype.h>

#include <stdio.h>

int getch(void);

void ungetch(int);

/* 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

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 conteudo de a[0] para x */

x = *(pa+1); /* Copia para x o conteudo de a[1] */

x = *(pa+i); /* Copia para x o conteudo de a[i] */

strlen(”Hello world”); /* string constant */

strlen(arr); /* char array[100] */

strlen(ptr); /* char *ptr */

AED 2003/2004 – p.7/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.8/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.9/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 100inteiros;

A declaração int *p não aloca qualquer espaço;

A função malloc(int size) aloca um espaço de dimensãosize

A declaração int *p = malloc(100*sizeof(int)); é equivalentea int p[100];

O espaço pode ser libertado com a chamada free(p);

AED 2003/2004 – p.10/37

Ponteiros para Caracteres

Uma constante do tipo string "Hello world" é uma tabelade 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.11/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.12/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.13/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.14/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.15/37

Tabelas de Ponteiros

Exemplo: ordenação de cadeias de caracteres

Usa-se mesmo algoritmo que para ordenação deinteiros

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 e %s\n",i,lineptr[i]);

AED 2003/2004 – p.16/37

Ler e Guardar Linhas/* readlines: le 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;

}

AED 2003/2004 – p.17/37

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

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.19/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.20/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.21/37

Inicialização de Tabelas de Ponteiros

/* month_name: devolve nome do i-esimo mes */

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.22/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.23/37

Ponteiros para Funções

É possível declarar ponteiros para funções

Uma função pode ser passada como argumento paraoutra

/* Funcao qsort generica */

void qsort(char *v[],int left, int right, int (*comp)(char *, char *);

...

if ((*comp)(v[i],v[j])) {

...

}

/* Uso da funcao qsort */

char *lineptr[MAXLINES]; /* Tabela de ponteiros */

int strcmp(char *, char *);

...

qsort(lineptr, 0, nlines-1, strcmp); /*Funcao strcmp como argumento*/

AED 2003/2004 – p.24/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()

{

/* funcao para multiplicar matrizes A e B */

}

(cont.)

AED 2003/2004 – p.25/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.26/37

Versão 1void 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];

}

}

AED 2003/2004 – p.27/37

Versão 2 – Utilização da Transposta

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 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.29/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.30/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.31/37

Stack de Inteiros com Tabela Dinâmica

Utilizar tabela dinâmica para implementar stack devalores inteiros com tamanho arbitrário

AED 2003/2004 – p.32/37

istack.hextern void st_init();

extern void st_push(int value);

extern int st_pop();

extern int st_is_empty();

AED 2003/2004 – p.33/37

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

istack.c – Versão 1void 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.35/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;

}

AED 2003/2004 – p.36/37

istack.c – Versão 2void 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