1 Topicos de C

Fazer download em pdf ou txt
Fazer download em pdf ou txt
Você está na página 1de 49

Introdução à Linguagem C

(Tópicos)
Conteúdos

1- Algoritmos
2- Introdução à Linguagem C & Estruturas de Controlo
3- Funções
4- Vectores e Matrizes
5- Apontadores (Ponteiros)
6- Estruturas de dados
7- Ficheiros
Programação Cap. 1

1 Capítulo 1. - Algoritmos

1 – Análises preliminar de programação

Programação

- Planificação, projecção e execução de uma tarefa com sucesso.

Programação de um computador

- É um processo de planificar uma sequência de instruções que o computador deve


seguir, com vista a executar uma determinada tarefa.
- Duas fases: Resolução e Implementação.

Fase de Resolução do problema


- Análise – Compreender (definir) o problema.
- Solução geral (Algoritmo) – desenrolar de uma sequência lógica de
passos utilizados para resolver o problema.
- Prova – seguir a sequência de passos anteriormente determinada para ver
se a solução resolve verdadeiramente o problema.

Fase de Implementação
- Solução específica (programa) – Traduzir o algoritmo numa linguagem
de programação específica: Pascal, C Basic, java, Cobol, ...
- Prova – Fase em que o computador segue as instruções. Comprovar os
resultados e fazer as correcções se necessário.
- Uso – utilizar o programa.

Algoritmo – é uma sequência ordenada e precisa de passos, acções ou operações,


que conduzem à solução de um dado problema.
- Total ausência de ambiguidade, ou seja, a interpretação dada ao algoritmo
é sempre a mesma, independente da leitura que dele se faça.
- Número finito de acções.
- Generalidades.

Exemplos: receitas de cozinha , instruções para instalar uma impressora, etc.

DEI E.S.T.G./I.P.Leiria 1
Programação Cap. 1

Algoritmo para por a arrancar um carro:


1- Colocar a chave na ignição
2- Assegurar que o carro está em ponto morto
3- Dar à chave para a posição de arranque
4- Se o motor arranca antes de 6 segundos, pode-se começa a andar
5- Se o motor não arranca antes dos 6 segundos esperar 10 segundos e repetir
os passos desde o 3 até ao 5 (mas não mais do que cinco vezes)
6- Se o carro não arranca chamar um mecânico.

EX: Qual é o algoritmo para calcular o salário semanal de um empregado?

Após ter o algoritmo há que transcrevê-lo para a linguagem de programação escolhida –


trata-se da operação de codificação.

Linguagem de programação:
- Conjunto de regras, símbolos e palavras especiais utilizados para construir um
programa.
- Composição:
o Uma terminologia ou conjunto de termos, palavras e sinais, que assumem
determinados significados (semântica);
o Um conjunto de regras que estipulam o uso correcto dos termos, para
construir enunciações válidas (sintaxe).

Estratégias de resolução de problemas


Dividir o problemas inicial em subproblemas de modo a que se torne mais
compreensível e de mais fácil interpretação. Apresenta-se dois métodos top-down e o
bottom-up :
- Aproximação top-down
o Método descendente de resolução do problema:
 1 - Analisar o problema
 2 – Escrever o módulo principal
 3 – Escrever os restantes módulos.

1 - Analisar o problema
- Compreender o problema. Compreender o que se dá (dados de entrada) e o que
se pede (dados de saída).
- Especificar os formatos de entrada e os de saída.
DEI E.S.T.G./I.P.Leiria 2
Programação Cap. 1

- Pensar em como se pode resolver o problema à mão.

2 – Escrever o módulo principal


- Se o módulo principal é demasiado grande é porque está com um nível
demasiado baixo de detalhe. Todo o que se tem a fazer no módulo principal é
atribuir nomes aos módulos do nível inferior. Utilizar nomes com significado
para os módulos.

3 – Escrever os restantes módulos.


- Os módulos de um nível podem especificar mais módulos de um nível inferior.
Cada módulo deve estar completo quando não fazem referência a nenhum outro.

Exemplo prático:
Pretende-se encontrar a média ponderada de três exames. Os dados são inseridos na
seguinte forma, nota do exame e respectivo peso.

- Aproximação bottom-up
Esta técnica, menos usada, segue o sentido inverso da primeira.

2 - Técnicas de representação de algoritmos


Existem algumas formas para representar algoritmos:
- pseudocódigo;
- fluxogramas;
- tabelas de decisão;
- quadros estruturados;
- diagramas HIPO

Pseudocódigo
- Linguagem próxima da fala.
- Sem redundância nem ambiguidades.
- Palavras chaves habituais:
o INÍCIO / FIM
o LER / ESCREVER
o SE ... ENTÃO ... SENÃO ...
o REPETIR ... ATÉ QUE ...
o ENQUANTO ... FAZER ...
DEI E.S.T.G./I.P.Leiria 3
Programação Cap. 1

o FAZER n VEZES ...

Exemplo
* programa que lê um número, calcula o seu dobro e apresenta o resultado
INÍCIO
LER a
b=a*2
ESCREVER “O dobro de a é b”
FIM

- Utilizar uma hierarquia de tabulação (com indentação) par ter uma maior
legibilidade do algoritmo.
- O símbolo * é utilizado par introduzir um comentário no algoritmo.

Fluxogramas
Fluxogramas são diagramas que mostram as operações a realizar e a sequência
segundo a qual as diferentes operações que constituem o algoritmo deverão ser realizadas.
O símbolos padrão são os seguintes:
- Processamento
- Leitura / escrita

- Linhas de fluxo

- Conector

- Decisão

- Decisão múltipla

- Início / fim

Exemplo de Fluxograma:

DEI E.S.T.G./I.P.Leiria 4
Programação Cap. 1

DEI E.S.T.G./I.P.Leiria 5
Programação Cap. 2

Capítulo 2.
Introdução à Linguagem C - Estruturas de Controlo

2.1 Introdução à linguagem C


A linguagem C foi desenvolvida por Dennis Ritchie, em 1972 nos laboratórios da Bell (“The
C Programming Language”, Printice-Hall, 1978).

Normalização ANSI, em 1989, para a linguagem C. Actualmente é ANSI/ISO.

Linguagem de programação: Conjunto de regras, símbolos e palavras especiais utilizado


para construir um programa (semântica + sintaxe).

Características da linguagem C:
- Rapidez;
- Simples;
- Alto grau de portabilidade;
- É de uso geral;
- Gera um código executável (Objecto);
- Permite total interacção com o sistema operativo;
- Possui uma sintaxe e poucos comandos;
- É uma linguagem estruturada e modular;
- Permite tratamento de estruturas de dados;
- Bibliotecas poderosas;
- Evolução (Linguagens Orientadas por Objectos).

Compilação e geração de código executável:


1. Edição do Código Fonte.
2. Compilação do Programa.
3. “Linkagem” dos objectos.
4. Execução do programa.

2.2 Estrutura de um programa em linguagem C

Exemplo de um programa em linguagem C:


#include <stdio.h>  Directiva de pré-processador: função padrão printf
#include <conio.h>  Directiva de pré-processador: função padrão getch

DEI E.S.T.G./I.P.Leiria 1
Programação Cap. 2

float mult(float a, float b);  declaração do protótipo da função multiplicação

void main(void)  início da função principal main


{  chaveta de abertura do corpo da função main
float a,b;  declaração e definição de duas variáveis em formato de vírgula
flutuante

printf("\nIntroduzir dois números: ");  escrita no ecrã


scanf("%f%f",&a,&b);  leitura do teclado
printf("\nResultado da multiplicação %.2f x %.2f = %.2f", a,b,mult(a,b));  escrita no ecrã
getch();  pausa
}  chaveta de fecho do corpo da função main

float mult(float a, float b)  definição da função multiplicação


{  chaveta de abertura do corpo da função mult
return (a*b);  instrução da função mult
}  chaveta de fecho do corpo da função mult

2.3 Tipos de dados, variáveis e constantes.

Identificadores de variáveis, constantes e funções:


- Caracteres permitidos: alfabéticos, numéricos e sublinha _ (“underscore”);
- Não começa por algarismo;
- Maiúscula ≠ minúscula (var1 ≠ Var1);
- Não permitidos nomes reservados: auto, break, case, const, continue, default, do, double,
else, extern,... ;
- Desaconselhado uso de acentuação: â, ú,...ç, ... ;
- Utilizar sublinha para separar palavras do mesmo nome (não utilizar espaço em branco);
- Comprimentos até 32 caracteres;
- Utilizar nomes sugestivos;
- Evitar tudo em maiúscula (somente em constantes).

