tipos de dados estruturados - fenix.tecnico.ulisboa.pt · ficha - armazena elementos de tipos...
TRANSCRIPT
1
João Miguel da Costa Sousa 248
Tipos de dados estruturados
� Tipos de dados intrínsecos em Fortran� INTEGER
� REAL
� COMPLEX
� CHARACTER
� LOGICAL
� É possível definir tipos (estruturas) ou fichas.� Ficha - armazena elementos de tipos diferentes� Exemplo: ficha de aluno de IP contém:
� Nome (cadeia de caracteres)� Número (inteiro)� Nota exame (real)� Nota projecto (real)� Nota final (inteiro)
João Miguel da Costa Sousa 249
Tipos estruturados
Definição de tipos estruturados (fichas)____________________________________________________________________
Forma:
TYPE nome_tipo
declaracao1declaracao2
...
declaracaok
END TYPE nome_tipo
� O nome_tipo é um identificador em Fortran;� Cada declaracaoi declara um ou mais componentes da
estrutura deste tipo.� Objectivo: declara tipo estruturado (ficha) cujos componentes são
declarados em declaracao1, …, declaracaok. Estas definições são efectuadas na zona de especificações do programa.
2
João Miguel da Costa Sousa 250
Exemplos de fichas
� Exemplo 1: ficha de alunoTYPE Ficha_Aluno
CHARACTER(20) :: Nome
INTEGER :: Numero
REAL :: Exame, Projecto
INTEGER :: NotaFinal
END TYPE Ficha_Aluno Aluno1 Aluno2 Nome Nome Numero Numero Exame Exame Projecto Projecto NotaFinal NotaFinal
� Exemplo 2: ponto no espaço 2-DTYPE Ponto2D
REAL :: X, Y
END TYPE Ponto2D
João Miguel da Costa Sousa 251
Declaração de estruturas
Declaração de estruturas____________________________________________________________________
Forma:
TYPE(nome_tipo) :: lista_identificadores
� Objectivo: declara os identificadores que serão os nomes das estruturas cujos componentes são declarados na definição do tipo nome_tipo .
� Exemplo: estruturas dos tipos definidos no Ex. 1 e no Ex. 2 anteriores:
TYPE(Ficha_Aluno) :: Aluno1, Aluno2
TYPE(Ficha_Aluno), DIMENSION(50) :: Alunos
ou:TYPE(Ficha_Aluno):: Alunos(50)
TYPE(Ponto2D) :: Ponto1, Ponto2
3
João Miguel da Costa Sousa 252
Construtores de fichas
Forma:nome_tipo(lista_componentes)
� Exemplo 1:Ponto2D(2.5, 3.2)
� é um valor do tipo Ponto2D e pode ser atribuida a P:P = Ponto2D(2.5, 3.2)
� Declaração da constante Centro:TYPE(Ponto2D), PARAMETER :: Centro = Ponto2D(2.5, 3.2)
� Declaração da constante Centro:TYPE(Ponto2D), PARAMETER :: Centro = Ponto2D(2.5, 3.2)
...
A = 1.1
P = Ponto2D(A, 2*A)
� Exemplo 2:Aluno1 = Ficha_Aluno(“J. Silva”, 10000, 15., 17., 16)
Alunos(1) = Aluno1
João Miguel da Costa Sousa 253
Acesso a componentes de fichas
� Componentes individuais são acedidos por variáveis qualificadas dadas por:� Nome da estrutura e� Nome do componente,� juntos pelo selector de componente: “%”:
nome_estrutura%nome_componente
� Exemplos:� P%X é o primeiro componente da estrutura P do tipo Ponto2D, e P%Y é o
segundo componente. � Alunos(1)%Nome é o primeiro componente da estrutura Alunos(1) do tipo
Ficha_Aluno, etc.
Aluno1%Nome = “Jose Silva”
READ(*, *) Aluno1%Nome
PRINT(*, *) Aluno1%Nome
Aluno1%Nome(1:1) = “J”
4
João Miguel da Costa Sousa 254
Estruturas encadeadas
� Os componentes de um tipo podem ser de qualquer tipo; mesmo de outra estrutura.
� Exemplo:TYPE Ponto2D
REAL :: X, Y
END TYPE Ponto2D
TYPE Circulo
TYPE(Ponto2D) :: Centro
REAL :: Raio
END TYPE Circulo
TYPE(Circulo) :: C
� declara C que é uma variável do tipo Circulo e tem dois componentes, onde o primeiro é do tipo Ponto2D, e o segundo do tipo REAL.
C = Circulo(Ponto2D(2.5, 3.2), 10.0)
� representa um círculo de raio 10.0 e centrado em (2.5, 3.2). � O valor de C%Centro%X é de 2.5.
João Miguel da Costa Sousa 255
Processamento e atribuições
� E/S de estruturas tem de ser efectuada componente a componente
� Exemplos: leitura e escrita da variável Aluno do tipo Ficha_Aluno, e atribuição por componentes.
READ(*, *) Aluno%Nome, Aluno%Numero, Aluno%Exame, &
Aluno%Projecto, Aluno%NotaFinal
WRITE(*, ‘(1X, “Nome: ”, A)’) Aluno%Nome
WRITE(*, ‘(1X, “Numero: ”, I5)’) Aluno%Numero
WRITE(*, ‘(1X, “Exame: ”, F6.1)’) Aluno%Exame
WRITE(*, ‘(1X, “Projecto: ”, F6.1)’) Aluno%Projecto
WRITE(*, ‘(1X, “Nota Final: ”, I4)’) Aluno%NotaFinal
Aluno2%Nome = Aluno%Nome
Aluno2%Numero = Aluno%Numero
Aluno2%Exame = Aluno%Exame
Aluno2%Projecto = Aluno%Projecto
Aluno2%NotaFinal = Aluno%NotaFinal
� Atribuição: variavel_estrutura = expressao_estrutura
� Exemplo: Aluno2 = Aluno
5
João Miguel da Costa Sousa 256
Estruturas como argumentos
� As estruturas podem ser usadas como argumentos de sub-programas.
� Os parâmetros actuais e formais devem ser do mesmo tipo!
� Exemplo: programa que dados dois pontos calcula a distância entre eles e a recta que passa pelos dois.
� Distância entre 2 pontos P1 com coordenadas (x1, y1) e P2 com coordenadas (x2, y2):
� Recta que passa nos pontos P1 e P2:
2 22 1 2 1( ) ( )x x y y− + −
y mx b= +
2 1
2 1
,y y
mx x
−=
−
1 1b y m x= −
João Miguel da Costa Sousa 257
Programa: Pontos e linhas (1)
PROGRAM Pontos_e_Linhas
!----------------------------------------------------------------------------------
! Programa que le dois pontos P1 e P2 representados como estruturas, calcula a
! distancia entre P1 e P2 e calcula a equacao da recta unindo os dois pontos.
! Identificadores usados:
! Ponto : ficha representada em 2 dimensoes! P1, P2 : dois pontos a ser processados! Distancia : funcao que calcula distancia entre pontos
! EquacaoRecta : subrotina que calcula a equacao duma recta
! Resposta : resposta do utilizador
!
! Entradas: Coordenadas dos pontos P1 e P2
! Saidas: distancia entre 2 pontos e recta entre eles
!-----------------------------------------------------------------------------------
IMPLICIT NONE
TYPE PontoREAL :: X, Y
END TYPE Ponto
TYPE(Ponto) :: P1, P2CHARACTER(1) :: Resposta
DO
WRITE(*, ‘(1X, A)’, ADVANCE = “NO”) &“ Introduza as coordenadas dos pontos P1 e P2: ”
READ (*, *) P1%X, P1%Y, P2%X, P2%YWRITE(*,‘(1X,2(A,“(”,F5.2,“,”,F5.2,“)”), “ e ”, F5.2)’) &
“Distancia entre ”, P1%X, P1%Y, “ e ”, P2%X, P2%Y, &Distancia(P1, P2)
CALL EquacaoRecta(P1, P2)
6
João Miguel da Costa Sousa 258
Programa: Pontos e linhas (2)
WRITE(*, ‘(/ 1X, A)’, ADVANCE = “NO”) &
“Mais pontos (S ou N)? ”
READ(*, *) Resposta
IF (Resposta /= “S”) EXIT
END DO
CONTAINS
!--Distancia-----------------------------------------------
! Funcao que calcula a distancia entre os pontos P1 e P2
!
! Aceita: Estruturas P1 e P2 do tipo Ponto
! Retorna: Distancia entre P1 e P2
!----------------------------------------------------------
FUNCTION Distancia(P1, P2)TYPE(Ponto), INTENT(IN) :: P1, P2REAL :: Distancia
Distancia = SQRT((P2%X - P1%X)**2 + (P2%Y - P1%Y)**2)END FUNCTION Distancia
!--EquacaoRecta--------------------------------------------
! Subrotina que calcula a equacao da recta y = mx + b da
! linha que passa nos pontos P1 e P2. Variaveis locais:
! M : declive da recta
! B : interseccao da recta com o eixo dos yy
! Aceita: Estruturas P1 e P2 do tipo Ponto
! Retorna: Escreve equacao da recta que passa em P1 e P2
!----------------------------------------------------------
João Miguel da Costa Sousa 259
Programa: Pontos e linhas (3)
SUBROUTINE EquacaoRecta(P1, P2)TYPE(Ponto), INTENT(IN) :: P1, P2REAL :: M, B
IF (P1%X == P2%X) THENWRITE (*, ‘(1X, A, F5.2)’) “Linha vertical x = ”, P1%X
ELSEM = (P2%Y - P1%Y) / (P2%X - P1%X)B = P1%Y - M * P1%XWRITE (*, ‘(1X, 2(A, F5.2))’) “Equacao da recta e y = ”, M, “x + ”, B
END IFEND SUBROUTINE EquacaoRecta
END PROGRAM Pontos_e_Linhas
� Exemplo de execução:> Introduza as coordenadas dos pontos P1 e P2: 0,0 1,1
> Distancia entre ( 0.00, 0.00) e ( 1.00, 1.00) e 1.41
> Equacao da recta e y = 1.00x + 0.00
>
> Mais pontos (S ou N)? S
> Introduza as coordenadas dos pontos P1 e P2: 1,1 1,5
> Distancia entre ( 1.00, 1.00) e ( 1.00, 5.00) e 4.00
> Linha vertical x = 1.00
>
> Mais pontos (S ou N)? S
> Introduza as coordenadas dos pontos P1 e P2: 3.1,4.2 -5.3,7.2
> Distancia entre ( 3.10, 4.20) e (-5.30, 7.20) e 8.92
> Equacao da recta e y = -0.36x + 5.31
>
> Mais pontos (S ou N)? N
7
João Miguel da Costa Sousa 260
Exemplo: Tabela de utilizadores
� Pretende-se procurar um utilizador numa base de dados, e verificar a utilização dos seus recursos computacionais. � Um dado ficheiro deverá conter o apelido, nome, número de
identificação, recursos disponíveis e recursos utilizados, i.e.:
Babbage Charles 10101 ADA 7503 8081
Newton Isaac 10102 APPLE 6505 9884
Leibnitz Gottfried 10103 CALC 2501 9374
Fahreneit Freda 10104 FRZ32 2501 7793
Celsius Christine 10105 FRZ0 8501 9191
Tower Lean 10106 PISA 3502 2395
VanderVan Henry 10107 VAN 7501 6859
Yale Harvard 20125 IVY 1501 2770
� Dado um número de utilizador, pretende-se que o programa indique o seu nome, apelido e a percentagem dos recursos disponíveis já utilizados.
João Miguel da Costa Sousa 261
Ex: Registo Utiliz. Computadores
PROGRAM Registos_Utilizacao_Computadores
!--------------------------------------------------------------
! Este programa le numeros de identificacao do teclado,
! e procura numa base de dados se esse numero existe, e
! nesse caso retorna informacao sobre esse utilizador.
! Os identificadores usados sao os seguintes:
!
! Tp_Registo_Utilizacao : nome do tipo com informacao
! Nome_Ficheiro : nome do ficheiro com dados
! Estado_Abertura : variavel de estado para OPEN
! Estado_Leitura : variavel de estado para READ
! Utilizadores : tabela do Tp_Registo_Utilizacao
! Num_Utilizadores : numero de utilizadores
! Numero_Procurado : numero de id a procurar
! Localizacao : indice do utilizador procurado
! Encontrado : indica se a id procurada foi
! : ou nao encontrada
! Entradas : Numero_Procurado(teclado), Utilizadores(fich.)
! Saidas : Numero, nome e % de recursos computacionais
! utilizados, ou uma mensagem indicando que o numero
! nao foi encontrado.
!-----------------------------------------------------------------
IMPLICIT NONE
TYPE Tp_Registo_Utilizacao
CHARACTER(15) :: Nome, Apelido
INTEGER :: Numero_Identificacao
CHARACTER(6) :: Palavra_chave
REAL :: Recursos_Usados, Limite_Recursos
END TYPE Tp_Registo_Utilizacao
8
João Miguel da Costa Sousa 262
Registo Utiliz. Computadores
CHARACTER(20) :: Nome_Ficheiro
TYPE(Tp_Registo_Utilizacao), DIMENSION(20) :: Utilizadores
INTEGER :: Estado_Abertura, Estado_Leitura, i
INTEGER :: Num_Utilizadores, Numero_Procurado, Localizacao
LOGICAL :: Encontrado
! Le o nome do ficheiro com os registos e abre-o
WRITE(*,'(1X, A)',ADVANCE="NO") "Escreva o nome do ficheiro:"
READ (*, *) Nome_Ficheiro
OPEN (10, FILE = Nome_Ficheiro, STATUS = "OLD", &
IOSTAT = Estado_Abertura)
IF (Estado_abertura <= 0) THEN
i = 0
DO
i = i+1
READ(10,*,IOSTAT=Estado_Leitura) Utilizadores(i)%Apelido,&
Utilizadores(i)%Nome, &
Utilizadores(i)%Numero_Identificacao, &
Utilizadores(i)%Palavra_chave, &
Utilizadores(i)%Recursos_Usados, &
Utilizadores(i)%Limite_Recursos
IF (Estado_Leitura<0) EXIT ! Fim do fiheiro
END DO
Num_Utilizadores = i-1
João Miguel da Costa Sousa 263
Registo Utiliz. Computadores
DO ! Procura numero identificacao
WRITE(*,*)
WRITE(*,'(1X,A)',ADVANCE="NO") "Escreva o numero de &
&utilizador (0 para parar): "
READ (*,*) Numero_Procurado
IF (Numero_Procurado /= 0) THEN
CALL Procura_Numero(Utilizadores(1:Num_Utilizadores), &
Numero_Procurado,Encontrado,Localizacao)
IF (Encontrado) THEN
WRITE(*,'(1X, I5, 1X, 2A)') &
Utilizadores(Localizacao)%Numero_Identificacao, &
Utilizadores(Localizacao)%Nome, &
Utilizadores(Localizacao)%Apelido
WRITE(*,'(1X, "utilizou", F5.1, "% de recursos")') &
100.0 * Utilizadores(Localizacao)%Recursos_Usados &
/ Utilizadores(Localizacao)%Limite_Recursos
ELSE
WRITE(*,*) Numero_Procurado, " nao encontrado."
END IF
END IF
! Se utilizador indicar, acaba o ciclo.
IF (Numero_Procurado == 0) EXIT
END DO
ELSE
WRITE(*,*) "Erro na abertura de ficheiro!!"
END IF
9
João Miguel da Costa Sousa 264
Registo Utiliz. Computadores
CONTAINS
!-Procura_Numero—(...)------------------------------------
SUBROUTINE Procura_Numero(Utilizadores, NumProcurado, Encontrado, Local)
TYPE(Tp_Registo_Utilizacao), DIMENSION(:) :: Utilizadores
INTEGER,INTENT(IN) :: NumProcurado
INTEGER,INTENT(OUT) :: Local
LOGICAL,INTENT(OUT) :: Encontrado
INTEGER :: NumUtilizadores
NumUtilizadores = SIZE(Utilizadores)
Local = 1
Encontrado = .FALSE.
DO
IF ((Local > NumUtilizadores) .OR. Encontrado) EXIT
IF (NumProcurado== &
Utilizadores(Local)%Numero_Identificacao) THEN
Encontrado = .TRUE.
ELSE
Local = Local + 1
END IF
END DO
END SUBROUTINE Procura_Numero
END PROGRAM Registos_Utilizacao_Computadores
João Miguel da Costa Sousa 265
Exemplo de execução
> Escreva o nome do ficheiro: dados.dat
>
> Escreva o numero de utilizador (0 para parar): 10101
> 10101 Charles Babbage
> utilizou 92.8% de recursos
>
> Escreva o numero de utilizador (0 para parar): 10103
> 10103 Gottfried Leibnitz
> utilizou 26.7% de recursos
>
> Escreva o numero de utilizador (0 para parar): 20125
> 20125 Harvard Yale
> utilizou 54.2% de recursos
>
> Escreva o numero de utilizador (0 para parar): 10200
> 10200 nao encontrado
>
> Escreva o numero de utilizador (0 para parar): 10102
> 10102 Isaac Newton
> utilizou 65.8% de recursos
>
> Escreva o numero de utilizador (0 para parar): 0
10
João Miguel da Costa Sousa 266
Outros tipos de dados
� Tipos de dados parametrizados� Inteiros em Fortran: 32 bits de -2 147 483 648 a +2 147 483 647
� Reais em Fortran: 32 bits -1038 a 1038 aprox. (precisão simples)
� Estes limites podem ser inadequados; podem ser necessária maior ou menor precisão.
� Estas alterações são dadas por tipos de dados parametrizados.
� Tipo COMPLEX� a + bi, onde a e b são números reais e� i2 = -1
� Tipo CHARACTER� processamento avançado de cadeias de caracteres
João Miguel da Costa Sousa 267
Tipos de dados parametrizados
� Representação de números é aproximada� Reais não são representados exactamente
� Exemplo: equação que retorna sempre 1:
A B AB B
A
A
A
+ − −= =
a f2 2
2
2
2
21
PROGRAM Demo_1
IMPLICIT NONE
REAL :: A, B, C
READ (*, *) A, B
C = ((A + B)**2 - 2.0*A*B - B**2) / A**2
WRITE (*,*) C
END PROGRAM Demo_1
A B C
0.1 888.0 1.0000000 1e-4 888.0 1.001166 1e-5 888.0 1.163585 2e-6 888.0 -1.421085E–02 1.1e-10 888.0 9.616402E+09
11
João Miguel da Costa Sousa 268
Declaração de tipos parametrizados
Tipos parametrizados____________________________________________________________________
Forma:
especificador_tipo(KIND = numero-tipo) :: lista
ouespecificador_tipo(numero-tipo) :: lista
� o especificador_tipo é em geral:INTEGER
REAL
COMPLEX
LOGICAL
� o numero-tipo é um inteiro positivo (constante) com valor positivo;� os atributos são atributos opcionais;� a lista é uma lista de identificadores.
� Declara que os identificadores na lista têm o tipo e o numero-tipoespecificado.
João Miguel da Costa Sousa 269
Tipos parametrizados (concl.)
� Os números-tipo dependem da máquina e do compilador. Reais mais utilizados:
Tipo NúmeroTipo Descrição REAL 4 Valores com precisão simples com aproximadamente 7
dígitos significativos; armazanados em 32 bits REAL 8 Valores com precisão dupla com aproximadamente 14
dígitos significativos; armazanados em 64 bits
� Exemplo:
REAL(KIND = 4) :: Z
REAL(8), DIMENSION(5,5) :: Beta
� Inteiros em PowerStation:Tipo NúmeroTipo Descrição INTEGER 1 Inteiros de 8 bits: -27 até 27 - 1 INTEGER 2 Inteiros de 16 bits: -215 até 215 - 1 INTEGER 4 Inteiros de 64 bits: -263 até 263 - 1
12
João Miguel da Costa Sousa 270
Tipo de dados COMPLEX
� Tipo COMPLEX� a + bi, onde a e b são reais. Em Fortran:
(a, b)
� Declarações de complexosCOMPLEX :: A, B
COMPLEX, DIMENSION(10,10) :: Rho
� Operações com complexos� Soma
� Subtração
� Produto
� Divisão
z a bi w c di= + = +e
z w a c b d i+ = + + +( ) ( )
z w a c b d i− = − + −( ) ( )
z w ac bd ad bc i⋅ = − + +( ) ( )
z
w
ac bd
c d
bc ad
c di=
+
+
+−
+2 2 2 2
João Miguel da Costa Sousa 271
Tipo complexo (exemplos)
� Exemplo de operações (C e Z variáveis complexas):C = (6.2, 2.4)
Z = 4.0 * C / 2
� retorna para Z o valor:
(12.4, 4.8)
� Se for atribuída a X do tipo real: X = 4.0 * C/2, retorna o valor 12.4� Se for atribuída a N do tipo inteiro: N = 4.0 * C/2, retorna o valor 12
� Funções complexas intrínsecas:� ABS(z)
� CONJG(z)
� EXP(z)
� AIMAG(z)
� CMPLX(x, y)
� REAL(z)
13
João Miguel da Costa Sousa 272
Entrada e saída de complexos
� Complexos são lidos como um par de reais ou 2 reaisPROGRAM Demo_2
IMPLICIT NONE
COMPLEX :: X, Y, W, Z, A
READ(*, *) X, Y
READ(*, ‘(2F2.0)’) W
WRITE(*, *) X, Y
WRITE(*, *) W
WRITE(*, 10) X, Y, W
10 FORMAT(1X, F5.2, “ +”, F8.2, “I”)
Z = (X + Y) / (1.0, 2.2)
A = X * Y
WRITE(*, 10) Z, A
END PROGRAM Demo_2
� Entrada de dados:> (3,4), (0.75, -2.23)
> 5 7
� Saída produzida:> ( 3.0000000, 4.0000000) ( 0.7500000, -2.2300000)
> ( 5.0000000, 7.0000000)
> 3.00 + 4.00I
> 0.75 + -2.23I
> 5.00 + 7.00I
> 1.31 + -1.11I
> 11.17 + -3.69I
João Miguel da Costa Sousa 273
O tipo CHARACTER
� Cadeia de caracteres vazia� “” ou ‘’
� Compilador associa cada variável a um endereço em memória. Nomes das variáveis são identificadores.
Declaração de cadeias de caracteres___________________________________________________________
CHARACTER(LEN = n) :: lista
ouCHARACTER(n) :: lista
� Exemplo:CHARACTER(LEN = 15) :: Nome, Apelido
CHARACTER(15) :: Nome
� Em subprogramas os argumentos formais podem ser pré-definidos:CHARACTER(*) :: lista_identificadores
14
João Miguel da Costa Sousa 274
Operacões com caracteres
� Caracteres podem ser parametrizados:CHARACTER(LEN=n, KIND=num_tipo) :: lista
CHARACTER(n, KIND=num_tipo) :: lista
CHARACTER(n, num_tipo) :: lista
CHARACTER(KIND=num_tipo, LEN=n) :: lista
CHARACTER(KIND=num_tipo) :: lista
� onde o num_tipo especifica o esquema de codificação (ASCII, EBCDIC, etc.) e/ou o tipo de caracteres (Inglês, Português, Russo, etc.)
� Concatenação de caracteres: operador binário dado por //� Exemplo 1
“centi” // “metros” produz:“centimetros”
� Exemplo 2CHARACTER(7) :: UnidadeQuadrada
UnidadeQuadrada = “ quadrados”
“centi” // “metros” // UnidadeQuadrada
produz:“centimetros quadrados”
João Miguel da Costa Sousa 275
Subcadeias de caracteres
� Exemplo: subcadeia dos caracteres 6 a 10 deUnidade = “centimetros”
é dada por:Unidade(6:10) e tem o valor: “metro”
� As primeiras e últimas posições não necessitam de ser especificadas.� Exemplo:
CHARACTER(15) :: Curso, Nome*20
Curso = “Engenharia”
Curso(:3) tem o valor “Eng” eCurso(8:) tem o valor “ria____”,
onde “_” corresponde a um espaço em branco.� A primeira posição deve ser positiva, e a última >= que a primeira, mas não
maior que o comprimento da cadeia de caracteres.� Podem ser efectuadas atribuições a sub-cadeias, modificando parte de uma
cadeia de caracteres.
15
João Miguel da Costa Sousa 276
Funções com caracteres
� Funções de cadeias para cadeias:� ADJUSTL(cad_caracteres)
� ADJUSTR(cad_caracteres)
� REPEAT(cad_caracteres, n)
� TRIM(cad_caracteres)
� Exemplo:CHARACTER(10) :: Cadeia = “ ABCDE”
� A saída produzida por:WRITE(*, *) “***”, Cadeia, “***”
WRITE(*, *) “***”, ADJUSTL(Cadeia), “***”
WRITE(*, *) “***”, ADJUSTR(Cadeia), “***”
WRITE(*, *) “***”, TRIM(Cadeia), “***”
WRITE(*, *) “***”, REPEAT(Cadeia,3), “***”
� é a seguinte:>*** ABCDE ***
>***ABCDE ***
>*** ABCDE***
>*** ABCDE***
>*** ABCDE ***
>*** ABCDE ABCDE ABCDE ***
João Miguel da Costa Sousa 277
Funções com caracteres (cont.)
� Funções de comprimento:� LEN(cad_caracteres)
� LEN_TRIM(cad_caracteres)
� Exemplo:CHARACTER(10) :: Cadeia = “ ABCDE”
O valor retornado por:LEN(Cadeia) retorna 10, eLEN_TRIM(Cadeia) retorna 6.
� Funções de procura:� INDEX(cadeia1, cadeia2) ou� INDEX(cadeia1, cadeia2, atras)
� SCAN(cadeia1, cadeia2) ou� SCAN(cadeia1, cadeia2, atras)
� VERIFY(cadeia1, cadeia2) ou� VERIFY(cadeia1, cadeia2, atras)
16
João Miguel da Costa Sousa 278
Exemplo com funções de procura
� Exemplo:CHARACTER(25) :: Unidades = “centimetros e metros”
� A saída produzida por:WRITE(*, *) INDEX(Unidades, “metros”)
WRITE(*, *) INDEX(Unidades, “metros”, .FALSE.)
WRITE(*, *) INDEX(Unidades, “metros”, .TRUE.)
WRITE(*, *) INDEX(Unidades, “cents”)
WRITE(*, *) SCAN(“kilometro”, Unidades)
WRITE(*, *) SCAN(“kilometro”, Unidades, .FALSE.)
WRITE(*, *) SCAN(“kilometro”, Unidades, .TRUE.)
WRITE(*, *) SCAN(“flora”, Unidades)
WRITE(*, *) VERIFY(“kilometro”, Unidades)
WRITE(*, *) VERIFY(“kilometro”, Unidades, .FALSE.)
WRITE(*, *) VERIFY(“kilometro”, Unidades, .TRUE.)
WRITE(*, *) VERIFY(“tenis”, Unidades)
� é a seguinte:> 6
> 6
> 15
> 0
> 2
> 2
> 9
> 3
> 1
> 1
> 3
> 0
João Miguel da Costa Sousa 279
Gestão de memória em tabelas
� Instruções ALLOCATE e DEALLOCATE utilizam memória quando o programa corre.� permitem utilizar apenas a memória necessária� evitam desperdício de memória� eficientes para tabelas com tamanho constante
� Para dados de diferentes tamanhos, quando se varia o tamanho da tabela efectuam-se as seguintes operações:� Uma nova tabela é alocada.� Os elementos da tabela antiga são copiados para a tabela nova.� Os novos elementos são introduzidos na nova tabela.� A tabela antiga é apagada da memória.
� Estas operações demoram bastante tempo!
17
João Miguel da Costa Sousa 280
Ponteiros
� As tabelas (mesmo alocadas) são estruturas de dados
estáticas.
� Estruturas de dados dinâmicas permitem expandir ou contrair a estrutura durante a execução.� É constituída por uma colecção de elementos, chamados nós ligados
entre si.
� Esta ligação associa a cada nó um ponteiro para o próximo nó da estrutura.
� Exige a necessidade de alocar e aceder à memória durante a execução dum programa.
� Variáveis que apontam para essas localizações em memória: ponteiros.
� Exemplo: Lista ligadaProx Prox ProxDados Dados Dados
XXX YYY ZZZLista
João Miguel da Costa Sousa 281
Listas implementadas em tabelas
� Tabelas podem implementar listas. São ineficientes para:� tamanhos variáveis durante a execução,
� inserir e retirar elementos na lista.
� Cada vez que elementos novos são inseri-dos dever-se-á mover elementos na tabela.
� Exemplo 1: Inserir 42 na lista 23, 25, 34, 48, 61, 89. Os elementos 4 a 6 devem ser deslocados para as posições 5 a 7, para o novo elemento ser introduzido em 4:
� Exemplo 2: Retirar 25 da lista:
23 25 34 48 61 89 ? ... ?
23 25 34 42 48 61 89 ... ?
23 34 42 48 61 89 ? ... ?
23 25 34 42 48 61 89 ... ?
18
João Miguel da Costa Sousa 282
Listas ligadas
� Contém uma colecção de elementos chamados nós, que contêm:1. um elemento da lista,
2. um ponteiro para o nó seguinte. O acesso ao nó inicial (1º elemento da lista) deve ser mantido.
� Exemplo: lista com nomes Silva, Fonseca e Castro
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
� A variável Lista aponta para o primeiro nó da lista, e o Prox aponta para o próximo nó.
� O símbolo “terra” não aponta para nada, indicando assim o fim da lista (ponteiro vazio ou null pointer).
João Miguel da Costa Sousa 283
Inserção de elementos em listas
� Nas listas ligadas não é necessário mover elementos quando se altera a lista.
� Para inserir um novo elemento na lista:
1. Criar um novo nó. Guardar o valor a inserir no elemento do nó (pressupõe-se que é possível obter nós duma dada fonte, e que estão nós disponíveis)
2. Ligar o novo nó à lista. Podem existir 2 casos:� o nó é acrescentado no início da lista;
� o nó é inserido no meio da lista.
19
João Miguel da Costa Sousa 284
Exemplo: inserção em listas
� Exemplo 1: inserir o nome Reis no início da lista� Criar um nó com o nome Reis. O ponteiro NovoPont aponta para este nó.
� O nó é inserido na lista, com a sua ligação a apontar para o primeiro nó na lista; o Prox de NovoPont aponta para o mesmo que Lista:
ProxDados
ReisNovoPont
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
� Ao ponteiro Lista é atribuído NovoPont:
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
ProxDados
ReisNovoPont
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
ReisNovoPont
João Miguel da Costa Sousa 285
Exemplo 2: inserção em listas
� Exemplo 2: inserir nome Ramos após Fonseca, onde PontPredé o ponteiro predecessor:
� Criar um nó com o nome Ramos (como anteriormente):
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
PontPred
ProxDados
RamosNovoPont
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
PontPred
20
João Miguel da Costa Sousa 286
Exemplo 2: inserção em listas
� Prox de NovoPont igual a Prox de PontPred
� Prox de PontPred igual a NovoPont:
ProxDados
RamosNovoPont
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
PontPred
ProxDados
RamosNovoPont
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
PontPred
João Miguel da Costa Sousa 287
Apagar elementos de listas
� Tal como na inserção existem 2 casos:1. apagar o primeiro elemento da lista;
2. apagar um elemento com um predecessor.
� Exemplo: para apagar o nome Silva no início da lista basta passar Lista para o segundo nó.
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
PontAux
� Atribui a PontAux o ponteiro Lista.
21
João Miguel da Costa Sousa 288
Apagar elementos de listas
� Atribui a Lista o Prox de PontAux.
� Ponteiro PontAux enviado para pilha de livres.
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
PontAux
Prox ProxDados Dados
Fonseca CastroLista
PontAux
João Miguel da Costa Sousa 289
Apagar elementos de listas
� Exemplo 2: apagar o nome Fonseca da lista inicial.
� Atribui ao ponteiro PontAux o ponteiro Prox de PontPred.
� Atribui a Prox de PontPred o ponteiro Prox de PontAux.
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
PontPred PontAux
� Coloca o ponteiro PontAux na pilha de ponteiros disponíveis.
Prox Prox ProxDados Dados Dados
Silva Fonseca CastroLista
PontPred PontAux
Prox ProxDados Dados
Silva CastroLista
PontPred PontAux
22
João Miguel da Costa Sousa 290
Ponteiros em Fortran
Variáveis do tipo ponteiro_____________________________________________________________________________________________________________________
Forma:
tipo, lista-atributos, POINTER :: var_ponteiro
� Declara a variável var_ponteiro, usada para aceder a localizações em memória.
� A variável tem um dado tipo onde os atributos podem ser guardados.
� Exemplo 1: Um ponteiro para cadeias de caracteres é definido como:CHARACTER(10), POINTER :: PontCadeia
� Esta variável só pode ser utilizada para aceder a localizações em memória com 10 caracteres.
� Exemplo 2TYPE :: Info_Inventario
INTEGER :: Numero
REAL :: Preco
END TYPE Info_Inventario
TYPE(Info_Inventario), POINTER :: PontInventario
João Miguel da Costa Sousa 291
Criação de ponteiros
Instrução ALLOCATE_______________________________________________________________________________________
Forma:
ALLOCATE(ponteiro)
� Exemplo: ALLOCATE(PontCadeia)
� O ponteiro PontCadeia “aponta” para uma localização em memória, chamada alvo, com uma cadeia de caracteres (e.g. “computador”)
PontCadeia Computador
� Estados de associação de ponteiros:1. Indefinido - estado inicial após declaração.2. Associado - quando aponta para um alvo.
ponteiro ?
3. Vazio - null pointer; não aponta para nada.
ponteiro
23
João Miguel da Costa Sousa 292
Associação de ponteiros
� Função de teste ASSOCIATEDASSOCIATED(ponteiro)
� Retorna .TRUE. se o ponteiro está associado e .FALSE. caso contrário. O ponteiro não pode estar indefinido.
� Comando NULLIFYNULLIFY(ponteiro)
� Torna o ponteiro vazio. A localização em memória não é acessível.
� Programa dispõe de uma pilha de memória disponível. Instrução ALLOCATE executa:1. Retira um bloco de memória livre da pilha.2. Aloca esse espaço ao programa executável.
� Pilha de memória é limitada:ALLOCATE(lista, STAT = variavel-inteira)
DEALLOCATE(lista, STAT = variavel-inteira)
João Miguel da Costa Sousa 293
Atribuição de ponteiros
Forma: ponteiro1 => ponteiro2
� O ponteiro1 tem a mesma associação do ponteiro2. O valor anterior de ponteiro1 não é acessível, a não ser que estivesse outro ponteiro a apontar para a mesma localização.
� Antes da atribuição:ponteiro1
ponteiro2
ponteiro3
� Após a atribuição ponteiro1 => ponteiro2:
� Exemplo:CHARACTER(8), POINTER :: PontCadeia, PontTemp
� onde PontTemp aponta para “software” e PontCadeia aponta para “hardware”. Qual o resultado da instrução:
PontTemp => PontCadeia ?
ponteiro1
ponteiro2
ponteiro3
24
João Miguel da Costa Sousa 294
Expressões com ponteiros
� Regra básica: Quando um ponteiro associado aparece numa expressão, é utilizado directamente o valor para o qual está a apontar.
� Exemplo:CHARACTER(10), POINTER :: PontCadeia
CHARACTER(10) :: Produto = “Computador”
PontCadeia = Produto ePontCadeia = “Computador”
� retornam:PontCadeia Computador
WRITE(*, *) PontCadeia eIF PontCadeia(2:4) == “omp” THEN
WRITE(*, *) PontCadeia
END IF
� imprimem:> Computador
PontTemp = PontCadeia
PontCadeia Computador
PontTemp Computador
João Miguel da Costa Sousa 295
Implementação de listas ligadas
� é definida como:TYPE Lista_Nos
INTEGER :: Dados
TYPE(Lista_Nos), POINTER :: Proximo
END TYPE Lista_Nos
� Construção de uma lista ligadaTYPE(Lista_Nos), POINTER :: ListaNumeros, PontTemp
ALLOCATE(PontTemp)
PontTemp%Dados = 1550
PontTemp%Proximo => ListaNumeros
ListaNumeros => PontTemp
� Para construir toda a lista, a primeira instrução seria:NULLIFY(ListaNumeros)
Prox Prox ProxDados Dados Dados
1550 1723 1996ListaNumeros
25
João Miguel da Costa Sousa 296
Listas ligadas
� Percorrer uma lista ligada, escrevendo todos os seus elementosPontActual => ListaNumeros
DO
IF (.NOT. ASSOCIATED(PontActual)) EXIT ! Fim da lista
WRITE (*, *) PontActual%Dados
PontActual => PontActual%Proximo
END DO
� Inserir elemento no meio da listaALLOCATE(PontTemp, STAT = EstadoAlocacao)
PontTemp%Dados = ElementoNovo
� Inserir elemento entre PontPred e PontActual:PontTemp%Proximo => PontActual
PontPred%Proximo => PontTemp
João Miguel da Costa Sousa 297
Apagar elementos em listas ligadas
� Apagar elementos na lista� Apagar elementos no início da lista
PontActual => Lista
Lista => PontActual%Proximo
DEALLOCATE(PontActual)
� Apagar o elemento apontado por PontActual precedido por PontPredmeio da listaPontPred%Proximo => PontActual%Proximo
DEALLOCATE(PontActual)
26
João Miguel da Costa Sousa 298
Aplicação: Endereços Internet
� Protocolos de comunicação� TCP (Transmission Control Protocol)� IP (Internet Protocol)
� TCP/IP identification endereços únicos na Internet. � Exemplo:
dem.ist.utl.pt
� endereço do Dep. Eng. Mecânica do IST
� Os 4 campos correspondem a:host.subdomain.subdomain.rootdomain
� Estes endereços são dados por inteiros:193.136.128.2
João Miguel da Costa Sousa 299
Problema: Acesso à Internet
� Uma porta de acesso é um sistema de ligação entre duas redes de computadores.� Exemplo: ligação de uma Universidade com a Internet.� Cada vez que um estudante acede à WWW o seu endereço TCP/IP é
guardado num ficheiro.
� Problema: O administrador do sistema pretende verificar periodicamente quem e quantas vezes acedeu à Internet.
� Solução:� Entrada: O ficheiro contendo os endereços TCP/IP� Saída: Uma lista com os diferentes endereços e o número de vezes que
aparecem no ficheiro� Existem 232 possibilidades de endereços, logo uma estrutura estática, tal
como uma tabela, não é eficiente.
27
João Miguel da Costa Sousa 300
Algoritmo: Acesso à Internet
� Identificadores� NomeFicheiro – nome do ficheiro� Endereco – o endereço TCP/IP� ListaEnderecos – lista ligada de endereços
Algoritmo
� Este algoritmo encontra endereços TCP/IP gravados num ficheiro eo número de vezes que ocorrem.
� Entrada: NomeFicheiro – ficheiro contendo os endereços TCP/IP.� Saída: Lista com os endereços e o número de vezes que aparecem
no ficheiro.1. Lê o nome do ficheiro e abre-o para leitura. Se o ficheiro não fôr
aberto acaba o programa.2. Inicializa a ListaEnderecos como lista vazia.
João Miguel da Costa Sousa 301
Algoritmo: Acesso à Internet (2)
3. Repete o seguinte:a) Lê um endereço do ficheirob) Se existe erro de leitura escreve mensagem de erro.c) Caso contrário:d) Se não há mais endereços termina o ciclo.e) Caso contrário:
i. Procura na ListaEnderecos se Endereco está contido na lista.ii. Se endereço já existe
Incrementa contador desse Endereco
Caso contrárioInsere novo endereço na lista, com contador a 1.
4. Atravessa ListaEnderecos e escreve cada TCP/IP e o valor do seu contador.
28
João Miguel da Costa Sousa 302
Programa: Enderecos_Internet
PROGRAM Enderecos_Internet
!--------------------------------------------------------------------------------------
! Este programa le enderecos TCP/IP de um ficheiro e produz uma lista de enderecos
! distintos indicando quantas vezes esses enderecos aparecem no ficheiro.
! Variáveis usadas:
!
! Nome_Ficheiro : nome do ficheiro com enderecos
! Estado_Abertura : variavel de estado para OPEN
! Estado_Leitura : variavel de estado para READ
! Endereco : endereco lido do ficheiro
! ListaEnderecos : ponteiro para o primeiro no da
! Lista de enderecos
!
! Subrotinas utilizadas para processar listas:
! Adiciona_Lista, Procura, Enderecos_saida
!
! Entradas : NomeFicheiro(teclado), Enderecos (ficheiro)
! Saidas : Lista com enderecos distintos e numero de ocorrencias.
!---------------------------------------------------------------------------------------
IMPLICIT NONE
!Definicao do tipo no-endereco
TYPE Lista_No
CHARACTER(15) :: Endereco_TCP_IP !Dados endereco
INTEGER :: Contador !Contador desse endereco
TYPE(Lista_No), POINTER :: Prox !Ponteiro para prox. no
END TYPE Lista_No
João Miguel da Costa Sousa 303
Programa: Enderecos_Internet
CHARACTER(15) :: Endereco, Nome_Ficheiro*20
INTEGER :: Estado_Abertura, Estado_Leitura
TYPE(Lista_No), POINTER :: ListaEnderecos
! Le o nome do ficheiro com os registos e abre-o
WRITE(*,'(1X, A)',ADVANCE="NO") "Escreva o nome do ficheiro:"
READ (*, *) Nome_Ficheiro
OPEN (10, FILE = Nome_Ficheiro, STATUS = "OLD", &
IOSTAT = Estado_Abertura)
IF (Estado_abertura > 0) THEN
WRITE(*, *) “*** Ficheiro de enderecos invalido ***”
ELSE
!Cria uma lista de enderecos vazia
NULLIFY(ListaEnderecos)
!Le enderecos do ficheiro ate ao fim do ficheiro
DO
READ(10,*,IOSTAT=Estado_Leitura) Endereco
IF (Estado_Leitura<0) EXIT ! Fim do ficheiro
CALL Adiciona_a_Lista(ListaEnderecos,Endereco)
END DO
END IF
CALL Escreve_Enderecos(ListaEnderecos)
29
João Miguel da Costa Sousa 304
Subrotina: Adiciona_a_Lista
CONTAINS
!------------------------------------------------------------------------------------
! Esta subrotina verifica se Endereco ja se encontra na lista ligada (utilizando
! Procura). Se nao, Endereco e acrescentado no inicio da lista. Se sim, o contador
! e incrementado de 1 elemento. Variaveis locais:
! EstadoAlocacao : estado da instrucao OPEN
! PontLocal : pont. para o no com Endereco, ou vazio
! Esta_na_Lista : indica se Endereco se encontra na
! ListaEnderecos
!
! Recebe: ListaEnderecos e Endereco
! Retorna: ListaEnderecos modificada
!-------------------------------------------------------------------------------------
SUBROUTINE Adiciona_a_Lista(ListaEnderecos,Endereco)
TYPE(Lista_No), POINTER :: ListaEnderecos
CHARACTER(*), INTENT(IN) :: Endereco
TYPE(Lista_No), POINTER :: PontLocal
INTEGER :: EstadoAlocacao
LOGICAL :: Esta_na_Lista
IF (.NOT. ASSOCIATED(ListaEnderecos)) THEN !Lista vazia
ALLOCATE(ListaEnderecos, STAT = EstadoAlocacao)
IF (EstadoAlocacao /= 0) THEN
WRITE(*, *) “*** Nao ha memoria disponivel! ***”
ELSE
ListaEnderecos%Endereco_TCP_IP = Endereco
ListaEnderecos%Contador = 1
NULLIFY(ListaEnderecos%Prox)
END IF
João Miguel da Costa Sousa 305
Subrotinas de Enderecos_Internet
ELSE !Lista nao vazia; determina se Endereco ja existe
CALL Procura_em_Lista(ListaEnderecos,Endereco, &
PontLocal,Esta_na_Lista)
IF (Esta_na_Lista) THEN ! Incrementa contador de um
PontLocal%Contador = PontLocal%Contador + 1
ELSE !Cria um novo no e insere-o no inicio da lista
ALLOCATE(PontLocal, STAT = EstadoAlocacao)
IF (EstadoAlocacao /= 0) THEN
WRITE(*, *) “*** Nao ha memoria disponivel! ***”
ELSE
PontLocal%Endereco_TCP_IP = Endereco
PontLocal%Contador = 1
PontLocal%Prox => ListaEnderecos
ListaEnderecos => PontLocal
END IF
ENDIF
ENDIF
END SUBROUTINE Adiciona_a_Lista
!----------------------------------------------------------------------------------
! Esta subrotina procura na ListaEnderecos por um no contendo Endereco. Se este
! endereco for encontrado, o ponteiro PontLocal aponta para o no com Endereco, e
! Esta_na_Lista retorna verdadeiro; caso contrario PontLocal e vazio (NULL) e
! Esta_na_Lista falso.
!
! Recebe: ListaEnderecos e Endereco
! Retorna: PontLocal, Esta_na_Lista
!--------------------------------------------------------------------------------------
SUBROUTINE Procura_em_Lista(ListaEnderecos, Endereco, PontLocal, Esta_na_Lista)
30
João Miguel da Costa Sousa 306
Subrotina: Procura_em_Lista
SUBROUTINE Procura_em_Lista(ListaEnderecos, Endereco, PontLocal, Esta_na_Lista)
TYPE(Lista_No), POINTER :: ListaEnderecos, PontLocal
CHARACTER(*), INTENT(IN) :: Endereco
LOGICAL, INTENT(OUT) :: Esta_na_Lista
PontLocal => ListaEnderecos
Esta_na_Lista = .FALSE.
! Percorre a lista ate encontrar endereco ou ate ao fim
DO
IF(Esta_na_Lista .OR. .NOT. ASSOCIATED(PontLocal)) EXIT
! Endereco nao encontrado ou fim da lista termina ciclo
IF (PontLocal%Endereco_TCP_IP == Endereco) THEN
Esta_na_Lista = .TRUE.
ELSE ! Procura no proximo elemento
PontLocal => PontLocal%Prox
END IF
END DO
END SUBROUTINE Procura_em_Lista
João Miguel da Costa Sousa 307
Subrotina: Enderecos_Saida
!----------------------------------------------------------------------------------
! Esta subrotina escreve o conteudo da lista ligada apontada por ListaEnderecos.
! Imprime o endereco e o contador de cada no.
! Variveis locais:
! PontAux : ponteiro que percorre a lista
!
! Recebe: ListaEnderecos
! Saida: Escreve endrecos e contador nos nos
!------------------------------------------------------------------------------------
SUBROUTINE Escreve_Enderecos(ListaEnderecos)
TYPE(Lista_No), POINTER :: ListaEnderecos, PontAux
PontAux => ListaEnderecos
WRITE(*, *)
WRITE(*, *) "Enderecos de Internet"
WRITE(*, *)
WRITE(*, *) " Endereco Contador "
WRITE(*, *) "------------------------------"
! Escreve informacao nos nos ate ao fim da lista
DO
IF (.NOT. ASSOCIATED(PontAux)) EXIT
WRITE(*,‘1X, A, 4X, I4’) PontAux%Endereco_TCP_IP, PontAux%Contador
PontAux => PontAux%Prox
END DO
END SUBROUTINE Escreve_Enderecos
END PROGRAM Enderecos_Internet
31
João Miguel da Costa Sousa 308
Resultados
� Ficheiro exfic.dat:128.159.4.20
123.111.222.33
100.1.4.31
34.56.78.90
120.120.120.120
128.159.4.20
123.111.222.33
123.111.222.33
77.66.55.44
100.1.4.31
123.111.222.33
128.159.4.20
� Exemplo de execução:> Escreva o nome do ficheiro: exfic.dat
>
> Endereco Contador
> ---------------------------
> 77.66.55.44 1
> 120.120.120.120 1
> 34.56.78.90 1
> 100.1.4.31 2
> 123.111.222.33 4
> 128.159.4.20 3