CES11 ALGORITMOS E ESTRUTURAS DE DADOS Captulo I

  • Slides: 90
Download presentation
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Capítulo I Introdução

CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Capítulo I Introdução

Capítulo I - Introdução 1. 1 – Revisão sobre tipos, comandos e subprogramação 1.

Capítulo I - Introdução 1. 1 – Revisão sobre tipos, comandos e subprogramação 1. 2 – Tipos abstratos de dados 1. 3 – Noções de complexidade de algoritmos

1. 1 – Revisão sobre Tipos, Comandos e Subprogramação 1. 1. 1 – Componentes

1. 1 – Revisão sobre Tipos, Comandos e Subprogramação 1. 1. 1 – Componentes de um sistema de informações n Um grande sistema de informações pode ser decomposto em um conjunto de subsistemas menores interligados n Cada um desses subsistemas por sua vez pode ser decomposto da mesma maneira n E assim por diante, até que se obtenha um conjunto

Exemplo: cadastro dos funcionários de uma empresa n n n Nome, setor de trabalho:

Exemplo: cadastro dos funcionários de uma empresa n n n Nome, setor de trabalho: strings Salário: número real Sexo: um caractere (M ou F) Data de nascimento: vetor de 3 inteiros Endereço: logradouro, número, bairro, cidade e estado Número inteiro Strings

n Informações escalares: compostas de um único elemento; indivisíveis; exemplos: Sexo, Salário e Número

n Informações escalares: compostas de um único elemento; indivisíveis; exemplos: Sexo, Salário e Número do Endereço n Informações estruturadas: podem ser subdivididas (exemplos: Nome, Endereço, Data de Nascimento, Setor de Trabalho) n Endereço: subdividido em outras informações estruturadas (Logradouro, Bairro, Cidade e Estado)

1. 1. 2 – Tipos escalares primitivos n Tipo primitivo: é um tipo escalar

1. 1. 2 – Tipos escalares primitivos n Tipo primitivo: é um tipo escalar cujas variáveis e constantes são declaradas por meio de palavras reservadas a) Tipo Inteiro: (int , short , long) Domínio: números inteiros entre - e + Operações: + - * / % Exemplos: 7 / 3 = 2 b) Tipo Real: (float, double) = < > 7 % 3=1 Domínio: números reais entre - e + Operações: + - * / = < >

c) Tipo Caractere: (char) Domínio: -Dígitos decimais: ‘ 0’, ‘ 1’, . . .

c) Tipo Caractere: (char) Domínio: -Dígitos decimais: ‘ 0’, ‘ 1’, . . . , ‘ 9’ -Letras: ‘A’, ‘B’, . . . , ‘Z’, ‘a’, ‘b’, . . . , ‘z’ -Sinais especiais: ‘. ’ , ‘, ’ , ‘; ’ , ‘+’ , ‘*’ , ‘/’, ‘(’ , ‘)’, ‘[’, ‘]’, . . . -Caracteres de controle: ‘n’, ‘t’, ‘b’, ‘r’, . . . Operações: = ( < > + - * / %) d) Tipo Lógico: (logic – não há em C) Domínio: Verdade e Falso Operações: =, ≠, and, or, not, nand, nor e xor Resultados de comparações são valores lógicos

1. 1. 3 – Comandos básicos de uma linguagem n Os algoritmos apresentados nesta

1. 1. 3 – Comandos básicos de uma linguagem n Os algoritmos apresentados nesta disciplina serão expressos num código correspondente a um aplainamento da Linguagem C - Quase tudo na mesma forma da Linguagem C - Comandos de entrada e saída, comandos de seleção e outros terão forma mais simples que a da Linguagem C, para maior clareza