Tipos de dados:
- char caracter (1 byte).
- int inteiro (2 ou 4 bytes).
- float número de vírgula flutuante (normalmente 4 bytes).
- double número de vírgula flutuante de precisão dupla (normal. 8 bytes).

Função sizeof(...) para determinar a quantidade de bytes usada!


Exemplo: sizeof (double);

Qualificadores para alterar a gama de valores (mínimo – máximo):


- short
- long
- unsigned
- signed

Exemplo: unsigned long int variavel;

DEI E.S.T.G./I.P.Leiria 2
Programação Cap. 2

Resumo de formatos de leituras e escritas:

Tipo Formato Observações


char %c Um único caracter
int %d ou %i Um inteiro
int %o Um inteiro (base octal)
int %x ou %X Um inteiro (base hexadecimal)
short int %hd Um short inteiro (base decimal)
long int %ld Um long inteiro (base decimal)
unsigned short %hu Um short inteiro positivo
unsigned int %u Inteiro positivo
unsigned long int %lu Long inteiro positivo
float %f ou %e ou %E Número de vírgula flutuante (normalmente 4 bytes)
double %f ou %e ou %E Número de vírgula flutuante (normalmente 8 bytes)

Declaração das variáveis:


- Localizada no corpo da função (variável local);
- Duas variáveis locais não podem ter o mesmo nome;
- Duas variáveis locais, de funções diferentes podem ter o mesmo nome.

Inicialização:
- Tipo_da_variável nome_da_variável = constante;
- Exemplos:
o char ch=’d’;
o char ch1=4;
o int x1, x2, y, z = 0;
o float pi=3.14156;

- Constante simbólicas:
o #define PI 3.14156
o #define IVA 0.19

2.4 Funções de entrada e saída.

Biblioteca “stdio.h”:
- getchar()
- putchar()
- gets()
- puts()
- scanf()
- printf()

Exemplos:
Saída formatada:
int printf(s_formato, arg1, arg2,...)

DEI E.S.T.G./I.P.Leiria 3
Programação Cap. 2

printf(“A multiplicação de %d por %f é igual a: %f\n”, 5, 4.2, 5*4.2);

Caracter % de conversão com opções.

As Flags são:
- - a saída é justificada à esquerda.
- + é mostrado o sinal dos números.
- ‘ ‘ os números positivos são precedidos de um espaço.
- # aplica-se aos caracteres x, X ou o.
- O especificador de largura do campo:
o Um inteiro decimal não começado por zero. A saída é mostrada com espaços
branco a encher todo o campo.
o Um inteiro decimal começado por zero. A saída é mostrada com zeros à esquerda
a encher todo o campo.
o O caracter asterisco (*). O valor do próximo argumento (que deverá ser um
inteiro) é usado como largura do campo.
- A precisão, especificada com o ponto decimal (.), podendo ser seguido de um número:
o Se especificado aos caracteres e, E, f, F, g, G, específica o número de dígitos a
ser mostrado à direita do ponto. Se o ponto é usado sozinho específica que a
precisão é 0;
o Se aplicado ao caracter de conversão s, específica o número de caracteres a serem
mostrados.
- Modificador de comprimento h, l, L:
o O “h” indica que o argumento correspondente deve ser escrito como um short ou
unsigned short.
o O “l” aplicado aos caracteres o, u, x, X, d, e b, indica que o argumento é do tipo
long, ou unsignel long.
o O “L” aplicado aos caracteres e, E, g, ou G, específica que o argumento é do tipo
long double.

Constantes do tipo caracter:


\b Retrocesso (“Back”)
\n Nova linha
\t Tabulação horizontal (“tab”)
\” Aspas
\’ Apóstrofo
\0 Nulo (0 em decimal)
\\ Barra invertida
\v Tabulação vertical
\a Sinal sonoro (“beep”)

Exemplo:

#include <stdio.h>

