1 / 59

Linguagem de programação I A

Linguagem de programação I A. Carlos Oberdan Rolim Ciência da Computação Sistemas de Informação. Versão: 220514_01. Ponteiros.  O C é altamente dependente dos ponteiros. Para ser um bom programador em C é fundamental que se tenha um bom domínio deles

foy
Download Presentation

Linguagem de programação I A

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Linguagem de programação I A Carlos Oberdan Rolim Ciência da Computação Sistemas de Informação Versão: 220514_01

  2. Ponteiros

  3.  O C é altamente dependente dos ponteiros. Para ser um bom programador em C é fundamental que se tenha um bom domínio deles • O Ministério da Saúde adverte: o uso descuidado de ponteiros pode levar a sérios bugs e a dores de cabeça terríveis :-).

  4. Ponteiros em Linguagem C O Que é uma variável? É uma área da memória do computador onde é armazenado um valor…. Exemplo 1: int a = 1;  Atribui ao endereço 1000 o valor 1 1000 1001 1002 1003

  5. Ponteiros em Linguagem C O Que É Um Ponteiro? Um ponteiro é uma variável que aponta para outra variável. Isto significa que um ponteiro mantém o endereço de memória de outra variável. Em outras palavras, o ponteiro não contém um valor no sentido tradicional, mas sim o endereço de outra variável. Um ponteiro "aponta para" esta outra variável mantendo uma cópia de seu endereço Convém dizer que a expressão “apontar para...” significa “armazenar o endereço de memória de...” Como um ponteiro contém um endereço, e não um valor, terá duas partes. O ponteiro contém um endereço e o endereço aponta para um valor. Há o ponteiro e o valor para o qual ele aponta. Este fato pode ser um tanto confuso, até você se familiarizar com ele. Superada a etapa da familiarização, ele se torna extremamente eficaz.

  6. Ponteiros em Linguagem C • Operadores relacionados a Ponteiros: *(asterisco): informa que uma variável irá armazenar o endereço de outra variável; ou: Informa ao computador que você deseja o conteúdo que está no endereço armazenado;- Pode ser lido como “o conteúdo no endereço” q = *m;  q recebe o valor armazenado no endereço m& (e comercial): retorna o endereço de uma variável;- Pode ser lido como “o endereço de”m = &count;  m recebe o endereço de count

  7. Ponteiros em Linguagem C int main() { int i,j; int *p; p = &i; *p=5; j=i; printf(("%d %d %d\n", i, j, *p); return 0; } ==> 5 5 5

  8. Operadores de ponteiros * (asterisco) indica que a variável é um ponteirotipo_dado *nome_ponteiro; • Ex: int x; int *pi; /* compilador sabe que pi é ponteiro */ /* pi é um ponteiro para inteiro */

  9. Operadores de ponteiros • o operador “&” quando aplicado sobre uma variável retorna o seu endereço • Ex: int x = 10, *pi; pi = &x; printf(“&x: %p pi: %p”, &x, pi); => &x: 0x03062fd8 pi: 0x03062fd8

  10. Operadores de ponteiros • o operador “*” quando aplicado sobre um ponteiro retorna o dado apontado • Ex: void main () { int *tmp_ptr; int x, y; x = 10; tmp_ptr = &x; y = *tmp_ptr; /* (*tmp_ptr) = 10 */ }

  11. Outro exemplo ilustrado int i; int *p; p = &i; *p=5;

  12. Relembrando... operador * Usado na declaração de um ponteiro int *x Usado para acessar o conteúdo de um endereço apontado *x = 10; // atribui o valor 10 ao local apontado pelo ponteiro ‘x’ printf(“%d”, *x); // imprime o valor armazenado no local apontado por ‘x’ operador & acessa o endereço de uma variável

  13. Exemplo de uso int a = 1;  declara variavel inteiro com valor 1 int *pt_a;  declara um ponteiro para um inteiro pt_a = &a;  ponteiro recebe o endereco da variavel a printf(“%d”, *pt_a);  imprime o valor apontado pelo ponteiro

  14. Ponteiros • ponteiros são variáveis tipadas:(int *) ≠ (float *) ≠ (char *) • As variaveis ponteiro devem sempre apontar para os tipos de dados corretos. Uma variavel ponteiro declarada como apontador de dados inteiros deve sempre apontar para dados deste tipo. • Ex: main() { int *ip, x; float *fp, z; ip = &x; /* OK */ fp = &z; /* OK */ ip = &z; /* erro */ fp = &x; /* erro */ }

  15. 1 byte 1 byte (int *) (float *) (char *) Ponteiros • espaço ocupado pelas variáveis • Ponteiro aponta para o tamanho segundo seu tipo

  16. Exemplo de uso Exemplo: int a = 1; int *pt_a; pt_a = &a; 1000 1001 1002 1003

  17. Ponteiros em Linguagem C Onde usar isto??? Funções! Alocação Dinâmica Não sei o tamanho que o vetor precisa ter….! Não sei o tamanho que cada string precisa ter… Não sei o tamanho que a matriz precisa ter…

  18. Utilizando Ponteiros void main() { int x = 10; int *pi; pi = &x; /* *pi == 10 */ (*pi)++; /* *pi == 11 */ printf(“%d”, x); } ==> 11 ao alterar *pi estamos alterando o conteúdo de x

  19. Utilizando Ponteiros void main() { int x = 10; int *pi, *pj; pi = &x; /* *pi == 10 */ pj = pi; /* *pj == 10 */ (*pi)++; /* (*pi, *pj, x) == 11 */ (*pj)++; /* (*pi, *pj, x) == 12 */ printf(“%d”, x); /* ==> 12 */ printf(“%x”, &pj); /* Endereco de x ==> 0x0c220c */ }

  20. Arrays e ponteiros • Lembrando: arrays são agrupamentos de dados adjacentes na memória • declaração: tipo nome_array[<tamanho>]; define um arranjo de <tamanho> elementos adjacentes na memória do tipo tipo_dado

  21. Arrays e ponteiros’ • Representação na memória: float m[10], *pf; pf = m; pf m Note que m é um ponteiro !!!!

  22. Referenciando Arrays • em float m[10]m é uma constante que endereça o primeiro elemento do array • portanto, não é possível mudar o valor de m • Ex: float m[10], n[10]; float *pf; m = n; /* erro: m é constante ! */ pf = m; /* ok */

  23. Referenciando Elementos • pode-se referenciar os elementos do array através do seu nome e colchetes: m[5] = 5.5; if (m[5] == 5.5) printf(“Exito”); else printf(“Falha”);

  24. Referenciando Elementos • Pode-se referenciar os elementos de um array através de ponteiros: float m[ ] = { 1.0, 3.0, 5.75, 2.345 }; float *pf; pf = &m[2]; printf(“%f”, *pf); /* ==> 5.75 */

  25. Referenciando Elementos • Pode-se utilizar ponteiros e colchetes: float m[] = { 1.0, 3.0, 5.75, 2.345 }; float *pf; pf = &m[2]; printf(“%f”, pf[0]); /* ==> 5.75 */ • Note que o valor entre colchetes é o deslocamento a ser considerado a partir do endereço de referência pf[n] => indica enésimo elemento a partir de pf

  26. Exemplo void main () { int arint[ ] = { 1,2,3,4,5,6,7 }; int size = 7; /* tamanho do array */ int i, *pi; for (pi=arint, i=0; i < size; i++, pi++) printf(“ %d “, *pi); } ==> 1 2 3 4 5 6 7

  27. Exemplo - variação voidmain () { int arint[] = { 1,2,3,4,5,6,7 }; int size = 7; /* tamanho do array */ int i, *pi; for (pi=arint, i=0; i < size; i++) printf(“ %d “, *pi++); } ==> 1 2 3 4 5 6 7

  28. Exemplo - variação voidmain () { int arint[] = { 1,2,3,4,5,6,7 }; int size = 7; /* tamanho do array */ int i, *pi; pi = arint; printf(“ %d “, *pi); pi += 2; printf(“ %d “, *pi); pi += 2; printf(“ %d “, *pi); pi += 2; printf(“ %d “, *pi); } ==> 1 3 5 7

  29. Isso causa a maior confusão.... int main() { int vetor[] = {1, 3, 5, 7, 9}; int *p = vetor; printf("%d \n", *p ); /* imprime 1 (posicao 0)*/ printf("%d \n", *p++ ); /* imprime 1 e incrementa o p para proxima posicao (posicao 1) */ printf("%d \n", (*p)++ ); /* imprime 3 e incrementa valor que esta posicao 1 (onde p aponta) */ printf("%d \n", *p ); /* p estah apontando para posicao 1, imprime 4 */ p++; /* p agora aponta para a proxima posicao, isto eh posicao 2, valor 5 */ printf("%d - %p\n", *p , p);/* imprime posicao 2, valor 5 */ ==> 1 1 3 4 5 Resumindo: p++  incrementa o ponteiro para próxima posição *p++  retorna o valor para onde p aponta e depois incrementa o p para próxima posição (*p)++  retorna o valor para onde p aponta e depois incrementa o valor que está ali armazenado (não muda a posição de p)

  30. Aritmética de Ponteiros • É possível fazer operações aritméticas e relacionais entre ponteiros e inteiros

  31. Aritmética de Ponteiros • Atribuição: Da mesma maneira que ocorre com uma variável comum, o conteúdo de um ponteiro pode ser passado para outro ponteiro do mesmo tipo. • Observar que em C é possível atribuir qualquer endereço a uma variável ponteiro. • Deste modo é possível atribuir o endereço de uma variável do tipo float a um ponteiro do tipo int. No entanto, o programa não irá funcionar da maneira correta. ....int vetor [] = { 10, 20, 30, 40, 50 };int *p1 , *p2;int i = 100;p1 = & vetor [2];p2 = &i;p2 = p1; ...

  32. Aritmética de Ponteiros • Soma e subtração:Quando soma-se 1 a uma variável seu valor é incrementado em 1. No caso de ponteiros quando adiciona-se 1 o valor é incrementado de um valor que corresponde a quantidade de bytes do tipo para o qual aponta • Assim, ao somar 1 a um ponteiro de int o seu valor será incrementado em 4 (devido a int = 4 bytes) • Ao somar-se um inteiro n a um ponteiro, endereçamos n elementos a mais (n positivo) ou a menos (n negativo) pf[2] equivale a *(pf+2) *(pf + n) endereça n elementos a frente *(pf - n) endereça n elementos atrás pf++ endereça próximo elemento array pf-- endereça elemento anterior array

  33. Aritmética de Ponteiros • Exemplos p = p + 3;  p aponte para o terceiro elemento após o atual *(p+1)=10;  armazena o valor 10 na posição seguinte • A diferença entre ponteiros fornece quantos elementos do tipo do ponteiro existem entre os dois ponteirosint main (void) { float vetor [] = { 1.0, 2.0, 3.0, 4.0, 5.0 }; float *p1 , *p2; p1 = & vetor [2]; /* endereco do terceiro elemento */ p2 = vetor; /* endereco do primeiro elemento */ printf(" Diferenca entre ponteiros %d\n", p1 -p2 ); return 0;} ==> 2

  34. Operações Válidas Sobre Ponteiros • É valido: • somar ou subtrair um inteiro a um ponteiro (pi ± int) • incrementar ou decrementar ponteiros (pi++, pi--) • subtrair ponteiros (produz um inteiro) (pf - pi) • comparar ponteiros ( >, >=, <, <=, == ) • Não é válido: • somar ponteiros (pi + pf) • multiplicar ou dividir ponteiros (pi*pf, pi/pf) • operar ponteiros com double ou float (pi ± 2.0)

  35. Cuidados... • C não controla os limites dos arrays, o programador deve fazê-lo • Ex: • encontrar o erro: voidmain () { int arint[] = { 1,2,3,4,5,6,7 }; int size = 7, i, *pi; for (pi=arint, i=0; i < size; i++, pi += 2) printf(“ %d “, *pi); }

  36. Cuidados... voidmain () { int arint[] = { 1,2,3,4,5,6,7 }; int size = 10; int i; for (pi=arint, i=0; i < size; i++) printf(“ %d “, arint[i]); }

  37. Cuidados... • Um ponteiro deve sempre apontar para um local válido antesde ser utilizado • Ex: voidmain () { int i=10, *pi; *pi = i; /*erro ! pi nao tem endereco valido*/ } voidmain () { int i=10, *pi = NULL; *pi = i; /*erro ! pi nao tem endereco valido*/ }

  38. Ponteiros e Strings • Quando imprimimos uma cadeia de caracteres constantes (string) com printf o que é passado é o ponteiro para a cadeia. Printf(“Ola como vai?”); • Dessa forma é possível carregar o endereço da string em um ponteiro do tipo charchar * lista;lista = "Ola como vai ?";printf("%s", lista );

  39. Ponteiros e Strings • Na verdade, strings são arrays de caracteres e podem ser acessados através de char * voidmain () { char str[]=“abcdef”, *pc; for (pc = str; *pc != ‘\0’; pc++) putchar(*pc); } ==> abcdef • o incremento de pc o posiciona sobre o próximo caracter (byte a byte)

  40. Ponteiros e Strings • Outra forma de mostrar uma string usando laço char *origem = "testando"; do{ printf("%c ", *origem); }while (*origem++); /* origem == \0 encerra o laco */ Primeiro retorna o conteúdo da posição apontada e depois incrementa a posição (precedência de operadores)

  41. Arrays Multidimensionais • Arrays podem ter diversas dimensões, cada uma identificada por um par de colchetes na declaração • Ex: char multi[5][10]; • declara um array de 5 linhas e 10 colunas: • na memória, entretanto, os caracteres são armazenados linearmente: [0,0] [4,9] [4,9] [1,9] [0,9] [0,0]

  42. Arrays Multidimensionais Percorrendo array com índices: void main () { char multi[5][10]; int lin, col; for (lin=0; lin<5; lin++) for (col =0; col<10; col++) multi[lin][col] = ‘‘; } as colunas (dimensões mais a direita) mudam mais rápido

  43. Arrays Multidimensionais • Percorrendoarray com ponteiro: void main () { char multi[5][10]; char *pc; inti; for (i=0, pc=multi[0]; i < 50; i++, pc++) *pc = ‘ ‘; } pc aponta para primeira posição do array Perceba a quantidade total de elementos

  44. Arrays Multidimensionais • Outra forma de visualizar char multi[5][10] O nome multi[5] é por si só um array indicando que existem 5 elementos, cada um deles sendo um array de 10 caracteres. multi[0] = {'0','1','2','3','4','5','6','7','8','9'} multi[1] = {'a','b','c','d','e','f','g','h','i','j'} multi[2] = {'A','B','C','D','E','F','G','H','I','J'} multi[3] = {'9','8','7','6','5','4','3','2','1','0'} multi[4] = {'J','I','H','G','F','E','D','C','B','A‘ • Como os arrays são contíguos na memória, nosso bloco de memória para o array acima pode ser algo do tipo: 0123456789abcdefghijABCDEFGHIJ9876543210JIHGFEDCBA inicio no endereço &multi[0][0]

  45. Arrays Multidimensionais multi[0] = {'0','1','2','3','4','5','6','7','8','9'} multi[1] = {'a','b','c','d','e','f','g','h','i','j'} multi[2] = {'A','B','C','D','E','F','G','H','I','J'} multi[3] = {'9','8','7','6','5','4','3','2','1','0'} multi[4] = {'J','I','H','G','F','E','D','C','B','A‘ • O compilador sabe quantas colunas estão presentes no array de forma que ele pode interpretar multi + 1 como o endereço do 'a' na segunda linha. Ou seja, ele acrescenta 10, o número de colunas, para obter sua posição • Assim, o endereço de 9 na quarta linha acima seria &multi[3][0] ou (multi + 3) em notação de ponteiro • Para obter o conteúdo do segundo elemento na quarta linha nós acrescentaríamos 1 a seu endereço e dereferenciaríamos o resultado como em *(*(multi + 3) + 1) • Com um pouco de raciocínio, podemos ver que: *(*(multi + lin) + col) e multi[lin][col] dão o mesmo resultado.

  46. Arrays Multidimensionais Outra forma de implementar o programa anterior int main( ){ char multi[5][10]; int lin, col; for (lin=0; lin < 5; lin++) for (col=0; col < 10; col++) *(*(multi + lin) + col) = 'A'; for (lin=0; lin < 5; lin++) for (col=0; col < 10; col++) printf("%c", *(*(multi + lin) + col) ); }

  47. Array de Strings • Neste caso, cada elemento do array é um ponteiro para um caracter • Declaração: char *arstr[] = {“Joao”, “Maria”, “Antonio”, “Zacarias”, “Carlos”}; • arstr é um array de ponteiros para char, iniciado com os strings indicados

  48. J o a o \0 M a r i a \0 A n t o n i o \0 Z a c a r i a s \0 C a r l o s \0 Array de Strings • Comparando array de string com array de char char *as[] = {“Joao”,“Maria”,“Antonio”,“Zacarias”,“Carlos”}; char ma[5][10] = {“Joao”,“Maria”,“Antonio”,“Zacarias”,“Carlos”}; Matriz (ma) Ponteiros (as)

  49. Cuidados com Strings • É comum esquecer de alocar uma área para armazenamento de caracteres void main() { char *pc; char str[] = “Um string”; strcpy(pc, str); /* erro! pc indeterminado */ ... }

  50. Ponteiros Genéricos • Um ponteiro genérico é um ponteiro que pode apontar para qualquer tipo de dado • Define-se um ponteiro genérico utilizando-se o tipo void: void *pv; int x=10; float f=3.5; pv = &x; /* aqui pv aponta para um inteiro */ pv = &f; /* aqui, para um float */

More Related