n Comando composto: { Comando. . . Comando } n Bloco: { Declarações Comando.

n Comando composto: { Comando. . . Comando } n Bloco: { Declarações Comando. . . Comando } n Comando de atribuição: Operadores: =, ++, --, +=, -=, *=, /=, %= n Comandos de entrada e saída: read (Variável , . . . , Variável); write (Elemento , . . . , Elemento) Elemento pode ser uma expressão ou uma string

n Comandos condicionais: if ( Expressão ) Comando else Comando n Expressão condicional: Expr

n Comandos condicionais: if ( Expressão ) Comando else Comando n Expressão condicional: Expr 1 ? Expr 2 : Expr 3 n Comandos repetitivos: while ( Expressão ) Comando do Comando while Expressão ; for ( Inicializações ; Expressão ; Atualizações ) Comando

n Comando de seleção: switch ( Expressão inteira ) { V 11, V 12,

n Comando de seleção: switch ( Expressão inteira ) { V 11, V 12, . . . , V 1 m : Lista de comandos; V 21, V 22, . . . , V 2 n : Lista de comandos; . . . . Vi 1, Vi 2, . . . , Vip : Lista de comandos; default: Lista de comandos; } Para maior clareza, nos algoritmos não serão usados case’s nem break’s n Comandos de desvio: break ; goto Rótulo ;

1. 1. 4 – Tipos estruturados de uma linguagem a) Vetores: Tipo. Primitivo V[30],

1. 1. 4 – Tipos estruturados de uma linguagem a) Vetores: Tipo. Primitivo V[30], W[50], X[200]; ou typedef Tipo. Primitivo vetor[30]; vetor V 1, V 2, V 3; b) Matrizes: Tipo. Primitivo M 1[10][10], M 2[8][20]; ou typedef Tipo. Primitivo matriz[10]; matriz M 1, M 2, M 3;

n Há matrizes especiais com poucos elementos nãonulos n Por simplicidade, serão abordadas apenas

n Há matrizes especiais com poucos elementos nãonulos n Por simplicidade, serão abordadas apenas as matrizes bidimensionais quadradas n Matriz diagonal: Para armazená-la: • Um vetor com os elementos da diagonal principal • Um inteiro com sua dimensão Mat. Diag 5 n Elem 5 6 2 8 1 0 3 4 1 2

n Matriz tridiagonal: Para armazená-la: • Um vetor para armazenar os elementos das 3

n Matriz tridiagonal: Para armazená-la: • Um vetor para armazenar os elementos das 3 diagonais relevantes • Um inteiro com o número de elementos dessas 3 diagonais n 19 Elem 5 3 7 6 2 4 2 8 5 8 3 1 1 4 4 8 3 9 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Mat. Tri. Diag Algoritmos especiais são necessários para manipular matrizes tridiagonais armazenadas em vetores

n Matriz triangular: Para armazená-la: • Um vetor para armazenar os elementos da área

n Matriz triangular: Para armazená-la: • Um vetor para armazenar os elementos da área não -nula Mat. Triang 5 4 1 3 1 6 2 7 2 2 4 3 8 9 Dimensão: 1 Tipo: 5 superior • Um inteiro com a dimensão da matriz • Um flag dizendo se é superior ou inferior Algoritmos especiais são necessários para manipular matrizes triangulares armazenadas em vetores

n Matriz faixa: Para armazená-la: • Um vetor para armazenar os elementos da área

n Matriz faixa: Para armazená-la: • Um vetor para armazenar os elementos da área nãonula • Um inteiro com a dimensão da matriz • Dois inteiros com a largura da faixa acima e abaixo da diagonal principal Algoritmos especiais são necessários para manipular matrizes faixas armazenadas em vetores

n Matriz esparsa: Para armazená-la: • Matriz bidimensional com 3 linhas: • Uma com

n Matriz esparsa: Para armazená-la: • Matriz bidimensional com 3 linhas: • Uma com os elementos não-nulos • Outra com os números das linhas desses elementos • Outra com os números de suas colunas • Um inteiro com o número de elementos não-nulos 9 4 3 2 8 5 0 2 3 4 5 6 4 1 4 0 5 1 6 elementos

c) Strings n Declarações: typedef char string[15]; string s 1, s 2; n Operações:

c) Strings n Declarações: typedef char string[15]; string s 1, s 2; n Operações: strcat (s 1, s 2); c = strlen (s 1); strcpy (s 1, s 2); strcmp (s 1, s 2); strcpy (s 1, “Cadeia de teste”);