main()
{
printf(“|%5.4d| |%-5.3s| |%5.0f|\n”,123,”nome”,45.6);
printf(“|%+5d| |%+d| |% 5d| |% 5d| \n”,123, -123, 123, -123);

DEI E.S.T.G./I.P.Leiria 4
Programação Cap. 2

printf(“|%#5o| |%#5x| |%#5.0f|\n”,15, 15, 15.0);


printf(“|%05d| |%5d| |%*.*f|\n”,15, 15, 6, 2, 15.0);
}

Saída:
| 0123| |nom | | 46|
| +123| | -123| | 123| | -123|
| O17| | xf| | 15.|
|00015| | 15| | 15.00|

Entrada formatada:

int scanf(s_formato, arg1, arg2, ...)

scanf((“%d %f”, &idade, &altura);

2.5 Operadores e expressões.

Operadores em linguagem C:

Aritméticos:
+ adição;
- subtracção;
* multiplicação;
/ divisão;
% módulo (resto da divisão inteira).
Manipulação de bits:
<< desloca para a esquerda os bits;
>> desloca para a direita os bits;
& conjunção AND binário;
^ XOR (ou exclusivo binário);
| disjunção OR (ou inclusivo binário).
Lógicos:
&& AND (e lógico);
|| OR (ou lógico);
! negação (NOT).
Atribuição:
= atribuição;
*= atribuição com multiplicação;
/= atribuição com divisão;
%= atribuição com resto da divisão inteira (modulus);
+= atribuição com adição;
-= atribuição com subtracção;
<<= atribuição com deslocamento binário para esquerda;
>>= atribuição com deslocamento binário para direita;
&= atribuição com AND (binário);

DEI E.S.T.G./I.P.Leiria 5
Programação Cap. 2

^= atribuição com XOR (binário);


|= atribuição com OR (binário).
Relacionais:
< menor que;
> maior que;
<= menor ou igual que;
>= maior ou igual que;
== comparar igualdade;
!= comparar diferença.
Componente de selecção:
. selector directo de componente;
-> selector indirecto de componente (de ponteiro).
Condicional:
?: operador ternário, x=a>b ? a : b; "se a>b então x=a senão x=b".
Vírgula:
, de avaliação.

Exemplos:
- Atribuição:
<variável> = <variável> <operador> <variável>
x = y + 3;

- Atribuição múltipla:
x = y = z = 47;

Ordem da atribuição.

- Atribuições compostas:
x+=1;  x=x+1;
y*=2+3;  y=y*(2+3);
a-=b+1;  a=a-(b+1);
k/=12;  k=k/12;
r%=2;  r=r%2;

- Atribuição com operadores unários:


x++;  x=x+1; Soma 1 ao seu operando.
++x;  x=x+1; Soma 1 ao seu operando.
x--;  x=x-1; Subtrai 1 ao seu operando.
--x;  x=x-1; Subtrai 1 ao seu operando.
Diferenças entre ++x e x++:
y=x++;  1º passo y=x;
2º passo x++;

y=++x;  1º passo x++;


2º passo y=x;

ex: int x, y=5;


x=y++; /* x vale 5 e y vale 6 */
x=++y; /* x vale 7 e y vale 7 */

DEI E.S.T.G./I.P.Leiria 6
Programação Cap. 2

Valores lógicos:
Em C o valor lógico Falso é representado por 0 (zero) e tudo o que for representado por um
valor diferente de zero representa o valor lógico Verdadeiro.

int i=5, j=7;


if ( (i>3) && (j<=7) && (i!=j) ) j++;
( V and V and V ) = V

Expressões de operadores por ordem decrescente de precedência:

Operadores Associatividade
( ) [ ] -> . Esquerda para a direita
! ~ ++ -- Direita para a esquerda
-(unário) (cast) *(unário)
&(unário)
(tipo) sizeof
* / % Esquerda para a direita
+ - “”
<< >> “”
< <= > >= “”
= = != “”
& “”
^ “”
| “”
&& “”
|| “”
?: Direita para a esquerda
= += -= *= /= %= &= Direita para a esquerda
^=
|= <<= >>=
, Esquerda para a direita

Modeladores (casts):
Para forçar um tipo especificado
(tipo) expressão;

exemplo:
#include <stdio.h>
int main ()
{
int num=10;
float f;
f=(float)num/7;
printf(“%f”,f); /* 1.42857 */
return (0);
}

DEI E.S.T.G./I.P.Leiria 7
Programação Cap. 2

Conversão de tipos em expressões:

char ch;
int i;
float f;
double d;

result = (ch / i) + ( f * d ) – ( f + i );

int double float

int double float

double

4.1 Instruções de controlo de sequência

- Instrução IF:

if (expr)
instrução;

ou

if (expr)
instrução1;
else
instrução2;

DEI E.S.T.G./I.P.Leiria 8
Programação Cap. 2

Nota: Existe uma extensão do if-else que é if-else-if.


if (expr1) instrução1;
else if (expr2) instrução2;
else if (expr3) instrução3;
...
else if (exprn) instrução n;

- Instrução SWITCH:

switch (expressão) {
case constante1 : instrução;
break;
case constante2 : instrução;
break;
...
default : instrução;
break;
}

- Ciclo WHILE:

while (expr)
instrução;

- Ciclo DO – WHILE:

do
Instrução;
while (expr);

DEI E.S.T.G./I.P.Leiria 9
Programação Cap. 2

- Ciclo FOR:

for (início; teste; incremento)


instrução;

- Instrução Break e Continue:

break; para interromper um ciclo.


continue; para saltar uma iteração passando à iteração seguinte.

DEI E.S.T.G./I.P.Leiria 10
Programação Cap. 3

Capítulo 3.
Funções

3.1 Definição
Uma função é um módulo independente de código, que tem um nome e executa uma tarefa específica.

Sintaxe de uma função:


Tipo_retornado nome_função(declarações de parâmetros)
{
declarações locais
instruções
}

Exemplos:

int le_digito(void)
{
int c;
do
c=getchar();
while(c<’0’ || c>’9’);
return c;
}
Nota:
Condição A Condição B Condição A || Condição B
Falso Falso Falso
Falso Verdadeiro Verdadeiro
Verdadeiro Falso Verdadeiro
Verdadeiro Verdadeiro Verdadeiro

- Instrução return dentro da função para devolver um valor.

- Função sem return é equivalente a um “procedimento”. Tipo devolvido = void.

- A ausência da declaração do tipo de retorno da função é equivalente a ter o tipo int.

- A instrução return retorna automaticamente o tipo dos dados correcto (“cast” automático).

- Uma função pode ter várias instruções return, mas só um return é executado:

int N_iguais(int n1,int n2)


{
if (n1 = = n2)
return 1;
else return 0;
}

DEI E.S.T.G./I.P.Leiria 1
Programação Cap. 3

Nota: implementação equivalente


int N_iguais(int n1, int n2)
{
return n1 == n2;
}

Características:
- Definição da função: O código da função (cabeçalho + corpo).

- Uma função não pode ser definida dentro de outras funções.

- Declaração/protótipo: Cabeçalho da função, seguido de ponto e vírgula (;). Informa o compilador que a
função existe. Desta forma a função pode ser definida depois a sua invocação.

- O nome da função é único.

- Uma função pode invocar (chamar) outra função.

- Os argumentos de uma função são as variáveis, constantes ou expressões colocadas entre parênteses da
função aquando da chamada desta.

- Os parâmetros são as variáveis colocadas entre os parênteses da função aquando da definição da função.

- Os argumentos de invocação da função devem existir na mesma quantidade e mesma ordem dos parâmetros da
definição da função. No entanto os nomes podem ser diferentes.

- As variáveis declaradas dentro da função são variáveis locais e são apenas visíveis dentro da função. Após
terminar a execução de uma função essas variáveis locais são destruídas (memória libertada).

- Em C, as funções são sempre globais.

3.2 Passagem de argumentos por valor e por “referência”


- Passagem por valor:
void troca(int n1, int n2)
{
int temp;  não inicializada => variável temp com lixo.
temp=n1;
n1=n2;
n2=temp;
}

int a=1, b=2;


Chamada: troca(a,b);  os valores 1 e 2 são passados para a função troca()
printf(“a=%d b=%d”,a,b);

Resultado no ecrã: a=1 b=2  não houve troca!

A função troca(int n1, int n2) somente faz a troca dentro da própria função com cópias n1 e n2 das variáveis a e b e
liberta essas cópias no fim da execução da função.

DEI E.S.T.G./I.P.Leiria 2
Programação Cap. 3

- Vectores como argumento de uma função => passagem por “referência” automática:
#include <stdio.h>
#include <conio.h>
void troca(int Vector[]);

void main(void)
{
int Vector[]={1,2};  A inicialização faz com que a dimensão do Vector seja 2.
troca(Vector);  O endereço do Vector é passado para a função troca.
printf("\n Vector[0]=%d Vector[1]=%d",Vector[0],Vector[1]);  Troca efectuada!
getch();
}

void troca(int Vect[])  A dimensão do vector não é necessária (na 1ª dimensão).


{
int temp;

temp=Vect[0];
Vect[0]=Vect[1];
Vect[1]=temp;
}

Resultado no ecrã: Vector[0]=2 Vector[1]=1  desta vez houve troca!

Notas:
a) O endereço do Vector é o próprio nome Vector = = &Vector[0].
b) Vector[i]  *(Vector+i)

Exemplos de funções e classes de armazenamento:


1)
main ()
{
int x; Variáveis distintas. Não há conflito!
...
}
func(float x)
{
...
x=1;
...
}

2)
main ()
{
int x; Variáveis distintas. Não há conflito!
...
}
func( )
{
int x;
...
x=1;
...
}

DEI E.S.T.G./I.P.Leiria 3
Programação Cap. 3

3)
func(float x) Errado!
{
float x;
...
}

4)
func( )
{
...
x=1; Errado!
...
} Variável global com visibilidade deste ponto para baixo.
int x;

DEI E.S.T.G./I.P.Leiria 4
Programação Cap. 4

Cap. 4 – Vectores e Matrizes


4.1 Vectores unidimensionais
Definição: Um vector é um conjunto de elementos consecutivos, todos do mesmo tipo, armazenados em memória e que
podem ser acedidos através de um nome e de um índice.

Declaração de vector unidimensional:

Tipo nome_variável[n.º de elementos]

Exemplo:

int array[10];  array é um vector com 10 elementos inteiros.

array[0] array[1] ... array[9]


23 567 1222 4 67 87654 2 345 12 1223

Vector array inicializado com valores aleatórios (lixo)!

#define DIMENSAO 12  Directiva de pré-processamento (sem o ponto e vírgula)


 const int dimensao = 12; dependendo do compilador!
float notas[DIMENSAO];  notas é um vector com 12 números reais.

notas[0] é o primeiro elemento do vector.


notas[DIMENSAO-1] é o último elemento do vector.

O n-ésimo elemento de um vector está na posição n-1.

Exemplo sem vector:


...
for (i=1, soma=0; i<=n; i++)
{
printf(“\n Nota %d = ”,i);
scanf(“%f”,&nota);
soma+=nota;
}
media=soma/n;
... As notas introduzidas perderam-se!

Exemplo com vector:

float nota[MAXALUNOS];  MAXALUNOS: constante declarada com #define MAXALUNOS 101


...
for (i=0, soma=0; i<n; i++)
{
printf(“\n Nota %d = ”,i+1);
scanf(“%f”,&nota[i]);
soma+=nota[i];
}
media=soma/n;
for (i=0; i<n; i++)
{
if(nota[i]>=media)  para imprimir as notas >= ao valor da média!
printf(“\n Nota %d = %f”, i+1, nota[i]);
...
}
...

DEI ESTG/IPLeiria 1
Programação Cap. 4

Inicialização de vectores unidimensionais:

int v[3]={11,22,33};  int v[]={11,22,33};

int v[3]={11,22};  int v[3]={11,22,0}; DIFERENTE de int v[]={11,22};  int v[2]={11,22};

int v[3]={11};  int v[3]={11,0,0};

int v[3]={0};  int v[3]={0,0,0};

v  &v[0]

int v[];  ERRADO!

int v[3], array[10];


v[3]=4;  ERRADO!
v=44;  ERRADO!
v=array;  ERRADO!

Funções e vectores:

Se o argumento de uma função for um vector, então, este é passado automaticamente por referência (ver Cap.1
Funções)! No entanto, a função desconhece a dimensão do vector.

Exemplo:
#include <stdio.h>
#include <conio.h>
#define DIM 4

void ini_vector(int x[],int dim, int ini );


