Carregar apresentação
A apresentação está carregando. Por favor, espere
PublicouRayssa Serpa Alterado mais de 10 anos atrás
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 Muitas vezes é desejável reservar espaço para vetores e matrizes somente em tempo de execução Exemplo: seja a seguinte declaração: Exemplo: seja a seguinte declaração: int A[100][100];
3
Neste exemplo, supõe-se que o número de linhas e colunas de A devam ser lidos durante a execução desse programa 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 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 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 É 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 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 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 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 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 malloc recebe como argumento o número de bytes a ser alocado malloc então reserva na heap esse número de bytes de forma contígua malloc entã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) O valor retornado por malloc é o endereço do primeiro desses bytes (um ponteiro) Esses bytes ficam indisponíveis para novas alocações Esses bytes ficam indisponíveis para novas alocações
6
Exemplo: para alocar um vetor de 7 elementos do tipo int: Exemplo: para alocar um vetor de 7 elementos do tipo int: int *V; V = (int *) malloc (7 * sizeof (int)); heap V A conversão (int *) é necessária pois malloc retorna um ponteiro do tipo void int 4 bytes 28 bytes V pode ser usada como vetor
7
#include #include typedef int *vetor; void 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\nDigite algo para encerrar: "); getch (); printf ("\n\nDigite algo para encerrar: "); getch ();} Exemplo: seja o programa à esquerda 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: No vídeo
8
O lay-out da área ocupada pelo programa é planejado pelo compilador O lay-out da área ocupada pelo programa é planejado pelo compilador O gerenciamento durante a execução fica por conta do próprio programa O gerenciamento durante a execução fica por conta do próprio programa A área total reservada para o programa é fixa A área total reservada para o programa é fixa As regiões das instruções e das variáveis globais também tem tamanho fixo 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 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 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 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 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 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 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 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 (malloc ou outras do gênero) Isso acontece quando uma alocação dinâmica de memória é feita (malloc ou outras do gênero) A área de dados das funções aumenta para baixo e a heap aumenta para cima 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 Nesse processo, se o programador não tomar cuidado, essas duas áreas podem se encontrar Aí, esgota-se a capacidade da área desocupada Aí, esgota-se a capacidade da área desocupada Novas chamadas de funções e novas alocações dinâmicas ficam impossibilitadas 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 A função free torna a deixar disponível a área reservada numa alocação dinâmica Seu parâmetro é um ponteiro Seu parâmetro é um ponteiro Ela re-disponibiliza a área previamente alocada e apontada por ele 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 Deve-se usar essa função toda vez que uma alocação não tiver mais utilidade para o programa
14
9.3.2 – Alocação dinâmica de matrizes Usa-se ponteiro para vetor de ponteiros: Usa-se ponteiro para vetor de ponteiros: Ver programa a seguir
15
#include #include typedef int **matriz; void 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\nDigite algo para encerrar: "); getch (); printf ("\n\nDigite algo para encerrar: "); getch ();} matriz é o tipo ponteiro para ponteiros de int A partir deste ponto, A pode ser usada como uma matriz comum
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 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: Caso o argumento correspondente seja o nome de uma variável indexada: O endereço correspondente aos seu nome é passado ao ponteiro-parâmetro 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 Os elementos da variável-argumento não são copiados para a função Então essa passagem de argumento é por referência 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 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 Outros possíveis argumentos: ponteiros e endereços
19
#include #include void Alterar (int B[]) { B[1] = B[3] = 7; } void main () { int i, A[10] = {0}; printf ("Vetor inicial : "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); Alterar (A); printf ("\n\nVetor intermediario: "); 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\nDigite algo para encerrar: "); getch (); printf ("\n\nDigite algo para encerrar: "); getch ();} Exemplo: seja o programa à esquerda O parâmetro B de Alterar é um ponteiro Não é necessário colocar a dimensão Poderia ser int *B
20
#include #include void Alterar (int B[]) { B[1] = B[3] = 7; } void main () { int i, A[10] = {0}; printf ("Vetor inicial : "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); Alterar (A); printf ("\n\nVetor intermediario: "); 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\nDigite algo para encerrar: "); getch (); printf ("\n\nDigite algo para encerrar: "); getch ();} A A[0]A[1]A[2]A[3]A[4]A[5]A[6]A[7]A[8]A[9] 0000000000 B B[0]B[1]B[2]B[3]B[4]B[5]B[6]B[7]B[8]B[9] 77 B[0]B[1]B[2]B[3]B[4]B[5] 77
21
#include #include void Alterar (int B[]) { B[1] = B[3] = 7; } void main () { int i, A[10] = {0}; printf ("Vetor inicial : "); for (i = 0; i <= 9; i++) printf ("%3d", A[i]); Alterar (A); printf ("\n\nVetor intermediario: "); 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\nDigite algo para encerrar: "); getch (); printf ("\n\nDigite algo para encerrar: "); getch ();} 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 Digite algo para encerrar: Resultado
22
#include #include void ImprimirMatriz (int V[][10], int x, int y) { int i, j; int i, j; printf ("Endereco(V) = %d; Conteudo(V) = %d;\n\n", &V, V); printf ("Endereco(V) = %d; Conteudo(V) = %d;\n\n", &V, V); printf ("Endereco(V[0][0]) = %d\n\n", &V[0][0]); printf ("Endereco(V[0][0]) = %d\n\n", &V[0][0]); for (i = 0; i < x; i++) { for (i = 0; i < x; i++) { for (j = 0; j < y; j++) { for (j = 0; j < y; j++) { printf ("%5d", V[i][j]); printf ("%5d", V[i][j]); } printf ("\n"); printf ("\n"); }} void 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]); printf ("Endereco(A[0][0]) = %d\n\n", &A[0][0]); for (i = 0; i < m; i++) for (i = 0; i < m; i++) for (j = 0; j < n; j++) for (j = 0; j < n; j++) A[i][j] = (i+1)*(j+1); A[i][j] = (i+1)*(j+1); ImprimirMatriz (A, m, n); getch (); } Exemplo com matriz bidimensional
23
#include #include void ImprimirMatriz (int V[][10], int x, int y) { int i, j; int i, j; printf ("Endereco(V) = %d; Conteudo(V) = %d;\n\n", &V, V); printf ("Endereco(V) = %d; Conteudo(V) = %d;\n\n", &V, V); printf ("Endereco(V[0][0]) = %d\n\n", &V[0][0]); printf ("Endereco(V[0][0]) = %d\n\n", &V[0][0]); for (i = 0; i < x; i++) { for (i = 0; i < x; i++) { for (j = 0; j < y; j++) { for (j = 0; j < y; j++) { printf ("%5d", V[i][j]); printf ("%5d", V[i][j]); } printf ("\n"); printf ("\n"); }} void 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]); printf ("Endereco(A[0][0]) = %d\n\n", &A[0][0]); for (i = 0; i < m; i++) for (i = 0; i < m; i++) for (j = 0; j < n; j++) for (j = 0; j < n; j++) A[i][j] = (i+1)*(j+1); A[i][j] = (i+1)*(j+1); ImprimirMatriz (A, m, n); getch (); } No parâmetro V, a 1ª dimensão é dispensada Resultado
24
#include #include void ImprimirMatriz (int V[][10], int x, int y) { int i, j; int i, j; printf ("Endereco(V) = %d; Conteudo(V) = %d;\n\n", &V, V); printf ("Endereco(V) = %d; Conteudo(V) = %d;\n\n", &V, V); printf ("Endereco(V[0][0]) = %d\n\n", &V[0][0]); printf ("Endereco(V[0][0]) = %d\n\n", &V[0][0]); for (i = 0; i < x; i++) { for (i = 0; i < x; i++) { for (j = 0; j < y; j++) { for (j = 0; j < y; j++) { printf ("%5d", V[i][j]); printf ("%5d", V[i][j]); } printf ("\n"); printf ("\n"); }} void 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]); printf ("Endereco(A[0][0]) = %d\n\n", &A[0][0]); for (i = 0; i < m; i++) for (i = 0; i < m; i++) for (j = 0; j < n; j++) { for (j = 0; j < n; j++) { A[i][j] = (i+1)*(j+1); A[i][j] = (i+1)*(j+1); } ImprimirMatriz (A, m, n); ImprimirMatriz (A, m, n); getch (); } Resultado A A[0][0] V
25
Exemplo: Fusão de 2 vetores ordenados O programa a seguir realiza as seguintes operações: O programa a seguir realiza as seguintes operações: Lê os dados sobre os dois vetores Lê os dados sobre os dois vetores Ordena-os pelo Bubble-Sort Ordena-os pelo Bubble-Sort Funde os dois vetores pelo método Merge-Sort, obtendo um terceiro vetor ordenado 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 O método Merge-Sort apresentado só funciona quando os 2 vetores já estão ordenados
26
O Método Merge-Sort: 3588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
27
O Método Merge-Sort: 33588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
28
O Método Merge-Sort: 343588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
29
O Método Merge-Sort: 3453588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
30
O Método Merge-Sort: 34553588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
31
O Método Merge-Sort: 345563588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
32
O Método Merge-Sort: 3455673588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
33
O Método Merge-Sort: 34556783588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
34
O Método Merge-Sort: 345567883588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
35
O Método Merge-Sort: 3455678883588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
36
O Método Merge-Sort: 34556788893588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j];
37
O Método Merge-Sort: 34556788891113163588111316456789 V1 V2 V3 i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; A seguir, o programa
38
/*Declaracoes globais */ #include #include typedef char logic; const logic TRUE = 1, FALSE = 0; typedef int vetor[20]; /*Prototipos das funcoes auxiliares*/ void LerVetor (vetor, int*); void EscreverVetor (vetor, int); void BubbleSort (vetor, int); void MergeSort (vetor, vetor, vetor, int, int, int*); O tipo dos parâmetros dos protótipos devem ser os mesmos nas definições das funções
39
void main () { int m, n, p; vetor V1, V2, V3; printf ("FUSAO DE DOIS VETORES ORDENADOS"); printf ("FUSAO DE DOIS VETORES ORDENADOS"); /*Leitura dos dois vetores*/ printf ("\n\nLeitura do vetor V1: \n"); LerVetor (V1, &m); LerVetor (V1, &m); printf ("\nLeitura do vetor V2: \n"); LerVetor (V2, &n); LerVetor (V2, &n); /*Escrita dos dois vetores lidos*/ printf ("\n\nVetor V1 inicial: \n\n"); printf ("\n\nVetor V1 inicial: \n\n"); EscreverVetor (V1, m); printf ("\n\nVetor V2 inicial: \n\n"); printf ("\n\nVetor V2 inicial: \n\n"); EscreverVetor (V2, n); V1, V2 e V3 são variáveis indexadas 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
/*Ordenacao e escrita dos dois vetores ordenados */ BubbleSort (V1, m); BubbleSort (V2, n); printf ("\n\nVetor V1 ordenado: \n\n"); printf ("\n\nVetor V1 ordenado: \n\n"); EscreverVetor (V1, m); printf ("\n\nVetor V2 ordenado: \n\n"); 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 V1 e V2: por referência Eles serão alterados pela função BubbleSort Passagem de V1 e V2: por referência Os elementos não precisam ser copiados para a função Passagem de V3 e p: por referência Eles serão alterados pela função MergeSort
41
/*Escrita do vetor resultado da fusao */ printf ("\n\nFusao V3 dos vetores V1 e V2:\n\n"); printf ("\n\nFusao V3 dos vetores V1 e V2:\n\n"); EscreverVetor (V3, p); /*Fechamento da tela */ printf ("\n\nDigite algo para encerrar: "); getch (); getch ();}
42
/*Funcao LerVetor para ler os elementos de um vetor */ void LerVetor (vetor V, int *n) { int i; 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]); } /*Funcao EscreverVetor para escrever os elementos de um vetor */ void EscreverVetor (vetor V, int n) { int i; for (i = 0; i <= n-1; i++) printf ("%4d", V[i]); } Na função main: LerVetor (V1, &m); LerVetor (V2, &n); 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
/*Funcao BubbleSort para ordenar os elementos de um vetor */ void BubbleSort (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 Na função main: BubbleSort (V1, m); BubbleSort (V2, n);
44
/*Funcao MergeSort para fundir dois vetores ordenados num terceiro tambem ordenado*/ void MergeSort (vetor V1, vetor V2, vetor V3, int m, int n, int *p) { int i, j, k; *p = m + n; *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]; } Na função main: MergeSort (V1, V2, V3, m, n, &p); O tamanho do vetor final é calculado pela MergeSort Percurso em V1 e V2 ainda não acabou Percurso em V1 ou V2 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 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 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 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 O ponteiro para os elementos da matriz é o valor de retorno
46
#include #include typedef int **matriz; matriz LerMatriz (int*, int*); void EscreverMatriz (matriz, int, int); void main () { int m, n; matriz A; printf ("Leitura da matriz A\n\n"); A = LerMatriz (&m, &n); A = LerMatriz (&m, &n); printf ("\nMatriz A lida:\n\n"); EscreverMatriz (A, m, n); EscreverMatriz (A, m, n); printf ("\n\nDigite algo para encerrar: "); printf ("\n\nDigite algo para encerrar: "); getch (); getch ();} O valor retornado de LerMatriz é atribuído a A
47
matriz LerMatriz (int *nlin, int *ncol) { matriz MatRetorno; int i, j; printf ("Digite as 2 dimensoes: "); 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 ("\nDigite os elementos da matriz\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; return MatRetorno;} Na função main: A = LerMatriz (&m, &n); 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 argumentos por valor e por referência e seus valores podem ser retornados de funções Em C, estruturas podem ser declaradas como parâmetros, passadas como argumentos por 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 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 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 É usada uma estrutura com a parte real e a parte imaginária de um complexo
50
#include #include struct complexo {float real, imag;}; typedef struct complexo complexo; void WriteMenu (void); complexo Soma (complexo, complexo); complexo Subtracao (complexo, complexo); complexo Multiplicacao (complexo, complexo); complexo Divisao (complexo, complexo); Nas funções para operações com complexo, todos os parâmetros e os valores retornados são estruturas
51
void main () { complexo a, b, r; char c; WriteMenu (); c = getche (); clrscr (); while (c != '0') { switch (c) { switch (c) { case '1': case '1': printf ("Soma de complexos\n\n"); printf ("Soma de complexos\n\n"); printf ("\tDigite os dois operandos: "); printf ("\tDigite os dois operandos: "); scanf ("%f%f%f%f", &a.real, &a.imag, &b.real, &b.imag); scanf ("%f%f%f%f", &a.real, &a.imag, &b.real, &b.imag); r = Soma (a, b); r = Soma (a, b); printf ("\n[(%g)+j(%g)] + [(%g)+j(%g)] = [(%g)+j(%g)]", printf ("\n[(%g)+j(%g)] + [(%g)+j(%g)] = [(%g)+j(%g)]", a.real, a.imag, b.real, b.imag, r.real, r.imag); a.real, a.imag, b.real, b.imag, r.real, r.imag); break; break;
52
case '2': case '2': printf ("Subtracao de complexos\n\n"); printf ("Subtracao de complexos\n\n"); printf ("\tDigite os dois operandos: "); printf ("\tDigite os dois operandos: "); scanf ("%f%f%f%f", &a.real, &a.imag, &b.real, &b.imag); scanf ("%f%f%f%f", &a.real, &a.imag, &b.real, &b.imag); r = Subtracao (a, b); r = Subtracao (a, b); printf ("\n[(%g)+j(%g)] - [(%g)+j(%g)] = [(%g)+j(%g)]", printf ("\n[(%g)+j(%g)] - [(%g)+j(%g)] = [(%g)+j(%g)]", a.real, a.imag, b.real, b.imag, r.real, r.imag); a.real, a.imag, b.real, b.imag, r.real, r.imag); break; break; case '3': case '3': printf ("Multiplicacao de complexos\n\n"); printf ("Multiplicacao de complexos\n\n"); printf ("\tDigite os dois operandos: "); printf ("\tDigite os dois operandos: "); scanf ("%f%f%f%f", &a.real, &a.imag, &b.real, &b.imag); scanf ("%f%f%f%f", &a.real, &a.imag, &b.real, &b.imag); r = Multiplicacao (a, b); r = Multiplicacao (a, b); printf ("\n[(%g)+j(%g)] * [(%g)+j(%g)] = [(%g)+j(%g)]", printf ("\n[(%g)+j(%g)] * [(%g)+j(%g)] = [(%g)+j(%g)]", a.real, a.imag, b.real, b.imag, r.real, r.imag); a.real, a.imag, b.real, b.imag, r.real, r.imag); break; break;
53
case '4': case '4': printf ("Divisao de complexos\n\n"); printf ("Divisao de complexos\n\n"); printf("\tDigite os dois operandos: "); printf("\tDigite os dois operandos: "); scanf ("%f%f%f%f", &a.real, &a.imag, &b.real, &b.imag); scanf ("%f%f%f%f", &a.real, &a.imag, &b.real, &b.imag); if (b.real == 0 && b.imag == 0) if (b.real == 0 && b.imag == 0) printf ("\nO divisor eh zero!!!"); printf ("\nO divisor eh zero!!!"); else { else { r = Divisao (a, b); r = Divisao (a, b); printf("\n[(%g)+j(%g)] / [(%g)+j(%g)] = [(%g)+j(%g)]", printf("\n[(%g)+j(%g)] / [(%g)+j(%g)] = [(%g)+j(%g)]", a.real, a.imag, b.real, b.imag, r.real, r.imag); a.real, a.imag, b.real, b.imag, r.real, r.imag); } break; break; default: default: printf ("Operacao invalida!!!"); printf ("Operacao invalida!!!"); } printf ("\n\nDigite algo para continuar"); getch (); printf ("\n\nDigite algo para continuar"); getch (); WriteMenu (); c = getche (); clrscr (); WriteMenu (); c = getche (); clrscr ();} printf ("Fim das operacoes!!!\n\nDigite algo: "); printf ("Fim das operacoes!!!\n\nDigite algo: "); getch(); getch();}
54
void WriteMenu () { clrscr (); printf ("OPERACOES COM NUMEROS COMPLEXOS\n\n"); printf ("\n\t1 - Soma"); printf ("\n\t2 - Subtracao"); printf ("\n\t3 - Multiplicacao"); printf ("\n\t4 - Divisao"); printf ("\n\nDigite a operacao desejada (Zero para encerrar): "); } complexo Soma (complexo a, complexo b) { complexo r; r.real = a.real + b.real; r.imag = a.imag + b.imag; return r; } complexo Subtracao (complexo a, complexo b) { complexo r; r.real = a.real - b.real; r.imag = a.imag - b.imag; return r; }
55
complexo Multiplicacao (complexo a, complexo b) { complexo r; r.real = a.real*b.real - a.imag*b.imag; r.imag = a.real*b.imag + a.imag*b.real; return r ; } complexo Divisao (complexo a, complexo b) { complexo r; float denominador; denominador = pow (b.real, 2) + pow (b.imag, 2); r.real = (a.real*b.real + a.imag*b.imag) / denominador; r.imag = (a.imag*b.real - a.real*b.imag) / denominador; r.imag = (a.imag*b.real - a.real*b.imag) / denominador; return r ; }
56
Como já foi visto, não é possível passar como argumentos por valor nem como valores a serem retornados de uma função todos os elementos de uma variável indexada Como já foi visto, não é possível passar como argumentos por valor nem como valores a serem retornados de uma função todos os elementos de uma variável indexada Se você não pode passar um elefante por debaixo de uma porta, coloque-o dentro de um envelope e passe-o Se você não pode passar um elefante por debaixo de uma porta, coloque-o dentro de um envelope e passe-o Se você não pode passar uma variável indexada como argumento por valor ou como valor de retorno de uma função, coloque-o dentro de uma estrutura e passe-o Se você não pode passar uma variável indexada como argumento por valor ou como valor de retorno de uma função, coloque-o dentro de uma estrutura e passe-o A seguir, um programa para elevar uma matriz a um expoente A seguir, um programa para elevar uma matriz a um expoente Ele invoca uma função para multiplicar duas matrizes Ele invoca uma função para multiplicar duas matrizes
57
/*Declaracoes globais */ #include #include typedef struct matriz matriz; struct matriz { int nlin, ncol; int elem[10][10]; }; /*Prototipos das funcoes auxiliares*/ void LerMatrizQuadrada (matriz *); void EscreverMatriz (matriz Mat); matriz MultMat (matriz, matriz);
58
void main () { int p, i, j, k; matriz M, Mpot; printf ("POTENCIACAO DE MATRIZ\n\n"); /*Leitura do expoente */ printf ("Digite o expoente: "); scanf ("%d", &p); while (p < 0) { printf ("\tExpoente < 0; Digite novamente: "); scanf ("%d", &p); } /*Leitura e escrita da matriz base*/ printf ("\nLeitura da matriz base: \n"); LerMatrizQuadrada (&M); printf ("\nMatriz lida: \n\n"); EscreverMatriz (M); printf ("\nExpoente de potenciacao: %d\n", p); O argumento é o endereço de uma estrutura
59
/*Inicializacao da matriz potencia com a matriz identidade */ Mpot.nlin = Mpot.ncol = M.nlin; for (i = 1; i <= Mpot.nlin; i++) for (j = 1; j <= Mpot.ncol; j++) Mpot.elem[i][j] = (i == j) ? 1 : 0; /* Calculo da matriz potencia*/ for (k = 1; k <= p; k++) Mpot = MultMat (Mpot, M); /* Escrita da matriz potencia*/ printf ("\nMatriz potencia: \n\n"); EscreverMatriz (Mpot); printf ("\n\nDigite algo para encerrar: "); printf ("\n\nDigite algo para encerrar: "); getch (); } Os argumentos e o valor retornado são estruturas
60
/*Funcao LerMatrizQuadrada: ler a matriz argumento pelo teclado*/ void LerMatrizQuadrada (matriz *Mat){ int i, j, n; printf ("\nDigite a dimensao da matriz: "); scanf ("%d", &n); while (n <= 0) { printf ("\tDimensao < 1; Digite novamente: "); scanf ("%d", &n); } (*Mat).ncol = (*Mat).nlin = n; for (i = 1; i <= (*Mat).nlin; i++) { printf ("\tLinha %d: ", i); for (j = 1; j <= (*Mat).ncol; j++) scanf ("%d", &(*Mat).elem[i][j]); }} Na função main: LerMatrizQuadrada (&M); Mat é um ponteiro para estrutura *Mat é uma estrutura
61
/*Funcao EscreverMatriz: escrever a matriz argumento no video*/ void EscreverMatriz (matriz Mat) { int i, j; for (i = 1; i <= Mat.nlin; i++) { for (j = 1; j <= Mat.ncol; j++) printf ("%10d", Mat.elem[i][j]); printf ("\n"); }} Na função main: EscreverMatriz (M); EscreverMatriz (Mpot);
62
matriz MultMat (matriz M1, matriz M2) { int i, j, k, aux; matriz M3; M3.nlin = M1.nlin; M3.ncol = M2.ncol; if (M1.ncol == M2.nlin) { for (i = 1; i <= M3.nlin; i++) for (j = 1; j <= M3.ncol; j++) { aux = 0; for (k = 1; k <= M1.ncol; k++) aux += M1.elem[i][k]*M2.elem[k][j]; M3.elem[i][j] = aux; M3.elem[i][j] = aux;}}else for (i = 1; i <= M3.nlin; i++) for (j = 1; j <= M3.ncol; j++) M3.elem[i][j] = 0; return M3; } Na função main: Mpot = MultMat (Mpot, M);
63
9.4.4 – Recursividade com variáveis indexadas Exemplo: formulação recursiva para a procura binária Exemplo: formulação recursiva para a procura binária ProcBinaria (x, inf, sup, Vet) = FALSO se (x Vet[sup]) VERDADE se (x == Vet[med]) ProcBinaria (x, inf, med-1, Vet) se (x < Vet[med]) ProcBinaria (x, med+1, sup, Vet) se (x > Vet[med]) -5 0 1 4 2 7 3 10 4 14 5 15 6 17 7 21 8 23 9 24 10 30 11 32 12 38 13 45 14 50 15 53 16 Vet med inf sup x
64
- - - - - typedef int *vetor; - - - - - logic ProcBinaria (int, int, int, vetor); void main () { int - - - -, n, num; vetor A; logic estah; - - - - - logic estah; - - - - - Alocacao, leitura e ordenacao do vetor A estah = ProcBinaria (num, 0, n-1, A); - - - - - } logic ProcBinaria (int x, int inf, int sup, vetor Vet) { int med; logic r; if (x Vet[sup]) r = FALSE; if (x Vet[sup]) r = FALSE; else { else { med = (inf + sup) / 2; if (x == Vet[med]) r = TRUE; else if (x < Vet[med]) r = ProcBinaria (x, inf, med-1, Vet); else r = ProcBinaria (x, med+1, sup, Vet); } return r; return r;} A Vet A[0] Os ponteiros Vet de todas as chamadas recursivas apontarão para A[0]
65
Exercícios 9.4: 1.Um conjunto de números inteiros não repetidos pode ser representado por uma estrutura com dois campos: um vetor guardando seus elementos e um inteiro contendo o número de elementos do conjunto Considerando como Universo o conjunto de números inteiros no intervalo [1.. 20], fazer: a)Uma função que tenha como parâmetro um conjunto e que retorne esse conjunto sem elementos repetidos e sem elementos que não pertençam ao referido universo b)Uma função que tenha dois conjuntos como parâmetros e que retorne o conjunto união desses conjuntos c)Uma função análoga à do item b, para o conjunto interseção
66
d)Uma função que receba um conjunto como parâmetro e que retorne o seu conjunto complemento, em relação ao referido universo. e)Uma função que receba um conjunto como parâmetro e que o liste no seguinte formato: {elemento, elemento,..., elemento}, ou, se for vazio, {conjunto vazio} f)Um programa principal que leia uma expressão contendo vários conjuntos e vários operadores de conjuntos (U = união, I = interseção, C = complemento), que use a função do item a para limpá-la, exibindo- a em seguida, e que calcule e escreva o valor do conjunto resultado da expressão, usando as funções dos outros itens Exemplo: se os dados de entrada forem: {9 11 3 7 6 3} U {3 11 15 22 10 5 9} I {18 1 3 9 -5 14 7 5} C I {7 2 15} A saída deve ser do tipo: {9 11 3 7 6} U {3 11 15 10 5 9} I {18 1 3 9 14 7 5} C I {7 2 3 11 13 15} = {2 11 13 15}
67
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
68
9.5 – Subprogramas como Parâmetros Em C, o nome de uma função é encarado pelo compilador como sendo um ponteiro para o código dessa função Em C, o nome de uma função é encarado pelo compilador como sendo um ponteiro para o código dessa função É uma variável que guarda o endereço da função na memória É uma variável que guarda o endereço da função na memória Esse fato possibilita, entre outras coisas, que nomes de funções sejam passados como argumentos para outras funções Esse fato possibilita, entre outras coisas, que nomes de funções sejam passados como argumentos para outras funções Seja o programa da Regra do Trapézio visto no Capítulo II Seja o programa da Regra do Trapézio visto no Capítulo II
69
#include #include double f (double x) {return (log10(x) + 5);} int main () { long n, i; float a, b, p; double S1, S2, STrap, Dx; scanf ("%f%f%f", &a, &b, &p); S2 = 0; n = 5; do { S1 = S2; n = 2*n; Dx = (b-a)/n; S2 = 0; i = 1; while (i <= n) { STrap = Dx * (f(a+(i-1)*Dx) + f(a+i*Dx)) / 2; S2 = S2 + STrap; i = i + 1; } } while (fabs (S1-S2) > p); printf ("\nA Integral de f(x) no intervalo [%g, %g]", a, b); printf (" com precisao %g eh %g", p, S2); printf ("\n\nDigite algo para encerrar"); getch (); } Este programa calcula a integral de uma só função: log 10 x + 5 Pode-se fazer uma função integradora em que um dos parâmetros é o nome da função a ser integrada
70
#include<stdio.h>#include<conio.h>#include<math.h> /* Declaracoes das 3 funcoes a serem integradas: log10(x) + 5, x^3 - x, sen(x) + 2 */ double f1 (double x) { return (log10(x)+5); } double f2 (double x) { return (pow(x,3)-x); } double f3 (double x) { return (sin(x)+2); }
71
/*Declaracao da funcao integradora*/ double integral (double f (double),float a, float b, float p) { double s1, s2, si, dx; int n, i; s2 = 0; n = 5; do { s1 = s2; n = 2*n; dx = (b-a)/n; s2 = 0; for (i = 1 ; i <= n; i = i+1) { si = dx * (f(a+(i-1)*dx)+f(a+i*dx)) / 2; s2 = s2 + si; } } while (fabs(s1 - s2) >= p); return s2; } A função f será substituída por aquela que vier como argumento
72
void main () { float a, b, p; printf ("Integral de log10(x):\n\n\tlimite inferior: "); scanf ("%f", &a); printf ("\tlimite superior: "); scanf ("%f", &b); printf ("\tprecisao: ");scanf ("%f", &p); printf ("\n\tValor da integral: %lf\n\n", integral (f1, a, b, p)); printf ("Integral de x**3 - x:\n\n\tlimite inferior: "); scanf ("%f", &a); printf ("\tlimite superior: "); scanf ("%f", &b); printf ("\tprecisao: ");scanf ("%f", &p); printf ("\n\tValor da integral: %lf\n\n", integral (f2, a, b, p)); printf ("Integral de sen(x)+2:\n\n\tlimite inferior: "); scanf ("%f", &a); printf ("\tlimite superior: "); scanf ("%f", &b); printf ("\tprecisao: ");scanf ("%f", &p); printf ("\n\tValor da integral: %lf\n\n", integral (f3, a, b, p)); printf("\n\nDigite algo para encerrar: "); getch(); printf("\n\nDigite algo para encerrar: "); getch();}
73
Integral de log10(x): limite inferior: 1 limite inferior: 1 limite superior: 20 limite superior: 20 precisao: 0.0001 precisao: 0.0001 Valor da integral: 112.768974 Valor da integral: 112.768974 Integral de x**3 - x: limite inferior: 3 limite inferior: 3 limite superior: 20 limite superior: 20 precisao: 0.001 precisao: 0.001 Valor da integral: 39784.250269 Valor da integral: 39784.250269 Integral de sen(x)+2: limite inferior: 0 limite inferior: 0 limite superior: 6.28 limite superior: 6.28 precisao: 0.00001 precisao: 0.00001 Valor da integral: 12.560005 Valor da integral: 12.560005 Resultado de uma execução
74
Subprogramas como parâmetros são usados em problemas científicos envolvendo funções: Subprogramas como parâmetros são usados em problemas científicos envolvendo funções: Tabelas, gráficos, máximos e mínimos, equações diferenciais, etc. Tabelas, gráficos, máximos e mínimos, equações diferenciais, etc.
75
Exercícios 9.5: 1.Fazer uma função para imprimir tabelas de funções de uma variável. Seus parâmetros devem ser: A função f(x) cuja tabela deve ser impressa, os extremos a e b do intervalo a ser impresso e uma variável inteira n contendo o número desejado de linhas da tabela. Cada linha da tabela deve conter um valor de x e o correspondente valor de f(x). O primeiro valor de x da tabela deve ser o valor de a e o último deve ser o valor de b. O número total de linhas deve ser o valor de n. Fazer um programa que chame a referida função para imprimir tabelas para as seguintes funções: Os intervalos e o número de linhas de cada tabela devem ser lidos. As três funções acima devem ser também programadas
76
2.Fazer uma função para traçar gráficos de funções de uma variável no modo gráfico do vídeo do computador. Seus parâmetros devem ser a função f(x) cujo gráfico deve ser desenhado e os extremos a e b do intervalo de variação de x nesse gráfico. O gráfico deve ocupar a tela inteira, portanto a variação da abscissa deve ser ajustar ao tamanho do intervalo Fazer um programa que chame a referida função para desenhar gráficos para as seguintes funções: Nesse programa, os intervalos devem ser lidos
77
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
78
9.6 – Encadeamento de Estruturas Estruturas também podem ser alocadas dinamicamente Estruturas também podem ser alocadas dinamicamente Por exemplo, sejam as seguintes declarações: Por exemplo, sejam as seguintes declarações: typedef struct st st; struct st {int a; float b;}; st *p; O comando O comando p = (st *) malloc (sizeof(st)); aloca espaço para uma estrutura st, cujo endereço é atribuído à variável p
79
typedef struct st st; struct st {int a; float b;}; st *p; p = (st *) malloc (sizeof(st)); Representação gráfica: Representação gráfica: Os parêntesis são necessários pois. tem precedência sobre * Os parêntesis são necessários pois. tem precedência sobre * Outra forma de referenciar os campos de uma estrutura apontada: Outra forma de referenciar os campos de uma estrutura apontada: ab p Atribuindo: (*p).a = 5; (*p).b = 17.3; 517.3 (*p).a = 5; (*p).b = 17.3; p->a = 5; p->b = 17.3; equivalem a (*p) é uma estrutura sem nome
80
Exemplo: sejam as seguintes declarações: Exemplo: sejam as seguintes declarações: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; e os seguintes comandos: p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); Um dos campos da estrutura st é um ponteiro para uma estrutura de mesmo tipo (st)
81
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 Formou-se um encadeamento de estruturas
82
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 q
83
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 q 2 Vídeo
84
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 q 2 Vídeo q
85
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 2 Vídeo q
86
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 2 3 Vídeo q
87
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 2 3 Vídeo qq
88
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 2 3 Vídeo q
89
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 2 3 5 Vídeo q
90
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 2 3 5 Vídeo q q q == NULL: Fim!!! O ponteiro q percorreu o encadeamento com o comando q = q->prox
91
Seja a execução dos comandos: Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox;}; st *p, *q; p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox->prox = (st *) malloc (sizeof(st)); p->prox->prox->a = 5; p->prox->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) printf ("%4d", q->a); p aprox 2 a 3 a 5 q A constante NULL é muito usada para teste de final de percurso O ponteiro q percorreu o encadeamento com o comando q = q->prox
92
p aprox 2 a 3 a 5 q Duas formas de referenciar este local p->prox->prox->a (*(*(*p).prox).prox).a Qual delas é mais cômoda???
93
Encadeamento de estruturas é a principal razão para incorporação de variáveis-ponteiros nas linguagens de programação Encadeamento de estruturas é a principal razão para incorporação de variáveis-ponteiros nas linguagens de programação A disciplina CES-11 Algoritmos e Estruturas de Dados mostra a grande variedade de alternativas de armazenamento de informações oferecida por encadeamentos desse gênero A disciplina CES-11 Algoritmos e Estruturas de Dados mostra a grande variedade de alternativas de armazenamento de informações oferecida por encadeamentos desse gênero Modelos como listas lineares, árvores, grafos, estruturas multi-ligadas muito se beneficiam da inclusão de um ou mais ponteiros em variáveis do tipo struct. Modelos como listas lineares, árvores, grafos, estruturas multi-ligadas muito se beneficiam da inclusão de um ou mais ponteiros em variáveis do tipo struct. O último capítulo, Noções de Estruturas de Dados, oferece uma pequena amostra da utilidade desses modelos O último capítulo, Noções de Estruturas de Dados, oferece uma pequena amostra da utilidade desses modelos
94
No exemplo anterior, a estrutura tinha apenas um campo- ponteiro No exemplo anterior, a estrutura tinha apenas um campo- ponteiro Estruturas com mais campos-ponteiros permitem construções bem mais complexas Estruturas com mais campos-ponteiros permitem construções bem mais complexas Exemplo: sejam as declarações: Exemplo: sejam as declarações: typedef struct celula celula; typedef struct celula *noh; struct celula { informacao info; noh pai, fesq, idir; }; Elas possibilitam construções de árvores (próximo slide) Elas possibilitam construções de árvores (próximo slide) infopai fesqidir Célula
95
infopai fesqidir Célula Aplicações: Organogramas Resolução de expressões aritméticas Jogos eliminatórios de um campeonato etc.
Apresentações semelhantes
© 2024 SlidePlayer.com.br Inc.
All rights reserved.