d) Estruturas n Estruturas simples: typedef struct funcionario; struct funcionario { char Nome[30], Endereço[30],

d) Estruturas n Estruturas simples: typedef struct funcionario; struct funcionario { char Nome[30], Endereço[30], Setor[15]; char Sexo, Estcivil; int Idade, Anosfirma ; }; funcionario F 1, F 2, F 3, Empregados [200]; . . . Empregados[1] = F 1; F 2. Sexo = ‘M’; strcpy (Empregados[3]. Nome, “José da Silva”);

n Estruturas de campos alternativos: Tipo union: define um conjunto alternativo de campos que

n Estruturas de campos alternativos: Tipo union: define um conjunto alternativo de campos que podem ser armazenados numa mesma posição de memória. n Exemplo: typedef union ttt; union ttt { char c 1; int c 2; double c 3; char A[10]; }; ttt t 1, t 2, t 3; O espaço reservado para t 1 é o do maior de seus campos t 1 c 1 / c 2 / c 3 / A

n Exemplo: Seja o cadastro dos habitantes de uma cidade A seguir, informações pertinentes

n Exemplo: Seja o cadastro dos habitantes de uma cidade A seguir, informações pertinentes sobre um habitante genérico

A seguir, declarações para implementar o cadastro desses habitantes

A seguir, declarações para implementar o cadastro desses habitantes

Habitante Hab [1000000]; typedef struct Habitante; struct Habitante { char nome [30], ender [30],

Habitante Hab [1000000]; typedef struct Habitante; struct Habitante { char nome [30], ender [30], cid_natal [20]; Data. Nasc: int esc; Formacao form; }; typedef union Formacao; union Formacao { Prim. Grau pg; Seg. Grau sg; Superior }; sp;

typedef struct Prim. Grau; struct Prim. Grau { int ano_term; }; typedef struct Seg.

typedef struct Prim. Grau; struct Prim. Grau { int ano_term; }; typedef struct Seg. Grau; struct Seggrau { int ano_term; char tipo; }; typedef struct Superior; struct Superior { int ano_term; char nome_escola[30], tipo[4]; }; typedef struct Data; struct Data { int dia, mes, ano; };

e) Tipos enumerativos: typedef enum Cor; enum Cor {Branca, Amarela, Verde, Azul, Preta}; typedef

e) Tipos enumerativos: typedef enum Cor; enum Cor {Branca, Amarela, Verde, Azul, Preta}; typedef enum Diasemana; enum Diasemana {Dom, Seg, Ter, Qua, Qui, Sex, Sab}; Diasemana Ontem, Hoje, Amanha; Cor c 1, c 2, c 3;

1. 1. 5 – Subprogramação n Chamada de função: Nome. Função (Lista. Argumentos) n

1. 1. 5 – Subprogramação n Chamada de função: Nome. Função (Lista. Argumentos) n Lista. Argumentos pode ser ou não vazia n Uma chamada de função pode aparecer em expressões maiores n Quando aparecer isolada, seguida de ‘; ’, torna-se um comando de uma lista de comandos