void main(void)
{
int i, v[DIM], w[2*DIM];
ini_vector(v,DIM,1);
ini_vector(w,2*DIM,5);
for (i=0;i<DIM;i++)
printf("\n v[%d]+w[%d]=%d",i,2*i,v[i]+w[2*i]);
getch();
}
void ini_vector(int x[],int dim, int ini )
{
int i;
for (i=0;i<dim;i++)
x[i]=ini;
}

Resultado no ecrã:
v[0]+W[0]=6
v[1]+W[2]=6
v[2]+W[4]=6
v[3]+W[6]=6

DEI ESTG/IPLeiria 2
Programação Cap. 4

4.2 Cadeias de caracteres (“Strings”)


Definição:
Uma String ou Cadeia de caracteres é um agrupamento de caracteres armazenados num vector. O último caracter do
vector é ‘\0’.

Exemplos de Strings com aspas:


“Pedro”
“Era uma vez...”
“c”  Carácter c com ‘\0’ no fim! Total 2 bytes!

Exemplos de caracteres com plicas:


‘a’  Ocupa 1 byte!
‘1’
‘=’

Exemplos de Strings e Vectores de caracteres:

char s[31];  30 caracteres a usar + 1 para o terminador!

char s[] = “Palavras”;  char s[9] =”Palavras”  char *s = “Palavras”


 ‘P’+’a’+’l’+’a’+’v’+’r’+’a’+’s’+’\0’
String com 8 caracteres + 1 terminador.

char s[8] = “Palavras”;  ‘P’+’a’+’l’+’a’+’v’+’r’+’a’+’s’ Vector com 8 caracteres.

Nota: Vector de caracteres pode ser ≠ de String!


Uma string é um vector de caracteres terminado com ‘\0’ !

char s[11] = “Palavras”;  ‘P’+’a’+’l’+’a’+’v’+’r’+’a’+’s’+’\0’+’\0’+’\0’


É uma String com 8 caracteres. Também é vector com 11 caracteres!

char s[11] = {‘P’,’a’,’l’,’a’,’v’,’r’,’a’,’s’};  ‘P’+’a’+’l’+’a’+’v’+’r’+’a’+’s’+’\0’+’\0’+’\0’


É uma String!

char s[8] = {‘P’,’a’,’l’,’a’,’v’,’r’,’a’,’s’};  ‘P’+’a’+’l’+’a’+’v’+’r’+’a’+’s’


É um Vector de 8 caracteres!

char s[] = {‘P’,’a’,’l’,’a’,’v’,’r’,’a’,’s’};  ‘P’+’a’+’l’+’a’+’v’+’r’+’a’+’s’


É um Vector de 8 caracteres!

char s[] = {‘P’,’a’,’l’,’a’,’v’,’r’,’a’,’s’,’\0’};  ‘P’+’a’+’l’+’a’+’v’+’r’+’a’+’s’+’\0’


É uma String de 8 caracteres!

Funções padrão de leitura e escrita de Strings:

Função printf:

char s1[100] = “Uma String é”;


char s2[100] = “uma cadeia de caracteres!”;
printf(“Uma String é uma cadeia de caracteres!”);
printf(“\n%s %s”, s1,s2);

Resultado no ecrã:
Uma String é uma cadeia de caracteres!
Uma String é uma cadeia de caracteres!

DEI ESTG/IPLeiria 3
Programação Cap. 4

Função puts:

char s1[100] = “Uma String é”;


char s2[100] = “uma cadeia de caracteres!”;
puts(“Uma String é uma cadeia de caracteres!”);
puts(s1);
puts(s2);

Resultado no ecrã:
Uma String é uma cadeia de caracteres!
Uma String é
uma cadeia de caracteres!

Função scanf para leitura de String:

char Nome[100];
scanf(“%s”,Nome);  Nome sem & e só consegue ler uma única palavra.
Um printf de um nome completo (com mais de que uma palavra) resultaria na impressão de somente o 1º nome. Leitura
até <espaço>, <tab>, ou <enter>.

Função gets:

char Nome[100];
gets(Nome);  Leitura de vários caracteres até encontrar o <enter>
puts(Nome);

Passagem de Strings para funções:


Um vector de caracteres é passado por referência para uma função!

/*Comprimento de um String*/
int strlen(char s[])  int strlen(char *s)
{
int i=0;
while (s[i]!=’\0’)
i++;
return i;
}

/*Copiar uma String Orig para Dest*/


char *strcpy(char *Dest, char *Orig)  A String Dest é devolvida de duas maneiras!
{
int i;
for (i=0;Orig[i]!=’\0’;i++)
Dest[i]=Orig[i];
Dest[i]=’\0’;
return Dest;
}

/*Concatenar duas String: Orig com Dest*/


char *strcat(char *Dest, char *Orig)  A String Dest é devolvida de duas maneiras!
{
int i, comp;
for (i=0,comp=strlen(Dest);Orig[i]!=’\0’;i++)
Dest[comp+i]=Orig[i];
Dest[comp+i]=’\0’;
return Dest;
}

DEI ESTG/IPLeiria 4
Programação Cap. 4

/*Comparar duas Strings*/


int strcmp(char *s1, char *s2)
{
int i=0;
while (s1[i] = = s2[i] && s1[i] != ‘\0’)
i++;
return (s1[i] – s2[i]);  diferença dos códigos ASCII
}

#include <string.h> tem um conjunto de funções para manipulação de Strings. As mais utilizadas são:
strlen Devolve o comprimento de uma String.
strcpy Copia uma String para outra.
strcat Concatenação de Strings.
strcmp Comparação alfabética de Strings.
stricmp Comparação de Strings com ignore case.
strchr Procura um caracter numa String.
strstr Procura uma String dentro de outra.
strlwr Converte todos os caracteres de uma String para minúsculas
strupr Converte todos os caracteres de uma String para maiúsculas.

4.3 Vectores Multi-dimensionais


Definição:
Um vector de vector (...) com elementos de qualquer tipo.

Declaração de vector Multi-dimensional:

Tipo nome_variável[n.º da 1ª dimensão] [n.º da 2ª dimensão] [..] [n.º da nª dimensão]

Exemplo de matriz:

#define DIM 4
...
int m[DIM][DIM];

m[0][0] m[0][1] m[0][2] m[0][3]  m[0]


m[1][0] m[1][1] m[1][2] m[1][3]  m[1]
m[2][0] m[2][1] m[2][2] m[2][3]  m[2]
m[3][0] m[3][1] m[3][2] m[3][3]  m[3]

int M[3][4];
M é um vector com 3 elementos (cada elemento é um vector de 4 inteiros).
M[i] é um vector com 4 inteiros.
M[i][j] é um inteiro que está na posição da linha i e da coluna j do vector M.

Inicialização de vectores Multi-dimensionais:

int v[2][3]={{1,2,3},{11,22,33}};  int v[][3] ={{1,2,3},{11,22,33}};


 int v[2][3] ={1,2,3,11,22,33}; é menos claro!
 int v[][3] ={1,2,3,11,22,33}; é menos claro!

sizeof(v) = = 2 * 3 * (sizeof(int))

v[0]  &v[0][0]
v[1]  &v[1][0]

DEI ESTG/IPLeiria 5
Programação Cap. 4

float v[][]={{1},{1}};  ERRADO! A 2ª dimensão é obrigatória!


float v[3][3]={{1},{2,1}};  Correcto!

Exemplo 1:
Void soma_matriz_quadrada(int M1[][MAX], int M2[][MAX], int Msoma[][MAX])
{
int i,j;
for (i=0; i<MAX; i++)
for (j=0; j<MAX; j++)
Msoma[i][j]=M1[i][j]+M2[i][j];
}

Exemplo 2:

/* JOGO DO GALO!*/

#include <stdio.h>
#include <conio.h>

#define DIM 3
#define ESPACO ' '

void mostra(char s[][DIM]);


void ini(char s[][DIM]);

void main(void)
{
char Galo[DIM][DIM];
int x,y;
char c='O';
int n_jogadas=0;
ini(Galo);
while (n_jogadas<DIM*DIM)
{
mostra(Galo);
printf("\nIntroduza a posição do Jogo Linha Coluna: ");
scanf("%d %d",&x,&y);
x--;y--;
if (Galo[x][y]==ESPACO)
{
Galo[x][y]= c = (c = = 'O')?'X':'O';
n_jogadas++;
}
else
printf("Posição já ocupada\nJogue novamente!\n");
}
mostra(Galo);
getch();
}

void ini(char s[][DIM])


{
int i,j;
for (i=0;i<DIM;i++)
for (j=0;j<DIM;j++)
s[i][j]=ESPACO;
}

