1 / 95

Capítulo IX – Ponteiros

Capítulo IX – Ponteiros. 9.1 – Introdução 9.2 – Relação entre ponteiros e variáveis indexadas 9.3 – Alocação dinâmica de memória 9.4 – Variáveis indexadas, ponteiros e estruturas como parâmetros e elementos de retorno 9.5 – Subprogramas como parâmetros 9.6 – Encadeamento de estruturas.

iman
Télécharger la présentation

Capítulo IX – Ponteiros

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. Capítulo IX – Ponteiros 9.1 – Introdução 9.2 – Relação entre ponteiros e variáveis indexadas 9.3 – Alocação dinâmica de memória 9.4 – Variáveis indexadas, ponteiros e estruturas como parâmetros e elementos de retorno 9.5 – Subprogramas como parâmetros 9.6 – Encadeamento de estruturas

  2. 9.3 – Alocação Dinâmica de Memória 9.3.1 – Dispositivos para alocação dinâmica • Muitas vezes é desejável reservar espaço para vetores e matrizes somente em tempo de execução • Exemplo: seja a seguinte declaração: int A[100][100];

  3. int A[100][100]; • Neste exemplo, supõe-se que o número de linhas e colunas de A devam ser lidos durante a execução desse programa • Caso eles sejam bem menores que 100, haverá grande desperdício de memória • Caso sejam maiores que 100, o espaço reservado não será suficiente para guardar os elementos de A • É conveniente alocar espaço para os elementos dessa variável depois de conhecidos os números de linhas e de colunas

  4. Na Linguagem C, a alocação de espaço em tempo de execução para vetores e matrizes só pode ser feita se esses forem declarados como ponteiros • Esse tipo de alocação denomina-se alocação dinâmica • Há uma região da memória ocupada pelo programa denominada heap, destinada a essas alocações dinâmicas

  5. A alocação pode ser feita pela função malloc do arquivo stdlib.h • malloc recebe como argumento o número de bytes a ser alocado • mallocentão reserva na heap esse número de bytes de forma contígua • O valor retornado por mallocé o endereço do primeiro desses bytes (um ponteiro) • Esses bytes ficam indisponíveis para novas alocações

  6. Exemplo: para alocar um vetor de 7 elementos do tipo int: int *V; V = (int *) malloc (7 * sizeof (int)); 28 bytes V int V pode ser usada como vetor 4 bytes A conversão (int *) é necessária pois malloc retorna um ponteiro do tipo void heap

  7. Tamanho dos vetores: 7 Vetor A: 28 39 84 27 82 49 10 Vetor B: 94 27 68 17 83 72 39 Vetor C: 94 39 84 27 83 72 39 Digite algo para encerrar: Exemplo: seja o programa à esquerda #include <stdio.h> #include <stdlib.h> typedef int *vetor; int main () { int m, i; vetor A, B, C; printf ("Tamanho dos vetores: "); scanf ("%d", &m); A = (int *) malloc (m*sizeof(int)); B = (int *) malloc (m*sizeof(int)); C = (int *) malloc (m*sizeof(int)); printf ("\nVetor A: "); for (i = 0; i < m; i++) scanf ("%d", &A[i]); printf ("\nVetor B: "); for (i = 0; i < m; i++) scanf ("%d", &B[i]); printf ("\nVetor C: "); for (i = 0; i < m; i++) C[i] = (A[i] > B[i])? A[i]: B[i]; for (i = 0; i < m; i++) printf ("%5d", C[i]); printf ("\n\n"); system ("pause"); return 0; } No vídeo

  8. O lay-out da área ocupada pelo programa é planejado pelo compilador • O gerenciamento durante a execução fica por conta do próprio programa • A área total reservada para o programa é fixa • As regiões das instruções e das variáveis globais também tem tamanho fixo

  9. As outras regiões tem tamanho variável durante a execução • A área de dados das funções destina-se a guardar os parâmetros, as variáveis locais e informações operacionais das versões ativas de funções num dado momento • Essa área varia de tamanho, pois essas versões de funções não ficam ativas o tempo todo

  10. Quando uma versão de função é chamada para execução, sua área de dados é carregada na memória • O carregamento é feito a partir da fronteira com a área desocupada • Quando sua execução é encerrada, sua área é retirada da memória, aumentando a área desocupada

  11. A área heap aumenta a partir de sua fronteira com a área desocupada • Isso acontece quando uma alocação dinâmica de memória é feita (mallocou outras do gênero) • A área de dados das funções aumenta para baixo e a heap aumenta para cima

  12. Nesse processo, se o programador não tomar cuidado, essas duas áreas podem se encontrar • Aí, esgota-se a capacidade da área desocupada • Novas chamadas de funções e novas alocações dinâmicas ficam impossibilitadas

  13. A função free torna a deixar disponível a área reservada numa alocação dinâmica • Seu parâmetro é um ponteiro • Ela re-disponibiliza a área previamente alocada e apontada por ele • Deve-se usar essa função toda vez que uma alocação não tiver mais utilidade para o programa

  14. Ver programa a seguir 9.3.2 – Alocação dinâmica de matrizes • Usa-se ponteiro para vetor de ponteiros:

  15. matriz é o tipo ponteiro para ponteiros de int A partir deste ponto, A pode ser usada como uma matriz comum #include <stdio.h> #include <stdlib.h> typedef int **matriz; int main () { int m, n, i, j; matriz A; printf ("Dimensoes de uma matriz: "); scanf ("%d%d", &m, &n); A = (int **) malloc (m * sizeof(int*)); for (i = 0; i < m; i++) A[i]= (int *) malloc (n * sizeof(int)); printf ("\nElementos da matriz:\n\n"); for (i = 0; i < m; i++) { printf ("\tLinha %d: ", i); for (j = 0; j < n; j++) scanf ("%d", &A[i][j]); } printf ("\nConfirmacao: \n\n"); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) printf ("%5d", A[i][j]); printf ("\n"); } printf ("\n\n"); system ("pause"); return 0; }

  16. Capítulo IX – Ponteiros 9.1 – Introdução 9.2 – Relação entre ponteiros e variáveis indexadas 9.3 – Alocação dinâmica de memória 9.4 – Variáveis indexadas, ponteiros e estruturas como parâmetros e elementos de retorno 9.5 – Subprogramas como parâmetros 9.6 – Encadeamento de estruturas

  17. 9.4 – Variáveis Indexadas, Ponteiros e Estruturas como Parâmetros e Elementos de Retorno 9.4.1 – Variáveis indexadas e ponteiros como parâmetros • Em C, quando um dos parâmetros de uma função for declarado como variável indexada, na realidade ele será um ponteiro

  18. Caso o argumento correspondente seja o nome de uma variável indexada: • O endereço correspondente aos seu nome é passado ao ponteiro-parâmetro • Os elementos da variável-argumento não são copiados para a função • Então essa passagem de argumento é por referência • Toda alteração nos elementos da variável-parâmetro terá efeito sobre aqueles da variável-argumento • Outros possíveis argumentos: ponteiros e endereços

  19. Exemplo: seja o programa à esquerda #include <stdio.h> #include <stdlib.h> void Alterar (int B[]) { B[1] = B[3] = 7; } int main () { int i, A[10] = {0}; printf ("Vetor inicial : "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); Alterar (A); printf ("\n\nVetorintermediario: "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); Alterar (&A[4]); printf ("\n\nVetor final : "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); printf ("\n\n"); system ("pause"); return 0; } O parâmetro B de Alterar é um ponteiro Não é necessário colocar a dimensão Poderia ser int *B

  20. B #include <stdio.h> #include <stdlib.h> void Alterar (int B[]) { B[1] = B[3] = 7; } int main () { int i, A[10] = {0}; printf ("Vetor inicial : "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); Alterar (A); printf ("\n\nVetorintermediario: "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); Alterar (&A[4]); printf ("\n\nVetor final : "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); printf ("\n\n"); system ("pause"); return 0; } 0 0 7 0 7 0 0 7 0 0 7 0 0 0 B[0] B[1] B[2] B[3] B[4] B[0] B[1] B[5] B[2] B[6] B[3] B[7] B[4] B[8] B[5] B[9] A A[3] A[4] A[5] A[6] A[0] A[2] A[1] A[7] A[9] A[8]

  21. Vetor inicial : 0 0 0 0 0 0 0 0 0 0 Vetor intermediario: 0 7 0 7 0 0 0 0 0 0 Vetor final : 0 7 0 7 0 7 0 7 0 0 Pressione ... #include <stdio.h> #include <stdlib.h> void Alterar (int B[]) { B[1] = B[3] = 7; } int main () { int i, A[10] = {0}; printf ("Vetor inicial : "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); Alterar (A); printf ("\n\nVetorintermediario: "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); Alterar (&A[4]); printf ("\n\nVetor final : "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); printf ("\n\n"); system ("pause"); return 0; } Resultado

  22. #include <stdio.h> #include <stdlib.h> voidImprimirMatriz (int V[][10], int x, int y) { int i, j; printf ("Endereco(V) = %d; Conteudo(V) = %d;\n\n", &V, V); printf ("Endereco(V[0][0]) = %d\n\n", &V[0][0]); for (i = 0; i < x; i++) { for (j = 0; j < y; j++) { printf ("%5d", V[i][j]); } printf ("\n"); } } int main () { int A[10][10], i, j, m = 5, n = 7; printf ("A = %d\n\n", A); printf ("Endereco(A[0][0]) = %d\n\n", &A[0][0]); for (i = 0; i < m; i++) for (j = 0; j < n; j++) A[i][j] = (i+1)*(j+1); ImprimirMatriz (A, m, n); getch (); } Exemplo com matriz bidimensional

  23. #include <stdio.h> #include <stdlib.h> voidImprimirMatriz (int V[][10], int x, int y) { int i, j; printf ("Endereco(V) = %d; Conteudo(V) = %d;\n\n", &V, V); printf ("Endereco(V[0][0]) = %d\n\n", &V[0][0]); for (i = 0; i < x; i++) { for (j = 0; j < y; j++) { printf ("%5d", V[i][j]); } printf ("\n"); } } int main () { int A[10][10], i, j, m = 5, n = 7; printf ("A = %d\n\n", A); printf ("Endereco(A[0][0]) = %d\n\n", &A[0][0]); for (i = 0; i < m; i++) for (j = 0; j < n; j++) A[i][j] = (i+1)*(j+1); ImprimirMatriz (A, m, n); getch (); } No parâmetro V, a 1ª dimensão é dispensada Resultado

  24. #include <stdio.h> #include <stdlib.h> voidImprimirMatriz (int V[][10], int x, int y) { int i, j; printf ("Endereco(V) = %d; Conteudo(V) = %d;\n\n", &V, V); printf ("Endereco(V[0][0]) = %d\n\n", &V[0][0]); for (i = 0; i < x; i++) { for (j = 0; j < y; j++) { printf ("%5d", V[i][j]); } printf ("\n"); } } int main () { int A[10][10], i, j, m = 5, n = 7; printf ("A = %d\n\n", A); printf ("Endereco(A[0][0]) = %d\n\n", &A[0][0]); for (i = 0; i < m; i++) for (j = 0; j < n; j++) { A[i][j] = (i+1)*(j+1); } ImprimirMatriz (A, m, n); printf ("\n\n"); system ("pause"); return 0; } V A A[0][0] Resultado

  25. Exemplo: Fusão de 2 vetores ordenados • O programa a seguir realiza as seguintes operações: • Lê os dados sobre os dois vetores • Ordena-os pelo Bubble-Sort • Funde os dois vetores pelo método Merge-Sort, obtendo um terceiro vetor ordenado • O método Merge-Sort apresentado só funciona quando os 2 vetores já estão ordenados

  26. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; j i k 3 5 8 8 11 13 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 V3

  27. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; j k i 3 3 5 8 8 11 13 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 V3

  28. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; j k i 3 3 4 5 8 8 11 13 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 V3

  29. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; k j i 3 3 4 5 5 8 8 11 13 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 V3

  30. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; k j i 3 3 4 5 5 8 5 8 11 13 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 V3

  31. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; k j i 3 3 4 5 5 8 5 8 11 6 13 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 V3

  32. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; k j i 3 3 4 5 5 8 5 8 11 6 7 13 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 V3

  33. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; j i k 3 3 4 5 5 8 5 8 11 6 13 7 8 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 V3

  34. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; j i k 3 3 4 5 5 8 5 8 6 11 7 13 16 8 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 8 V3

  35. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; j i k 3 3 4 5 5 8 5 8 11 6 7 13 8 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 8 8 V3

  36. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; j i k 3 3 4 5 5 8 5 8 11 6 7 13 8 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 8 8 9 V3

  37. V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; j i k 3 3 4 5 5 8 8 5 6 11 13 7 8 16 V1 O Método Merge-Sort: 4 5 6 7 8 9 V2 8 8 9 11 13 16 V3 A seguir, o programa

  38. O tipo dos parâmetros dos protótipos devem ser os mesmos nas definições das funções /* Declaracoesglobais */ #include <stdio.h> #include <stdlib.h> typedef char logic; const logic TRUE = 1, FALSE = 0; typedef int vetor[20]; /* Prototipos das funcoesauxiliares */ void LerVetor (vetor, int*); void EscreverVetor (vetor, int); void BubbleSort (vetor, int); void MergeSort (vetor, vetor, vetor, int, int, int*);

  39. V1, V2 e V3 são variáveis indexadas int main () { int m, n, p; vetor V1, V2, V3; printf ("FUSAO DE DOIS VETORES ORDENADOS"); /* Leitura dos dois vetores */ printf ("\n\nLeitura do vetor V1: \n"); LerVetor (V1, &m); printf ("\nLeitura do vetor V2: \n"); LerVetor (V2, &n); /* Escrita dos dois vetores lidos */ printf ("\n\nVetor V1 inicial: \n\n"); EscreverVetor (V1, m); printf ("\n\nVetor V2 inicial: \n\n"); EscreverVetor (V2, n); Passagem de V1, V2, m e n: por referência Eles serão alterados pela função LerVetor Passagem de V1 e V2 : por referência Os elementos não precisam ser copiados para a função

  40. Passagem de V1 e V2: por referência Eles serão alterados pela função BubbleSort /* Ordenacao e escrita dos dois vetores ordenados */ BubbleSort (V1, m); BubbleSort (V2, n); printf ("\n\nVetor V1 ordenado: \n\n"); EscreverVetor (V1, m); printf ("\n\nVetor V2 ordenado: \n\n"); EscreverVetor (V2, n); /* Fusao dos dois vetores num terceiro */ MergeSort (V1, V2, V3, m, n, &p); Passagem de V3 e p: por referência Eles serão alterados pela função MergeSort Passagem de V1 e V2: por referência Os elementos não precisam ser copiados para a função

  41. /* Escrita do vetor resultado da fusao */ printf ("\n\nFusao V3 dos vetores V1 e V2:\n\n"); EscreverVetor (V3, p); /* Fechamento da tela */ printf ("\n\n"); system ("pause"); return 0; }

  42. Na função main: LerVetor (V1, &m); LerVetor (V2, &n); /* FuncaoLerVetor para ler os elementos de um vetor */ voidLerVetor (vetor V, int *n) { int i; printf ("\n\tNumero de elementos: "); scanf ("%d", n); printf ("\n\tSeus %d elementos: ", *n); for (i = 0; i <= *n-1; i++) scanf ("%d", &V[i]); } /* FuncaoEscreverVetor para escrever os elementos de um vetor */ voidEscreverVetor (vetor V, int n) { int i; for (i = 0; i <= n-1; i++) printf ("%4d", V[i]); } Não é &n, pois n já é o endereço alvo Local apontado por n V[i] coincide com os elementos V1[i] e V2[i] dos argumentos V1 e V2

  43. Na função main: BubbleSort (V1, m); BubbleSort (V2, n); /* FuncaoBubbleSort para ordenar os elementos de um vetor */ voidBubbleSort (vetor V, int n) { int i, p, aux; logic trocou; p = n-2; trocou = TRUE; while (p>=0 && trocou) { trocou = FALSE; i = 0; while (i <= p) { if (V[i] > V[i+1]) { aux = V[i]; V[i] = V[i+1]; V[i+1] = aux; trocou = TRUE; } i = i+1; } p = p-1; } } V[i] e V[i+1] coincidem com os elementos correspondentes dos argumentos V1 e V2

  44. Percurso em V1 ou V2 acabou Na função main: MergeSort (V1, V2, V3, m, n, &p); /* FuncaoMergeSort para fundir dois vetores ordenados num terceiro tambem ordenado */ voidMergeSort (vetor V1, vetor V2, vetor V3, int m, int n, int *p) { int i, j, k; *p = m + n; for (i = j = k = 0; i < m && j < n; k++) if (V1[i] < V2[j]) { V3[k] = V1[i]; i++; } else { V3[k] = V2[j]; j++; } for (; i < m; i++, k++) V3[k] = V1[i]; for (; j < n; j++, k++) V3[k] = V2[j]; } O tamanho do vetor final é calculado pela MergeSort Percurso em V1 e V2 ainda não acabou

  45. 9.4.2 – Variáveis indexadas e ponteiros como valores retornados • Quando se deseja produzir uma variável indexada dentro de uma função e retornar seus elementos, deve-se usar um ponteiro • O programa a seguir faz alocação dinâmica de uma matriz dentro de uma função auxiliar • As dimensões são passadas por referência e lidas na própria função • O ponteiro para os elementos da matriz é o valor de retorno

  46. #include <stdio.h> #include <stdlib.h> typedef int **matriz; matrizLerMatriz (int*, int*); void EscreverMatriz (matriz, int, int); int main () { int m, n; matriz A; printf ("Leituradamatriz A\n\n"); A = LerMatriz (&m, &n); printf ("\nMatriz A lida:\n\n"); EscreverMatriz (A, m, n); printf ("\n\n"); system ("pause"); return 0; } O valor retornado de LerMatriz é atribuído a A

  47. Na função main: A = LerMatriz (&m, &n); matrizLerMatriz (int *nlin, int *ncol) { matrizMatRetorno; int i, j; printf ("Digite as 2 dimensoes: "); scanf ("%d%d", nlin, ncol); MatRetorno = (int **) malloc (*nlin * sizeof(int*)); for (i = 0; i < *nlin; i++) MatRetorno[i]= (int *) malloc (*ncol * sizeof(int)); printf ("\nDigiteoselementosdamatriz\n\n"); for (i = 0; i < *nlin; i++) { printf ("\tLinha %d: ", i); for (j = 0; j < *ncol; j++) scanf ("%d", &MatRetorno[i][j]); } return MatRetorno; } Alocação do vetor de ponteiros O valor retornado é um ponteiro

  48. void EscreverMatriz (matriz Mat, int m, int n) { int i, j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) printf ("%5d", Mat[i][j]); printf ("\n"); } } Na função main: EscreverMatriz (A, m, n);

  49. 9.4.3 – Estruturas como parâmetros e valores retornados • Em C, estruturas podem ser declaradas como parâmetros, passadas como argumentospor valor e por referência e seus valores podem ser retornados de funções • Na passagem de argumento por valor e no retorno de uma função, há uma cópia de toda a estrutura, de um módulo para outro • O programa a seguir realiza operações com números complexos • É usada uma estrutura com a parte real e a parte imaginária de um complexo

  50. #include <stdio.h> #include <conio.h> #include <conio2.h> #include <stdlib.h> #include <math.h> structcomplexo {float real, imag;}; typedefstructcomplexocomplexo; void WriteMenu (void); complexo Soma (complexo, complexo); complexoSubtracao (complexo, complexo); complexoMultiplicacao (complexo, complexo); complexoDivisao (complexo, complexo); Nas funções para operações com complexo, todos os parâmetros e os valores retornados são estruturas

More Related