n n Declaração de funções: Tipo Nome. Função (Lista. Parâmetros) { Corpo. Função Funções

n n Declaração de funções: Tipo Nome. Função (Lista. Parâmetros) { Corpo. Função Funções que não } retornam valores serão do tipo void Lista. Parâmetros pode ser ou não vazia n Parâmetros sempre são alocados quando a função é chamada para execução n Parâmetros recebem os argumentos da chamada da função n Duas formas de passagem de argumentos: por valor ou por referência (ou por endereço)

Passagem por valor: void ff (int a) { a += 1; write ("Durante ff:

Passagem por valor: void ff (int a) { a += 1; write ("Durante ff: a = ", a); } void main ( ) { int a = 5; write ("Antes de ff: a = ", a); ff (a); write ("Depois de ff: a = ", a); } Saída: Antes de ff: a = 5 Durante ff: a = 6 Depois de ff: a = 5 a 6 5 a 5 São 2 variáveis diferentes, de mesmo nome: a

Passagem por referência ou endereço: void trocar (int *p, int *q){ int aux; aux

Passagem por referência ou endereço: void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

Seja sua execução: void trocar (int *p, int *q){ int aux; aux = *p;

Seja sua execução: void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } 3 i 8 j void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

void trocar (int *p, int *q){ int aux; aux = *p; *p = *q;

void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } 3 i 8 j void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

aux p q 3 i 8 j void trocar (int *p, int *q){ int

aux p q 3 i 8 j void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

aux p q 3 i 8 j void trocar (int *p, int *q){ int

aux p q 3 i 8 j void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

aux 3 p q 3 i 8 j void trocar (int *p, int *q){

aux 3 p q 3 i 8 j void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

aux 3 p q 3 i 8 j void trocar (int *p, int *q){

aux 3 p q 3 i 8 j void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

aux 3 p q 8 i 8 j void trocar (int *p, int *q){

aux 3 p q 8 i 8 j void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

aux 3 p q 8 i 8 j void trocar (int *p, int *q){

aux 3 p q 8 i 8 j void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

aux 3 p q 8 i 3 j void trocar (int *p, int *q){

aux 3 p q 8 i 3 j void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

Desalocação das variáveis de Trocar: aux 3 p q 8 i 3 j void

Desalocação das variáveis de Trocar: aux 3 p q 8 i 3 j void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

Antes de trocar, i = 3; j = 8 Depois de trocar, i =

Antes de trocar, i = 3; j = 8 Depois de trocar, i = 8; j = 3 Resultado void trocar (int *p, int *q){ int aux; aux = *p; *p = *q; *q = aux; } 8 i 3 j void main ( ) { int i = 3, j = 8; write ("Antes de trocar, i = ", i, "; j = ", j); trocar(&i, &j); write ("Depois de trocar, i = ", i, "; j = ", j); }

Passagem de variáveis indexadas: n O nome de uma variável indexada é o endereço

Passagem de variáveis indexadas: n O nome de uma variável indexada é o endereço de seu 1º elemento n Se um dos parâmetros de uma função for uma variável indexada, na realidade ele será um ponteiro n Caso o argumento correspondente seja o nome de uma variável indexada: - O endereço correspondente ao seu nome é passado ao parâmetro - Os elementos da variável-argumento não são copiados para a função

n Então essa passagem de argumento é por referência ou por endereço n Toda

n Então essa passagem de argumento é por referência ou por endereço n Toda alteração nos elementos da variávelparâmetro terá efeito sobre aqueles da variávelargumento n Outros possíveis argumentos: ponteiros e endereços n A seguir um exemplo ilustrativo

void Alterar (int B[]) { B[1] = B[3] = 7; } O parâmetro B

void Alterar (int B[]) { B[1] = B[3] = 7; } O parâmetro B de Alterar é um ponteiro void main () { int i, j, A[10] = {0}; Não é necessário write ("Vetor inicial: "); colocar a dimensão for (i = 0; i <= 9; i++) write (A[i]); Poderia ser int *B Alterar (A); write ("Vetor intermediario: "); for (i = 0; i <= 9; i++) write (A[i]); Alterar (&A[4]); write ("Vetor final: "); for (i = 0; i <= 9; i++) write (A[i]); }

B void Alterar (int B[]) { B[1] = B[3] = 7; } A 0

B void Alterar (int B[]) { B[1] = B[3] = 7; } A 0 07 0 0 0 A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] void main () { int i, j, A[10] = {0}; B[0] B[1] B[2] B[3] B[0] B[4] B[1] B[5] B[2] B[6] B[3] B[7] B[4] B[8] B[5] B[9] write ("Vetor inicial: "); for (i = 0; i <= 9; i++) write (A[i]); Alterar (A); write ("Vetor intermediario: "); for (i = 0; i <= 9; i++) write (A[i]); Alterar (&A[4]); write ("Vetor final: "); for (i = 0; i <= 9; i++) write (A[i]); }

Vetor inicial void Alterar (int B[]) { B[1] = B[3] = 7; } :

Vetor inicial void Alterar (int B[]) { B[1] = B[3] = 7; } : 0 0 0 0 0 Vetor intermediario: 0 7 0 0 0 Vetor final 0 7 0 7 0 0 : void main () { int i, j, A[10] = {0}; write ("Vetor inicial: "); for (i = 0; i <= 9; i++) write (A[i]); Alterar (A); write ("Vetor intermediario: "); for (i = 0; i <= 9; i++) write (A[i]); Alterar (&A[4]); write ("Vetor final: "); for (i = 0; i <= 9; i++) write (A[i]); } Resultado

Passagem de estruturas: n A passagem de uma estrutura como argumento pode ser por

Passagem de estruturas: n A passagem de uma estrutura como argumento pode ser por valor ou por referência (endereço) n A passagem de uma grande estrutura por valor provoca a movimentação de considerável massa de dados n Então uma grande estrutura só deve ser passada por valor, se o subprograma alterar esse valor e se o argumento não puder sofrer essa alteração n Caso o subprograma não altere o parâmetro correspondente, é recomendável que tal estrutura seja passada por endereço:

1. 1. 6 – Ponteiros a) Conceitos, declarações e atribuições n Ponteiros são endereços

1. 1. 6 – Ponteiros a) Conceitos, declarações e atribuições n Ponteiros são endereços n Existem constantes e variáveis do tipo ponteiro n O endereço de uma variável a declarada num bloco qualquer permanece o mesmo durante a execução do bloco - n Então &a é uma constante do tipo ponteiro Variável do tipo ponteiro armazena um endereço que pode ser alterado durante a execução do

Exemplo: seja trecho de programa: int c = 237, b = 15, *q; double

Exemplo: seja trecho de programa: int c = 237, b = 15, *q; double a = 13. 5, *p; p = &a; q = &b; write ("Endereco(p) = ", write ("p = ", p); write ("Endereco(a) = ", write ("Endereco(q) = ", write ("q = ", q); write ("Endereco(b) = ", write ("Endereco(c) = ", write ("a = ", a); write ("b = ", b); write ("c = ", c); &p); &a); &q); &b); &c); Resultado Endereco(p) p Endereco(a) Endereco(q) q Endereco(b) Endereco(c) a b c = = = = = 1638204 1638208 1638216 1638220 1638224 13. 5 15 237 Com este resultado, pode-se desenhar o mapa da memória a seguir

int c = 237, b = 15, *q; double a = 13. 5, *p;

int c = 237, b = 15, *q; double a = 13. 5, *p; p = &a; q = &b; 1638204 1638208 p 13. 5 a 1638220 q 15 b 237 c 1638208 Endereco(p) p Endereco(a) Endereco(q) q Endereco(b) Endereco(c) a b c Resultado = = = = = 1638204 1638208 1638216 1638220 1638224 13. 5 15 237 1638216 1638220 1638224

int c = 237, b = 15, *q; double a = 13. 5, *p;

int c = 237, b = 15, *q; double a = 13. 5, *p; p = &a; q = &b; 1638204 1638208 p 13. 5 a 1638220 q 15 b 237 c 1638208 &a é uma constanteponteiro para double &b é uma constanteponteiro para int 1638216 1638220 1638224

int c = 237, b = 15, *q; double a = 13. 5, *p;

int c = 237, b = 15, *q; double a = 13. 5, *p; p = &a; q = &b; 1638204 1638208 p 13. 5 a 1638220 q 15 b 237 c 1638208 q é um ponteiro para o tipo int p é um ponteiro para o tipo double 1638216 p recebe o endereço de a q recebe o endereço de b p aponta para a q aponta para b a é apontada por p b é apontada por q 1638220 1638224

int c = 237, b = 15, *q; double a = 13. 5, *p;

int c = 237, b = 15, *q; double a = 13. 5, *p; p = &a; q = &b; 1638204 1638208 p 13. 5 a 1638220 q 15 b 237 c 1638208 Duas formas de representação gráfica: p 13. 5 a 1638216 q 15 b ou simplesmente: p q 1638220 13. 5 a 15 b 1638224

n Considerando-se as declarações: float a; int c; float *p; int *q; são possíveis

n Considerando-se as declarações: float a; int c; float *p; int *q; são possíveis as seguintes atribuições: p = &a; q = &c; p = NULL; p q a c p p = (float*) 1776; p 1776

Acesso ao local apontado por um ponteiro: n Seja a declaração: int a, b,

Acesso ao local apontado por um ponteiro: n Seja a declaração: int a, b, *p; p a *p n O local apontado por p é referenciado por *p b *p n Executando-se p = &a; então *p passa a coincidir com a n Depois, executando-se coincidir com b p = &b; então *p passa a

n Exemplo: Seja o seguinte trecho de programa: int a, b = 2, *p;

n Exemplo: Seja o seguinte trecho de programa: int a, b = 2, *p; p = &a; *p = 1; b = *p; a 1 Prosseguind Inicialmente o b 2 1 p

n Exemplo: Seja a seguinte declaração: int a = 2, b = 5, *p

n Exemplo: Seja a seguinte declaração: int a = 2, b = 5, *p = &a, *q = &b; Inicialmente: Voltando Fazendo pà =situação *p =q; *q; inicial: a 2 5 p b 5 q Apesar de (*p) e (*q) serem iguais, p é diferente de q

n As principais utilidades dos ponteiros são: - Alocação dinâmica de variáveis indexadas Passagem

n As principais utilidades dos ponteiros são: - Alocação dinâmica de variáveis indexadas Passagem de parâmetros por referência Encadeamento de estruturas n O encadeamento de estruturas foi a principal razão para a criação de ponteiros n Ele é usado intensamente em CES-11 Algoritmos e Estruturas de Dados

b) Relação entre Ponteiros e Variáveis Indexadas: n O nome de uma variável indexada

b) Relação entre Ponteiros e Variáveis Indexadas: n O nome de uma variável indexada é o endereço do primeiro de seus elementos - É uma constante-ponteiro apontando para seu elemento zero Não tem um local exclusivo na memória n Seja a declaração int A[8]; n Representação gráfica de A: O nome de uma variável indexada pode ser atribuído a um ponteiro de mesmo tipo

Exemplo: seja o seguinte trecho de programa: int p = i, A[8], B[5], *p;

Exemplo: seja o seguinte trecho de programa: int p = i, A[8], B[5], *p; A; B; Inicialmente Após p = B; A; : A Proibidos: p tem local A = p; exclusivo. B = p; = B; A e B não. Atêm B = A; A = &i; B = &i; A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] p ? B B[0] B[1] B[2] B[3] B[4] *A A[0] e *B B[0] p tornou-se equivalente a A: B: p[0] B[0], A[0], p[1] B[1], A[1], . . . , p[7] B[4] p[4] A[7] p se tornou variável

n Ponteiros podem ter subscritos e variáveis indexadas admitem o operador unário ‘*’ n

n Ponteiros podem ter subscritos e variáveis indexadas admitem o operador unário ‘*’ n Exemplo: supondo as declarações: int i, A[50], *p; A[i] *(p+i) é equivalente a *(A+i) é equivalente a p[i] Sabe-se que A contém o endereço de A[0], logo p=A equivale a p = &A[0] p = A+i equivale a p = &A[i] a[1] tem sempre o mesmo endereço p[1] pode variar de endereço

c) Alocação dinâmica de memória n Muitas vezes é útil reservar espaço para uma

c) Alocação dinâmica de memória n Muitas vezes é útil reservar espaço para uma variável indexada, em tempo de execução n Sabendo-se o seu número de elementos, reserva-se espaço necessário e suficiente para essa variável n Em primeiro lugar, tal variável deve ser declarada como ponteiro

n Esse tipo de reserva em tempo de execução denomina-se alocação dinâmica n Há

n Esse tipo de reserva em tempo de execução denomina-se alocação dinâmica n Há uma região da memória ocupada pelo programa denominada heap, destinada a essas alocações dinâmicas

n A alocação pode ser feita pela função malloc n malloc recebe como argumento

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

n Exemplo: para alocar um vetor de 7 elementos do tipo int: int *V;

n 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 heap

Tamanho dos vetores: typedef int *vetor; void main () { Vetor A: 28 39

Tamanho dos vetores: typedef int *vetor; void main () { Vetor A: 28 39 84 27 int m, i; vetor A, B, C; Vetor B: 94 27 68 17 write ("Tamanho dos vetores: "); Vetor C: 94 39 read (m); A = (int *) malloc (m*sizeof(int)); B = (int *) malloc (m*sizeof(int)); C = (int *) malloc (m*sizeof(int)); write ("n. Vetor A: "); for (i = 0; i < m; i++) read (A[i]); write ("n. Vetor B: "); for (i = 0; i < m; i++) read (B[i]); write ("n. Vetor C: "); for (i = 0; i < m; i++) C[i] = (A[i] > B[i])? A[i]: B[i]; for (i = 0; i < m; i++) write (C[i]); } 7 Exemplo: seja o 83 72 39 programa à 84 esquerda 27 83 72 82 49 10 39 No vídeo

n Quando um espaço assim alocado não for mais usado, ele pode ser novamente

n Quando um espaço assim alocado não for mais usado, ele pode ser novamente disponibilizado para outras alocações, mediante o comando free (A); n Quando um programa faz muitas alocações dinâmicas, ele pode esgotar a capacidade dessa área especial n Se, durante a execução, algumas dessas alocações perderem sua utilidade, é bom que elas sejam novamente disponibilizadas n Isso pode evitar tal esgotamento

d) Alocação dinâmica de matrizes: Pode feita por vetores de ponteiros Seja A uma

d) Alocação dinâmica de matrizes: Pode feita por vetores de ponteiros Seja A uma matriz (m x n):

typedef int *vetor; Exemplo: leitura typedef vetor *matriz; uma matriz void main () {

typedef int *vetor; Exemplo: leitura typedef vetor *matriz; uma matriz void main () { int m, n, i, j; matriz A; write ("Dimensoes de uma matriz: "); read (m, n); A = (vetor *) malloc (m * sizeof(vetor)); for (i = 0; i < m; i++) A[i] = (int *) malloc (n * sizeof(int)); A ? ? ? ? de 5 m 4 n Dimensõe s da matriz A partir daqui, o ponteiro A pode ser usado como matriz

typedef int *vetor; Exemplo: leitura typedef vetor *matriz; uma matriz void main () {

typedef int *vetor; Exemplo: leitura typedef vetor *matriz; uma matriz void main () { int m, n, i, j; matriz A; write ("Dimensoes de uma matriz: "); read (m, n); A = (vetor *) malloc (m * sizeof(vetor)); for (i = 0; i < m; i++) A[i] = (int *) malloc (n * sizeof(int)); write ("Elementos da matriz: "); for (i = 0; i < m; i++) { write ("Linha ", i); for (j = 0; j < n; j++) read (A[i][j]); } write ("Confirmacao: "); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) write (A[i][j]); write ("n"); } } de

e) Alocação dinâmica e encadeamento de estruturas n Seja o seguinte código: typedef struct

e) Alocação dinâmica e encadeamento de estruturas n Seja o seguinte código: typedef struct st {int a; st *p; p = (st *) malloc p n a 5 st; float b; }; (sizeof(st)); b 17. 3 Atribuindo: (*p). a = 5; (*p). b = 17. 3; Outra forma de referenciar os campos de uma estrutura apontada: p->a = 5; p->b = 17. 3; equivalem a (*p). a = 5; (*p). b = 17. 3;

n Exemplo: sejam as seguintes declarações: typedef struct st st; struct st {int a;

n Exemplo: sejam as seguintes declarações: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; e os seguintes comandos: Um dos campos da estrutura st é um ponteiro para a própria st p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a);

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; p a 2 prox a 3 prox p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a); a 5 prox

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; a 2 p prox a 3 prox q p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a); a 5 prox

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; a 2 p prox a 3 prox a 5 prox q p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a); Vídeo 2

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; a 2 p q prox a 3 prox a 5 prox q p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a); Vídeo 2

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; p a 2 prox a 3 prox a 5 prox q p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a); Vídeo 2

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; p a 2 prox a 3 prox a 5 prox q p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a); Vídeo 2 3

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; p a 2 prox a 3 prox a 5 q p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a); prox q Vídeo 2 3

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; p a 2 prox a 3 prox a 5 prox q p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a); Vídeo 2 3

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; p a 2 prox a 3 prox a 5 prox q p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a); Vídeo 2 3 5

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; p a 2 prox a 3 prox a 5 q p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; for (q = p; q != NULL; q = q->prox) write (q->a); prox q q == NULL: Fim!!! Vídeo 2 3 5