DEI ESTG/IPLeiria 6
Programação Cap. 4

void mostra(char s[][DIM])


{
int i,j;
for (i=0;i<DIM;i++)
{
for (j=0;j<DIM;j++)
printf("%c %c",s[i][j],j!=DIM-1?'|':' ');
if (i!=DIM-1) printf("\n--------");
putchar ('\n');
}
}

DEI ESTG/IPLeiria 7
Programação Cap. 5

Cap. 5 – Apontadores
5.1 Definição
Declaração de apontadores (ponteiros) com o símbolo *.

int *p;  p é uma variável do tipo apontador para inteiros, ou seja, p é uma variável que irá
conter o endereço de uma variável do tipo inteiro.

Notações:
int *p;  int* p;  int * p;
int* x,y;  x é um apontador mas y não é um apontador!

Para se aceder ao conteúdo do endereço que p guarda, usa-se o operador de conteúdo *.

Exemplo:

int x, y, *p = &x;
↑_ Apontador p inicializado com o endereço de memória da variável x.
Diz-se que p aponta para x!
x = -9;
y = *p;  Atribui a y o conteúdo da posição para onde p aponta (ou seja –9).

x p y
-9 101 -9
101 ... 256 ... 533

Apontador para apontador para ..., até ao nível pretendido:

int x, *p, **pp;


p = &x;
pp = &p;
**pp = -9;
pp p x
446 103 -9
123 446 103
*p  x
**pp  *p  x

Regras fundamentais:

Regra 1: Um apontador é equivalente a um endereço.

Regra 2: Um apontador aponta para um objecto do mesmo tipo (sizeof(*p)) ou para constante NULL.

Regra 3: Um apontador p tem uma localização (&p, onde ele próprio está guardado) um conteúdo (p, o
que se guarda em p) e um valor indirecto (*p, o que é guardado no endereço apontado por p).

Regra 4: Com um apontador podemos:


- Guardar um endereço;
- Obter e alterar o conteúdo do endereço;
- Adicionar e subtrair um inteiro,
- Subtrair-lhe ou compará-lo com outro apontador se for do mesmo tipo de dados;
- Passá-lo como argumento para uma função que espera um apontador do mesmo tipo.

Erros comuns:
int *p;
*p = 5;  ERRADO!

DEI ESTG/IPLeiria 1
Programação Cap. 5

int *p = NULL;
*p = 1;  ERRADO!

float x[4], *p;


p = x;
p += 10; ERRADO!
*p = 1;

int vect[20];
vect = p;  ERRADO!
vect++;  ERRADO!

Operadores unários * e & têm maior precedência que os operadores aritméticos básicos. Exemplo:

int x, *p, y;
x = 2;
p = &x;
y = *p+7;  y terá o valor 9! *p+7 = = (*p)+7

5.2 Aritmética de Apontadores


Exemplo:

#include <stdio.h>
#include <conio.h>

void main(void)
{
int Vector[]={1,2}, *p;
p = Vector;  ou p = &Vector[0]
printf("\n p = = %d *p = = %d",p,*p);
p = p+1;
printf("\n p = = %d *p = = %d",p,*p);
getch();
}

Resultado no ecrã:
p = = 126478 *p = = 1
p = = 126479 *p = = 2

Algumas propriedades:
p = Vector  p = &Vector[0]
*(p + n) = = Vector[n]
p ± n  endereço ± (n * sizeof (*p))
p+n = =&Vector[n] então p = = Vector e
*(p + n)  *(Vector +n) = = Vector[n]  p[n]
Nota: *(Vector +n) = = *(n + Vector) = = n[Vector]

Exemplo:

#include <stdio.h>
#include <conio.h>

void main(void)
{
int v[]={1,2}, *p=v;

DEI ESTG/IPLeiria 2
Programação Cap. 5

printf("\n v[0]==%d p[0]==%d *(p+0)==%d *(v+0)==%d",v[0],p[0],*(p+0),*(v+0));


printf("\n v[1]==%d p[1]==%d *(p+1)==%d *(v+1)==%d",v[1],p[1],*(p+1),*(v+1));
getch();
}

Resultado no ecrã:
v[0] = = 1 p[0] = = 1 *(p+0) = = 1 *(v+0) = = 1
v[1] = = 2 p[1] = = 2 *(p+1) = = 2 *(v+1) = = 2

Exemplo com String:

#include <stdio.h>
#include <conio.h>

strlen (char *s);

void main(void)
{
char *string = "ola!!";

printf("\n strlen=%d",strlen(string));
getch();
}

strlen (char *s)


{
char *p; _______________
↓ |
for (p=s; *p; p++);  *P != ‘\0’
return p-s;
}

Resultado no ecrã:
strlen = 5

Exemplo com vectores de apontadores:

#include <stdio.h>
#include <conio.h>

void main(void)
{
char *linha[2]={"1a linha", "2a linha"};
char *s;

puts(linha[0]);
puts(linha[1]);
s=linha[0];
linha[0]=linha[1];
linha[1]=s;
puts(linha[0]);
puts(linha[1]);
getch();
}

Resultado no ecrã:
1a linha
2a linha
2a linha
1a linha

DEI ESTG/IPLeiria 3
Programação Cap. 5

Exemplo de apontador passado como argumento numa função:

#include <stdio.h>
#include <conio.h>

void incr_ender(int **v);


void incr_valor(int **v);

void main(void)
{
int vect[2]={11,22}, * p=vect;

incr_ender(&p);
printf("\n%d",*p);
incr_valor(&p);
printf("\n%d",*p);
getch();
}

void incr_ender(int **v)


{
*v=*v+1;
}

void incr_valor(int **v)


{
**v=**v+1;
}

Resultado no ecrã:
22
23

5.3 Apontadores e memória dinâmica


O “header” malloc.h tem a função void *malloc(size_t num) para alocação dinâmica de memória.
A função retorna um apontador para a 1ª posição de uma zona de memória com tamanho de num bytes.
No caso da função não conseguir fazer a alocação, será devolvida a constante NULL.

A função void free(void *apt) liberta a memória previamente reservada e apontada por apt.
Nota: free(NULL) não faz nada!

Exemplo:

#include <stdio.h>
#include <conio.h>
#include <malloc.h>
#include <string.h>

strlen (char *s);

void main(void)
{
char *v, buf[81];
int comp;

comp=strlen(gets(buf));
v=(char *)malloc(comp+1);

DEI ESTG/IPLeiria 4
Programação Cap. 5

if (v!=NULL) {
strcpy(v,buf);
printf("\nEndereco v=%d\nConteudo endereco =",v);
puts(v);
free(v);
}
else
printf("\n Impossivel alocar memoria!\n");
getch();
}

strlen (char *s)


{
char *p;

for (p=s; *p; p++);


return p-s;
}

Resultado no ecrã sem erro de alocação de memória:


Isto é um teste!
Endereco v= 1233456
Conteudo endereco = Isto é um teste!

DEI ESTG/IPLeiria 5
Programação Cap. 6

Cap. 6 – Estruturas
6.1 Definição
Uma estrutura é um agrupamento de várias variáveis que podem ser de diferentes tipos. A estrutura está
referenciada por um nome e contém membros ou campos.

Declaração de uma Estrutura (tipo):

struct nome_da_estrutura
{
tipo1 campo1, campo2;
...
tipon campon;
};

“struct nome_da_estrutura” é um tipo de dados e não um conjunto de variáveis!

Exemplo:
struct Data
{int Dia;
char Mês[12];
int Ano;
};

struct Aniversario
{char Nome[101];
struct Data quando;
};

Declaração de uma variável do tipo Estrutura:

struct Aniversario Amigo[13], Temp, *Ptr_aniversario;

Amigo é um vector de 13 elementos. Cada elemento é do tipo struct Aniversario.


Temp é uma variável do tipo struct Aniversario.
Ptr_aniversario é um apontador para o tipo struct Aniversario.

Outra maneira de definir essas mesmas variáveis:

struct nome_da_estrutura
{
tipo1 campo1, campo2;
...
tipon campon;
} v1, v2, ... , vn;

v1, v2, ... e vn são variáveis do tipo struct nome_da_estrutura.

Exemplo:
struct Data
{int Dia;
char Mes[12];
int Ano;
};
struct Aniversario
{char Nome[101];
struct Data quando;
} Amigo[13], Temp, *Ptr_aniversario;

DEI ESTG/IPLeiria 1
Programação Cap. 6

Os membros das estruturas são acedidos através do operador membro de estrutura (.), da seguinte forma:

Temp.quando.Dia = 12;
scanf(“%d”,&Temp.quando.ano);
gets(Temp.Nome);
strcpy(Temp.Nome,”Pedro”);
strcpy(Temp.quando.Mes,”Abril”);
printf(“Data: %d/%s/%d”, Amigo[2].quando.Dia, Amigo[2].quando.Mês, Amigo[2].quando.Ano);
if (Amigo[i].quando.mês[0] = = ‘\0’) ...;
gets((*Ptr_aniversario).Nome); ou  gets(Ptr_aniversario->Nome);
scanf(“%d”, &Ptr_aniversario->quando.Dia);

6.2 Inicialização de Estruturas


struct nome_da_estrutura var = {valor1, valor2, ..., Valorn};

Exemplo:
struct Data
{int Dia;
char Mes[12];
int Ano;
};
struct Aniversario
{char Nome[101];
struct Data quando;
} v = {“Pedro”, {25,”Dezembro”,2000}};

ou
struct Aniversario v = {“Pedro”, {25,”Dezembro”,2000}};
struct Aniversario var = {“Maria”, {1,”Janeiro”,}};
struct Data vect_data[] = {{25, ”Dezembro”, 2000}, {1, ”Abril”, 1999}}; 
struct Data vect_data[2] = {{25, ”Dezembro”, 2000}, {1, ”Abril”, 1999}};

struct  Sem nome da estrutura


{int Dia;
char Mes[12];
int Ano;
};  ERRADO!

struct  Sem nome da estrutura


{int Dia;
char Mes[12];
int Ano;
} var_data={1, ”Abril”, 1999};  Correcto!

6.3 Definição de tipos – typedef


Sintaxe: typedef tipo_existente sinónimo

Exemplo: typedef int Inteiro;


int x,*y, v[10];  Inteiro x, *y, v[10];

typedef char* Apontador;


typedef char str60[61];
Apontador string = ”Olá!”;
str60 tabela[3] = {"um","dois","tres"};

DEI ESTG/IPLeiria 2
Programação Cap. 6

typedef com estruturas:

typedef struct funcionario


{
char nome[61];
int idade;
float salario;
} FUNC;  Nome do tipo de dados. Não é uma variável!

Declaração das variáveis:


struct funcionario administrativo, financeiro;

ou declaração equivalente:
FUNC administrativo, financeiro;

O nome da estrutura funcionario pode ser omitido:


typedef struct
{
char nome[61];
int idade;
float salario;
} FUNC;

Não declarar variáveis conjuntamente com um typedef:


typedef struct
{
char nome[61];
int idade;
float salario;
} FUNC administrativo, financeiro;  ERRADO!!!

Exemplo com vectores de estruturas:


struct data {
int dia;
char mes[10];
int ano;
};
typedef struct data DATA;
DATA datas[100];

Os typedef devem ser definidos no início do programa:


#include<...>

struct data {...};


typedef ...;

/*protótipos das funções*/


...

main()
{...}

f()
{...}

6.4 Operações com Estruturas


- Obter o endereço de uma estrutura com o operador &;
- Aceder aos membros com o operador .;

DEI ESTG/IPLeiria 3
Programação Cap. 6

- Atribuição, por exemplo:


struct data dat1, dat2;
...
dat1 = dat2;
- Passar uma estrutura para uma função, por exemplo:
mostrar_data(dat1);
- Retornar uma estrutura de uma função, por exemplo:
struct data ler_data();
...
dat1 = ler_data();

Exemplo de passagem de Estruturas e Vectores de Estruturas para funções:

#include <stdio.h>
#include <conio.h>

typedef struct {int Dia, Mes, Ano;} DATA;


typedef struct pessoa
{
char Nome[100];
int Idade;
float Salario;
DATA Nasc;
} PESSOA;

void Ler (PESSOA *ptr);


void Mostrar( struct pessoa x);
void Mostrar_tudo(PESSOA vect[]);

main ()
{
PESSOA p[2]={{"Zé",21,1000.00,{2,10,1982}},
{"Maria",22,1500.00,{25,12,1981}}};
Mostrar(p[0]);
puts("");
Mostrar(p[1]);
puts("");
Ler(&p[1]);
puts("");
Mostrar_tudo(p);
puts("");
getch();
}

void Ler (PESSOA *ptr)


{
printf("Qual o Nome : ");
gets(ptr->Nome);
printf("Qual a Idade : ");
scanf("%d",&ptr->Idade);
printf("Qual o Salário : ");
scanf("%f",&ptr->Salario);
printf("Qual a data de Nascimento: ");
scanf("%d %d %d",&ptr->Nasc.Dia,&ptr->Nasc.Mes,&ptr->Nasc.Ano);
}
void Mostrar( struct pessoa x)
{
printf("Nome : %s\n",x.Nome);
printf("Idade : %d\n",x.Idade);
printf("Salário : %.2f\n",x.Salario);

DEI ESTG/IPLeiria 4
Programação Cap. 6

printf("Data de Nasc : %d/%d/%d\n",x.Nasc.Dia,x.Nasc.Mes,x.Nasc.Ano);


}

void Mostrar_tudo(PESSOA vect[])


{
Mostrar(vect[0]);
puts("");
Mostrar(vect[1]);
}

Neste exemplo houve uma passagem por referência do vector p, nomeadamente da estrutura p[1]!

Nota: typedef PESSOA p[2]; faz com que p seja um tipo de vector de 2 estruturas struct pessoa.

6.5 Estruturas e Apontadores


Apontadores como membros de Estruturas

Exemplo:
struct Data {
int Dia;
char *mes;
int ano;
}dat1,dat2;

dat1.mes=”Abril”;

Apontadores para Estruturas

Utilizados em lista encadeadas ou para passar estruturas como argumentos de funções:

struct pessoa {
char nome [61];
int ano_nasc;
};
struct pessoa *p

ou com typedef:
typedef struct pessoa *Apont;
Apont p;

Inicialização do apontador:
struct pessoa homem;
p = &homen;

ou
p=(Apont)malloc(sizeof(struct pessoa));  p=(struct pessoa *)malloc(sizeof(struct pessoa));

Para aceder aos membros:


(*p).ano_nasc=2003;  p->ano_nasc=2003;

Membros Apontadores para Estruturas

Exemplo:
struct pessoa {
char nome[61];
struct pessoa *seguinte;
};

ou

DEI ESTG/IPLeiria 5
Programação Cap. 6

typedef struct pessoa *Apont_p;  Nota: utilização correcta da estrutura antes da sua definição
struct pessoa {
char nome[61];
Apont_p seguinte;
};

6.6 Outros tipos de Estruturas


Enumerados

Sintaxe: enum [<Nome_enum>] {<Nome_const> [= <valor>], ...} [var_lista];

<Nome_enum> é opcional.
<Nome_const> nome da constante que pode ser inicializado com o valor inteiro <valor>. O 1º <valor> é
igual a zero se for omitido a sua inicialização e os valores seguintes serão valores unitários crescentes.

Exemplo: enum SEXO {Masculino, Feminino} sexo

Nota: Ver exemplo com solução na ficha prática sobre Estruturas!

Fields

Um field é uma estrutura com membros compostos com uma quantidade específica de bits. Os tipos field
são utilizados quando a memória é escassa!

Exemplo:

struct {
unsigned int a : 1;
unsigned int b : 3;
} var;

var.a é composto de 1 bit e var.b é composto de 3 bits.


A variável var.a pode variar entre 0 e 1. A variável var.b pode variar entre 0 e 7 (0 23-1).

Unions

A memória alocada é igual ao maior tamanho das variáveis da composição.

Exemplo:

union valor {
int x;
double y;
char z;
} var;

A variável var só tem o tamanho de um double, por isso, é necessário saber previamente qual o tipo de
dados que será armazenado. A solução pode ser como no exemplo seguinte:

struct Valor {
char tipo;
union valor {
int x;
double y;
char z;
};
} var;

DEI ESTG/IPLeiria 6
Programação Cap. 7

Cap. 7 – Ficheiros
7.1 Definição
Os ficheiros são estruturas de dados próprias para armazenar dados em memória secundária, por exemplo,
em disco ou disquete.

“Streams” (conjunto sequencial de bytes) padrão em <stdio.h>:


- stdin standard input (teclado)
- stdout standard output (monitor)
- stderr standard error (monitor)