n Seja a execução dos comandos: typedef struct st st; struct st {int a;

n Seja a execução dos comandos: typedef struct st st; struct st {int a; st *prox; }; st *p, *q; p a 2 prox a 3 prox a 5 prox q p = (st *) malloc (sizeof(st)); p->a = 2; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 3; p->prox = (st *) malloc (sizeof(st)); p->prox->a = 5; p->prox->prox = NULL; A constante NULL for (q = p; q != NULL; q = q->prox) é muito usada write (q->a); para teste de final de percurso

p a 2 prox a 3 prox a 5 prox q Duas formas de

p a 2 prox a 3 prox a 5 prox q Duas formas de referenciar este local p->prox->a (*(*(*p). prox). a Qual delas é mais cômoda? ? ?

n Encadeamento de estruturas é a principal razão para incorporação de variáveis-ponteiros nas linguagens

n Encadeamento de estruturas é a principal razão para incorporação de variáveis-ponteiros nas linguagens de programação n Nesta disciplina será vista grande variedade de alternativas de armazenamento de informações oferecida por encadeamentos desse gênero n 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

1. 1. 7 – Recursividade Formulas recursivas escalares simples: Fatorial: n! = -1, para

1. 1. 7 – Recursividade Formulas recursivas escalares simples: Fatorial: n! = -1, para n < 0 1, para 0 ≤ n ≤ 1 n * (n-1)!, para n > Potenciação: 1, para n = 0 An = A * An-1, para n > 0 1 Máximo divisor comum: ∞, p/ m = 0 e n = 0 mdc (m, n) = m, p/ m > 0 e n = 0 n, p/ m = 0 e n > 0 mdc (n, m%n), p/ m e n > 0

int fat (int f; if (n < 0) else if (n else f =

int fat (int f; if (n < 0) else if (n else f = n return f; } n) { f = -1; <= 1) f = 1; * fat(n-1); void main() { char c; int n; write ("Calculo do fatorial de n"); write ("Digite n: "); read (n); write ("Fat(", n, ") = ", fat(n)); } Exemplo: execução de um programa com uma função recursiva para o cálculo de fatorial

int fat (int f; if (n < 0) else if (n else f =

int fat (int f; if (n < 0) else if (n else f = n return f; } n) { f = -1; <= 1) f = 1; * fat(n-1); void main() { char c; int n; write ("Calculo do fatorial de n"); write ("Digite n: "); read (n); write ("Fat(", n, ") = ", fat(n)); } 5 n Valor digitado:

int fat (int f; if (n < 0) else if (n else f =

int fat (int f; if (n < 0) else if (n else f = n return f; } n) { f = -1; <= 1) f = 1; * fat(n-1); fat – v 1 fat – v 2 fat – v 3 n n 4 n 3 f 24 f 6 5 f 120 f = 5*fat(4) void main() { char c; int n; write ("Calculo do fatorial de n"); write ("Digite n: "); read (n); write ("Fat(", n, ") = ", fat(n)); } f = 4*fat(3) f = 3*fat(2) fat – v 5 fat – v 4 n 1 n 2 f 1 f 2 f=1 f = 2*fat(1) 5 n Valor digitado:

Recursividade com variáveis indexadas n Exemplo: formulação recursiva para a procura binária Vet -5

Recursividade com variáveis indexadas n Exemplo: formulação recursiva para a procura binária Vet -5 -1 4 7 10 14 15 17 21 23 24 30 32 38 45 50 53 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 inf x med sup Proc. Binaria (x, inf, sup, Vet) = FALSO se (x < Vet[inf] ou x > Vet[sup]) VERDADE se (x == Vet[med]) Proc. Binaria (x, inf, med-1, Vet) se (x < Vet[med]) Proc. Binaria (x, med+1, sup, Vet) se (x >

- - typedef int *vetor; - - logic Proc. Binaria (int, vetor); A A[0]

- - typedef int *vetor; - - logic Proc. Binaria (int, vetor); A A[0] void main () { int - -, n, num; vetor A; logic estah; - - Alocacao, leitura e ordenacao do vetor A estah = Proc. Binaria (num, 0, n-1, A); - - } logic Proc. Binaria (int x, int inf, int sup, vetor Vet) { int med; logic r; if (x < Vet[inf] || x > Vet[sup]) r = FALSE; Vet else { med = (inf + sup) / 2; if (x == Vet[med]) r = TRUE; else if (x < Vet[med]) r = Proc. Binaria (x, inf, med-1, Vet); else r = Proc. Binaria (x, med+1, sup, Vet); } return r; Os ponteiros Vet de todas as } chamadas recursivas apontarão