Nota: Estes “streams” são processados como se fossem ficheiros e podem ser Binários (sem “\n”) ou de
Texto (com linhas “\n”).

Exemplos de funções da biblioteca <stdio.h> para trabalhar com ficheiros:

E/s formatada:
fscanf
fprintf
E/S carácter/”string”:
getc
fgetc
fgets
putc
fputc
fputs
E/S bloco de dados:
fread
fwrite
Manipulaçãode erros:
clearerr
feof
ferror
Acesso:
fopen
freopen
fclose
fflush
setbuf
setvbuf
Posicionamento:
fgetpos
fsetpos
fseek
ftell
rewind

7.2 Abertura e Fecho de Ficheiros


Abertura de um ficheiro:

A estrutura FILE * é utilizada para declarar um apontador de um ficheiro. A função FILE *fopen(const
char *nome_ficheiro, const char *modo_ficheiro) é utilizada para abrir um ficheiro com nome
nome_ficheiro e modo de abertura modo_ficheiro. Este tipo de dados FILE e esta função fopen estão em
<stdio.h>.

DEI ESTG/IPLeiria 1
Programação Cap. 7

Exemplo:
FILE *fptr;
fptr = fopen(“a:\\Dados.dat”, “a+b”);

a:\\Dados.dat é o nome do ficheiro e “a+b” é o modo de abertura em formato binário para leitura
e escrita a partir do fim do ficheiro.

Modos de abertura:
“r” - read (Abertura do ficheiro para Leitura);
“w” - write (Abertura do ficheiro para Escrita);
“a” – append (Abertura do ficheiro para Acrescento);
“r+”, “w+”, “a+” – Abertura do ficheiro para Leitura e Escrita. ;

Por predefinição, os ficheiros são do tipo texto. Para ter um tipo binário, basta acrescentar um b. Por
exemplo: “rb”, “wb”, “ab”, “r+b” ou “rb+”, “w+b” ou “wb+”, “a+b” ou “ab+”.

Quadro dos modos de abertura:


Modo de Breve Permite Permite Se ficheiro Se ficheiro Posição
abertura Descrição leitura escrita não existir já existir inicial
r Leitura Sim Não NULL OK Início
w Escrita Não Sim Cria Recria Início
a Acrescento Não Sim Cria OK Fim
r+ Ler/Escrever Sim Sim Cria Permite Início
Alterar dados
w+ Ler/Escrever Sim Sim Cria Recria Início
a+ Ler/Escrever Sim Sim Cria Permite Fim
acrescentar
Dados

Nota: Se a função fopen conseguir abrir o ficheiro com sucesso, cria em memória uma estrutura (do tipo
FILE) que representa toda a informação necessária relativa ao ficheiro que estiver a processar,
devolvendo o endereço em que essa estrutura foi criada. Caso não tenha conseguido abrir o ficheiro,
devolve o valor NULL, isto é o endereço zero de memória. Ou seja, devolve NULL quando:
- nome de ficheiro inválido;
- tenta abrir um ficheiro ainda não fechado;
- tenta abrir um ficheiro num local inexistente;
- tenta abrir um ficheiro inexistente em modo r.

Fecho de um ficheiro:

Após se ter realizado o processamento sobre um ficheiro, é necessário fechá-lo. A operação de fecho de
um ficheiro é realizada pela função fclose:

int fclose(FILE *fp)

Esta função retorna 0 em caso de sucesso e –1 (EOF) em caso de erro. A função desaloca a respectiva
estrutura FILE e fecha o ficheiro apontado por fp. Quando um ficheiro é fechado, o conteúdo do “buffer”
é escrito no ficheiro.

Exemplo para verificar se um ficheiro já existe:

#include <stdio.h>

main()
{
FILE *fp;
char nome[13];

printf(“\nIntroduzir o nome do ficheiro: “);

DEI ESTG/IPLeiria 2
Programação Cap. 7

scanf(“%s”,nome);
if ((fp = fopen(nome, “r”)) != NULL) {
printf(“O ficheiro %s já existe!”, nome);
fclose(fp);
}
else
printf(“O ficheiro %s não existe!”, nome);
}

Notas: - Após fechar um ficheiro, o apontador fp pode ser reutilizado para outros fins!
- Embora os ficheiros sejam automaticamente fechados quando uma aplicação termina, é bom
hábito dos programadores efectuarem eles mesmo o fecho dos ficheiros.
- É possível fechar todos os ficheiros abertos (exepto stdin, stdout, stderr, stdprn e stdaux)
usando a função fcloseall().

7.3 Escrita e Leitura de Ficheiros


Escrita de blocos de Ficheiros binários:

Sintaxe: int fwrite(void *ptr, int size, int n, FILE *fich)

ptr: - Apontador para void (qualquer tipo) que contém o endereço de memória daquilo que
pretendemos guardar em ficheiro.
size: - Tamanho em Bytes de cada um dos elementos que pretendemos escrever.
n: - Quantidade de elementos que pretendemos escrever. O valor n será devolvido pela
função fwrite em caso de sucesso.
fich: - Indica o ficheiro onde os dados serão colocados. É o parâmetro devolvido por fopen().

Exemplo:

#include <stdio.h>
#define MAX 5
#define NOME_FICH "a:\\dados.dat"

main()
{
FILE *fp;
int i,v[MAX];
for (i=0; i<MAX;i++)
{
printf("Introduzir o %d-esimo elemento: ", i+1);
scanf("%d",&v[i]);
}
if ((fp=fopen(NOME_FICH,"wb"))==NULL)
{
printf("impossível criar o ficheiro %s\n",NOME_FICH);
}
else
{
if (fwrite(v,sizeof(int),MAX,fp)!=MAX)
printf("Não foram escritos todos os elementos!\n");
fclose(fp);
}
}

Nota: é possível escrever o bloco de dados de uma só vez com fwrite(v ,1, sizeof(int)*MAX, fp); ou
elemento a elemento com o seguinte código for (i=0;i<MAX;i++) fwrite(&v[i] ,sizeof(int),1 ,fp);.

DEI ESTG/IPLeiria 3
Programação Cap. 7

Leitura de blocos de Ficheiros binários:

Sintaxe: int fread(void *ptr, int size, int n, FILE *fich)

ptr: - Apontador para void (qualquer tipo) que contém o endereço de memória onde
queremos colocar os dados que iremos ler a partir do ficheiro.
size: - Tamanho em Bytes de cada um dos elementos que pretendemos ler
n: - Quantidade de elementos que pretendemos ler. O valor n será devolvido pela função
fread em caso de sucesso.
fich: - Indica o ficheiro de onde os dados irão ser lidos. É o parâmetro devolvido por fopen().

Exemplo:

#include <stdio.h>
#include <conio.h>
#define MAX 5
#define NOME_FICH "a:\\dados.dat"

main()
{
FILE *fp;
int i, n, v[MAX];

if ((fp=fopen(NOME_FICH,"rb"))==NULL)
{
printf("impossível abrir o ficheiro %s\n",NOME_FICH);
}
else
{
n=fread(v,sizeof(int),MAX,fp);
if (n!=MAX)
printf("Foram lidos apenas %d elementos!\n",n);

for (i=0; i<n;i++)


printf("%2d elemento: %d\n",i+1,v[i]);

fclose(fp);
}
getch();
}

Nota: é possível ler o bloco de dados de um só vez com fread(v ,1 ,sizeof(int)*MAX ,fp); ou elemento a
elemento com o seguinte código for (i=0;i<MAX;i++) fread(&v[i] ,sizeof(int),1 ,fp); ou com
i=0;while(fread(&v[i] ,sizeof(int),1 ,fp))i++;

Detecção do final do ficheiro:

Sintaxe de End-of-File: int feof(FILE *fich)

A função feof só detecta uma situação de End-of-File depois de ter sido realizada uma operação sobre o
ficheiro que a provoque. A função feof sobre um ficheiro vazio acabado de abrir devolve falso.

Exemplo com vector de estrutura:

#include <stdio.h>
#include <conio.h>
#define NOME_FICH "a:\\dados.dat"

DEI ESTG/IPLeiria 4
Programação Cap. 7

typedef enum {informatico, electrotecnico, matematico} curso_t;


typedef struct {
int dia, mes, ano;
}data_t;
typedef struct {
char nome[50];
long numero;
data_t inscricao;
curso_t curso;
}aluno_t;

void main(void)
{
FILE *fptr;
aluno_t dados[2] = {{"Maria",5675,23,12,2003,informatico},
{"Pedro",1176,20,2,2003,matematico}};
aluno_t al;

fptr = fopen(NOME_FICH,"wb");
if (fptr!=NULL)
{
if (fwrite(dados,sizeof(aluno_t),2,fptr)!=2)
printf("Erro de escrita");
fclose(fptr);
}
else
printf("Erro de abertura para escrita");

fptr=fopen(NOME_FICH,"rb");
if (fptr!=NULL)
{
while (fread(&al,sizeof(aluno_t),1,fptr)==1)
{
printf("Nome: %s Número: %ld ", al.nome, al.numero);
printf("Data de Nasc. %d/%d/%d curso:",al.inscricao.dia,al.inscricao.mes,al.inscricao.ano);
switch (al.curso) {
case 0 : printf("informatico\n");break;
case 1 : printf("electrotecnico\n");break;
case 2 : printf("matematico\n");
}
}
if (!feof(fptr))
printf("Erro de leitura!");
fclose(fptr);
}
else
printf("Erro de abertura para leitura");
getch();
}

- Leitura de Caracteres de um Ficheiro

Sintaxe: int fgetc(FILE *fptr)

Leitura de um caracter a partir de fptr. Em caso de erro ou fim de ficheiro a função devolve EOF (-1).
Caso contrário devolve o caracter apontado por fptr. O apontador fptr avança para o elemento seguinte
após efectuar a leitura.

Exemplo:

DEI ESTG/IPLeiria 5
Programação Cap. 7

int conta_digito(void)
{
FILE *fptr;
int ch, conta=0;
fptr=fopen("c:\\lixo2.txt","r");
if(fptr!=NULL)
{
while ((ch=fgetc(fptr))!=EOF)
if(isdigit(ch))
conta++;
//verificar se está no fim do ficheiro. Se não ocorreu um Erro!
if (!feof(fptr))
printf("ERRO de Leitura");
fclose(fptr);
return conta;
}
else
return -1;
}

- Escrita de Caracteres de um Ficheiro

Sintaxe: int fputc(int ch, FILE *fptr)

Escrita de um caracter ch no ficheiro apontado por fptr. Em caso de erro a função devolve EOF (-1). Caso
contrário devolve o caracter escrito. O apontador fptr avança para o elemento seguinte após efectuar a
escrita.

Exemplo:

#include <stdio.h>
#include <conio.h>

void escrever_ficheiro(void);
void copia_ficheiro(void);

void main(void)
{
escrever_ficheiro();
copia_ficheiro();
}

void escrever_ficheiro(void)
{
FILE *fptr;
char str[101];
int i=0;

fptr=fopen("c:\\lixo1.txt","w");
if(fptr==NULL)
printf("Erro na abertuta do Ficheiro para escrita!");
else
{
gets(str);
while (str[i]!='\0')
{
fputc(str[i],fptr);
i++;
}

DEI ESTG/IPLeiria 6
Programação Cap. 7

fputc('\0',fptr);
}
fclose(fptr);
}

void copia_ficheiro(void)
{
FILE *fptr1, *fptr2;
char ch;

fptr1=fopen("c:\\lixo1.txt","r");
fptr2=fopen("c:\\lixo2.txt","w");

if(fptr1==NULL)
printf("Erro na abertuta do Ficheiro para leitura!");
else if (fptr2==NULL)
printf("Erro na abertuta do Ficheiro para escrita!");
else
{
while ((ch=fgetc(fptr1))!=EOF)
if(fputc(ch,fptr2)==EOF)
{
printf("Erro de escrita\n");
break;
}
fclose(fptr1);
fclose(fptr2);
}
}

- Ficheiros de texto com Strings fgets

Sintaxe: char *fgets(char *linha, int n, FILE *fptr)

A função fgets efectua a leitura por linha de uma cadeia de n caracteres (incluído ‘\n’) de um ficheiro
apontado por fptr para uma variável linha parando quando se verificar uma das seguintes condições:
- encontrou o caracter fim de linha (‘\n’);
- encontrou o caracter fim de ficheiro (EOF);
- leu n –1 caracteres;

O valor ‘\0’ é colocado automaticamente no fim da linha. Em caso de erro devolve NULL.

Exemplo:

/*Função que mostra o conteúdo de um ficheiro de texto numerando cada linha*/


void mostra_fich(char *nome_fich)
{
FILE *fptr;
int linha=1;
char buffer[100];

fptr=fopen(nome_fich,”r”);
if (fptr != NULL)
{
while (fgets(buffer, 100, fptr) != NULL)
{
printf(“Linha %d: %s\n”, linha, buffer);
linha++;
}

DEI ESTG/IPLeiria 7
Programação Cap. 7

if (!feof(fptr))
printf(“Erro de Leitura”);
fclose(fptr);
}
else
printf(“O ficheiro não existe”);
}

- Ficheiros de texto com Strings fputs

Sintaxe: int fputs(char *linha, FILE *fptr)

A função escreve a cadeia de caracteres linha, a qual necessita conter o carácter ‘\n’, num ficheiro
apontado por fptr. O valor retornado é a quantidade de caracteres escritos ou, em caso de erro, EOF.

Exemplo:

/*Função que vai acrescentando num ficheiro o que o utilizador vai introduzindo. A função termina após
a introdução da palavra “fim”*/
void teclado_ficheiro(char *nome_fich)
{
FILE *fptr;
char buffer[100];
int len;

fptr = fopen(nome_fich, “a”);


if (fptr != NULL)
{
gets(buffer);
while (strcmp(buffer,”fim”) !=0)
{
len=strlen(buffer);
if (fputs(buffer, fptr)<len)
{
printf(“Erro de escrita\n”);
break;
}
gets(buffer);
}
fclose(fptr);
}
else
printf(“Erro ao abrir o ficheiro\n”);
}

- Entradas e saídas de ficheiros de texto formatadas

Sintaxe: int fscanf(FILE *fich, char *format, arg1, arg2, ...)

A função fscanf efectua a leitura formatada a partir de um ficheiro apontado por fich. Se chegar ao fim
devolve EOF. Caso contrário, devolve o número de campos lidos correctamente. Se esse número de
campos lidos for inferior ao esperado então, o formato do ficheiro está incorrecto.

Exemplo:

Supondo que existe um ficheiro de texto com a seguinte informação:

Maria 24 1.80
Pedro 25 1.82
Catarina 20 1.71

DEI ESTG/IPLeiria 8
Programação Cap. 7

/* Função para leitura formatada do ficheiro de texto*/

void ler (char *nome_fich)


{
FILE *fptr;
int idade, numero_fichas;
float altura, soma;
char nome[41];

fptr = fopen(nome_fich,”r”);
if (fptr != NULL)
{
numero_fichas = 0;
soma = 0;
while (fscanf(fptr, “%s %d %f”, nome, &idade, &altura) = =3)
{
soma += idade;
numero_fichas++;
printf(“Ficha %d: Nome = %s Idade = %d Altura = %f\n”, numero_fichas,
nome, idade, altura);
}
if (!feof(fptr))
printf(“Erro de Leitura. Formato do ficheiro incorrecto\n”);
else if (numero_fichas>0)
printf(“Media das idades: %f\n”, soma/numero_fichas);
fclose (fptr);
}
else
printf(“O ficheiro nao existe!”);
}

Sintaxe: int fprintf(FILE *fich, char *format, arg1, arg2, ...)

A função fprintf efectua a escrita formatada a partir de um ficheiro apontado por fich. Se chegar ao fim
devolve EOF. Caso contrário, devolve o número de bytes escritos correctamente.

Exemplo:

Supondo que existe a seguinte estrutura:


typedef struct {
char nome[41];
long numero;
} aluno_t;

void main(void)
{
FILE *fptr;
aluno_t dados[2] = {{“Maria”,21},{“Pedro”,24}};
int i;

fptr = fopen(“Dados.txt”,”w”);
if (fptr != NULL)
{
for (i=0; i<2; i++)
if (fprintf(fptr, “%s %ld\n”, dados[i].nome, dados[i].numero) = = EOF)
{
printf(“Erro de escrita\n”);
break;

DEI ESTG/IPLeiria 9
Programação Cap. 7

}
flcose(fptr);
}
else
printf(“Erro ao abrir o ficheiro\n”);
}

O conteúdo de ficheiro Dados.txt será:


Maria 21
Pedro 24

DEI ESTG/IPLeiria 10

Você também pode gostar