Você está na página 1de 25

ATAD

Algoritmos e Tipos Abstratos de Dados

Introdução à Programação
em
Linguagem C

Elaborado por: Rossana Santos


Revisto por: Patricia Macedo
Bruno Silva

Última revisão: 24/02/2017


Introdução à Programação em Linguagem C

Indíce

Introdução ........................................................................................................................... 2
I - Programas Simples .......................................................................................................... 3
Programa em C ............................................................................................................... 3
Declaração de variáveis ............................................................................................... 3
Arrays (vetores) ................................................................................................................ 4
Entrada e saída de valores............................................................................................ 5
Ciclo de desenvolvimento de uma aplicação .......................................................... 7
Operações aritméticas .................................................................................................. 7
Exercícios .......................................................................................................................... 8
II - Instruções ......................................................................................................................... 9
Operadores relacionais ou de comparação ............................................................. 9
Operadores lógicos ........................................................................................................ 9
Instrução if ........................................................................................................................ 9
Instrução switch ............................................................................................................... 9
Instrução while ............................................................................................................... 10
Instrução do-while......................................................................................................... 10
Instrução for ................................................................................................................... 10
Instrução break.............................................................................................................. 11
Exercícios ........................................................................................................................ 12
III - Funções e Estruturas .................................................................................................... 13
Funções .......................................................................................................................... 13
Passagem de arrays para funções............................................................................. 14
Estruturas de Dados ...................................................................................................... 15
Acesso a campos de uma estrutura .......................................................................... 15
Definição de tipos – typedef ....................................................................................... 16
Estruturas dentro de estruturas .................................................................................... 17
Passagem de estruturas para funções ...................................................................... 17
Exercícios ........................................................................................................................ 18
IV - Ponteiros ...................................................................................................................... 19
Ponteiros ou apontadores ........................................................................................... 19
Apontadores e Funções............................................................................................... 19
O porquê dos & no scanf() ...................................................................................... 20
Apontadores e arrays ................................................................................................... 20
Apontadores e Estruturas ............................................................................................. 22
Exercícios ........................................................................................................................ 23

1 | 25
Introdução à Programação em Linguagem C

Introdução

O objectivo deste documento é dar uma visão geral da Linguagem de Programação C,


prestando especial atenção à sua sintaxe, de forma a permitir uma iniciação mais rápida na
sua programação. Não pretende de forma alguma descrever exaustivamente a linguagem.
É dirigido a alunos que saibam programar em outras linguagens ou que dominem os
conceitos de programação.
Este documento está dividido em quatro secções:

 Programas simples.
 Instruções.
 Funções e estruturas.
 Ponteiros.

Devem ser tidas em conta as regras (convenções) de codificação impostas para a


disciplina de ATAD, assim como as guidelines de codificação dos ficheiros *.h e *.c
(módulos).

2 | 25
Introdução à Programação em Linguagem C

I - Programas Simples

Pretende-se nesta secção introduzir a linguagem explicando os passos básicos para a


escrita, compilação e execução de programas simples:

 O ciclo de desenvolvimento de uma aplicação.


 Tipos de dados, declaração e inicialização de variáveis.
 Vectores.
 Formas mais usuais de leitura e escrita de dados.
 Operações e operadores.

Programa em C

Uma das formas de organização e de evitar duplicação de código é a utilização de


funções.

Na linguagem C existe uma função especial chamada “main” (traduz-se por: principal)
que é o local onde começam todos os programas em C.

Todo o programa em C terá de conter uma e uma só função main().

O mais pequeno programa em C que se pode escrever consiste no texto:

main() {

Neste caso a função main não recebe nenhum argumento (não existe nada escrito entre
os parentesis). As chavetas { } agrupam as instruções a executar pela função e como não
escrevemos qualquer instrução o programa começa e termina logo de seguida, como não
utilizamos a instrução return também não retorna nada.

Declaração de variáveis

A linguagem C possui quatro tipos simples de dados, existindo algumas variações


destes:

 char (caracter)
 int (inteiro)
 float (real com precisão simples)
 double (real com precisão dupla)

Os nomes das variáveis têm de obedecer a algumas regras:

 Só podem conter letras do alfabeto, os dígitos de 0 a 9 e o caracter underscore ( _ ).


 O primeiro caracter não pode ser um dígito.
 A linguagem C é case-sensitive logo, por exemplo, as variáveis Xpto e xpto
representam valores diferentes.
 Uma variável não pode ter o nome de uma palavra reservada da linguagem.
 Não é aconselhada a utilização de letras com acentos, nem com cedilhas, visto que
a maior parte dos compiladores não aceita estes caracteres como admissíveis.

3 | 25
Introdução à Programação em Linguagem C

As variáveis são declaradas da seguinte forma:

tipo_da_variável nome_da_variável;

Também podem ser inicializadas aquando da sua criação:

tipo_da_variável nome_da_variável = valor_inicial;

A atribuição é representada no C pelo operador =.

Um comentário em C corresponde a texto delimitado pelos caracteres /* e */.

Podemos ter variáveis locais (só existem dentro da função em que são declaradas), e
variáveis globais (visíveis em todas as funções de um programa). Por exemplo, no programa
seguinte podemos ver diversos tipos de inicialização possíveis:

/* Inicio variaveis globais */

float sum = 0.0;/* declaracao e inicialiacao da variável sum do tipo real com o valor 0
*/
int bignumber = 0, bigsum; /* declaracao das variaveis bignumber e bigsum do tipo
inteiro em que a variavel bignumber é inicializada a 0 */

char letter; /* declaracao da variavel letter do tipo caracter sem


inicializacao */

/* Fim variaveis globais */

main()
{
/* Inicio variaveis locais */

int i, j, k; /* declaracao das variaveis i, j, e k do tipo inteiro


sem inicializacao */

int a = b = c = d = 3; /* declaracao e inicialiacao das variaveis a, b, c, d


do tipo inteiro com o valor 3 */

float x, y, z; /* declaracao das variaveis x, y, e z do tipo real


sem inicializacao */

char ch; /* declaracao da variavel ch do tipo caracter sem


inicializacao */

/* Fim variaveis locais */

i = 0; /* inicializacao da variavel local i do tipo inteiro com o valor


0 */

ch = ‫ܝ‬a‫;ܞ‬ /* inicializacao da variavel local ch do tipo caracter com o


valor a */

bigsum = 0; /* inicializacao da variavel global bigsum do tipo inteiro com o


valor 0 */

Arrays (vetores)

Os arrays (vectores) unidimensionais, na linguagem C, definem-se da seguinte


forma:

tipo_da_variável nome_da_variável[número_elementos];

4 | 25
Introdução à Programação em Linguagem C

Os arrays (vectores) bidimensionais (N x M):

tipo_da_variável nome_da_variável[N][M];

Os arrays (vectores) multidimensionais (N1 x N2 x ... x Nm):

tipo_da_variável nome_da_variável[N1][N2]...[Nm];

Exemplo:

int num[4][3][5]; /*matriz 3-dimensional 4x3x5*/

Os arrays (vectores) obedecem a algumas regras:

 Um vector pode conter elementos de qualquer tipo mas todos os seus elementos têm
de ser do mesmo tipo.
 Os índices de um vector variam entre zero e o seu número de elementos – 1.
 O índice do primeiro elemento é sempre o zero.
 Os vectores quando são criados contêm valores aleatórios (LIXO) nas suas posições
até serem inicializadas.

Os vectores podem ser inicializados de várias formas:

tipo var[n] = {valor_0, valor_1,...,valor_n-1};

Exemplo:

char num[4] = { ‫ܝ‬2‫ܞ‬, ‫ܝ‬4‫ ܞ‬, ‫ܞ‬6‫ܞ‬, ‫ܞ‬8‫;} ܞ‬

O que nos evita fazer (equivalente a):

char num[4];

num[0] = ‫ܝ‬2‫;ܞ‬
num[1] = ‫ܝ‬4‫;ܞ‬
num[2] = ‫ܝ‬6‫;ܞ‬
num[3] = ‫ܝ‬8‫;ܞ‬

No caso de arrays (vectores) :

int num[10];

Podemos utilizar a seguinte forma de inicialização:

int num[10] = {1,2,3};

que é equivalente a:

int num[10] = {1,2,3,0,0,0,0,0,0,0};

i.e., assume que as posições não referidas explicitamente guardam o valor 0.

Podemos também definir strings recorrendo a arrays (vectores) . Uma string é uma cadeia
de caracteres, i.e., é um array (vector) de caracteres:

char nome[20]=‫ܢ‬ATAD‫;ܢ‬

A variável nome comporta-se como um array (vector) usual. Podemos aceder às letras
de uma cadeia de caracteres acedendo às posições do array (vector) . No exemplo acima
nome[4] guarda o caracter ‘e’ (não esquecer que a primeira posição de um vector é a
zero);
5 | 25
Introdução à Programação em Linguagem C

Entrada e saída de valores

A linguagem C não possui mecanismos de Input e Output. Para resolver este problema
temos de recorrer a um conjunto de funções que existem em bibliotecas de funções. Isto
implica que temos de adicionar à linguagem um conjunto de outras funcionalidades que,
por defeito, ela não nos proporciona. Para termos acesso a esse conjunto de funções
teremos de incluir a sua definição no nosso programa, para tal escrevemos no início do
programa:

#include <nome_ficheiro_que contem_a_biblioteca.h>

São as funções da biblioteca standard scanf() e printf() (leitura e escrita formatada,


respectivamente) que permitem ler do teclado e escrever no écran , respectivamente. Estas
funções encontram-se na biblioteca de “standard input / output” que se encontra num
ficheiro (gravado algures no disco) chamado “stdio.h”.

Pelo que, para as utilizarmos, temos de acrescentar ao nosso programa: #include


<stdio.h>, na primeira linha:

#include <stdio.h>

main()
{
}

A função scanf() lê valores do teclado para variáveis. Recebe como primeiro


parâmetro uma string especificando o tipo e a ordem das variáveis a ler. Seguem-se como
parâmetros as próprias variáveis pela ordem especificada. Na string de formatação indica-
se a ordem e o tipo das variáveis através do carácter % seguido de uma letra indicadora do
tipo. Alguns dos caracteres indicadores do formato são:

 %c para variáveis do tipo char


 %d para variáveis do tipo int
 %f para variáveis do tipo float
 %s para variáveis do tipo char[] (strings)

Há que ter em atenção que a string especificando a ordem das variáveis ler não
pode conter outros caracteres (por exemplo: \n e \t) que não os caracteres indicadores dos
formatos. Não esquecer também que na lista de variáveis é obrigatório usar o operador &
antes de cada variável (o motivo será explicado na secção quatro: Ponteiros), excepto nas
strings.

Note-se que quando se usa a função scanf() para ler strings a função apenas lê até ao
primeiro espaço, logo se escrevermos uma frase apenas a primeira palavra é guardada na
variável.

A leitura de strings também pode ser efectuada através da função:

gets(nome_variável);

Neste caso é lida a cadeia de caracteres que o utilizador insere até pressionar
return (ie, lê espaços, o que permite guardar numa variável uma frase).

A função printf() recebe como primeiro parâmetro uma string especificando o


formato e a ordem das variáveis a escrever. Seguem-se como parâmetros as próprias
variáveis pela ordem especificada. Na string de formatação indica-se o local e o tipo de um
valor de variável através do carácter % seguido de uma letra indicadora do tipo.

6 | 25
Introdução à Programação em Linguagem C

Notas: As strings em C definem-se entre aspas (" "), os caracteres simples aparecem
entre plicas (' '); o texto normal da string de formatação aparece tal e qual no écran, os
valores das variáveis aparecem nos locais indicados pelo carácter %. É possível formatar a
string utilizado caracteres especiais, tais como:

 new line: \n
 tab: \t

A escrita de strings também pode ser feita pela função:

puts(nome_variável);

Por exemplo:

puts(‫ܡ‬Hello world!‫;)ܢ‬

é equivalente a

printf(‫ܡ‬Hello world!\n‫;)ܢ‬

Um exemplo:

#include <stdio.h>

main()
{
char ch;
char palavra[10];
char frase[30];
int i ;
float x;

/* guarda um caracter lido do teclado na variavel ch,


um inteiro na variavel i e um real na variavel x */
scanf(" %c %d %f", &ch, &i, &x);

scanf(" %s", palavra); /* guarda uma palavra na variavel palavra */


gets(frase); /* guarda uma frase na variável frase */

puts(frase);
printf("Os valores das variaveis sao: \n \t %c,\t %d, \t%f, \t%s", ch, i, x,
palavra);
}

Se tivéssemos inserido os valores A, 41, 0.0, olá e Bom dia, o resultado seria:

Bom dia
Os valores das variáveis são:
A, 41, 0.0, ola

7 | 25
Introdução à Programação em Linguagem C

Ciclo de desenvolvimento de uma aplicação

Após a edição do código, já explicada anteriormente, há que compilar e linkar o


programa desenvolvido. Como exemplo vamos supor que criámos um ficheiro chamado
“programa.c” onde escrevemos o seguinte código:

#include <stdio.h>

main()
{
printf("Hello world!");
}

O papel do compilador é verificar se a sintaxe do programa está correcta. Se esta se


encontrar correcta é criado um ficheiro objecto, com o nome igual ao programa mas com
extensão “.o”, e um ficheiro executável do programa com a extensão .out – ou sem
extensão (sistemas Unix). Em geral, no Windows, é criado um ficheiro executável .exe.

O ficheiro executável é criado a partir do ficheiro objecto e através das bibliotecas que
contêm código já compilado das funções do próprio C e que são necessárias ao executável
final.

Operações aritméticas

O C suporta, entre outras, as seguintes operações aritméticas usuais: + (soma), -


(subtracção), * (multiplicação), / (divisão) e % (resto da divisão inteira).
Outros operadores aritméticos são os operadores de incremento e decremento,
representados respectivamente por ++ e --.

8 | 25
Introdução à Programação em Linguagem C

Exercícios

a. Escreva um programa que leia um valor real, representando graus Celsius e escreva o
seu equivalente em Fahrenheit na seguinte forma:

100.0 graus Celsius equivalem a 212.0 graus Fahrenheit

b. Escreva um programa que leia 6 inteiros que representam o valor dos lados de uma
figura geométrica e que escreve o seu perímetro:

i. Sem utilizar arrays.


ii. Utilizando arrays.

9 | 25
Introdução à Programação em Linguagem C

II - Instruções

Pretende-se nesta segunda secção descrever as principais instruções da Linguagem de


Programação C. No final desta secção os alunos deverão ter o conhecimento da sintaxe das
instruções e de como aplicar as várias formas de realização de testes e ciclos que a
linguagem possui.

Operadores relacionais ou de comparação

A linguagem C não possui nenhum tipo que permita representar os valores lógicos
(verdade e falso). Em C o valor lógico falso é representado por 0 (zero). Tudo aquilo que seja
diferente de zero é verdade (Nota: o valor lógico verdade não é apenas o valor 1 mas todos
os que são diferentes de zero).
O operador de teste de igualdade no C é == (não confundir com o operador de
atribuição =), e de desigualdade é o !=.
Os restantes operadores de comparação são os usuais: < (menor), <= (menor ou igual), >
(maior), >= (maior ou igual).

Operadores lógicos

Os três operadores lógicos do C são:

 negação (not): !
 e (and): &&
 ou (or): ||

Instrução if

A instrução if tem a mesma sintaxe que em outras linguagens:

if (condição)
instrução;

ou
if (condição)
instrução_1;
else
instrução_2;

pudemos ainda utilizar o else if:

if(condição_1)
instrução_1;
else if(condição_2)
instrução_2;
else
instrução_3;

10 | 25
Introdução à Programação em Linguagem C

Instrução switch

A instrução switch permite uma escolha múltipla de execução baseada no valor de


uma expressão. A sua estrutura geral é a seguinte:

switch (condição) {
case constante_1:
instrução1;
break;
case constante_2:
instrução2;
break;
...
case constante_n:
instruçãon;
break;
default:
instrução;
}

Os valores que aparecem a seguir à palavra case são valores constantes, não podem ser
expressões nem variáveis. Se a expressão inicial coincidir com algum desses itens executa-se a
instrução que vem logo a seguir. Caso contrário, e se a palavra default estiver presente
(não é obrigatório), passa-se a essa instrução; se não estiver presente passa-se à instrução
que se segue à instrução switch. A palavra break (é uma instrução do C) faz com que se
passe imediatamente à instrução que se segue à presente (a instrução que virá a seguir a
esta instrução switch no programa). Se não estiver presente a execução continua para a
instrução do próximo case.

Instrução while

A instrução while (também chamada ciclo while), executa uma instrução ou bloco de
instruções enquanto uma determinada condição for verdadeira. Adapta-se particularmente
às situações em que o número de iterações não é conhecido à partida. A sua sintaxe é:

while (condição)
{
bloco
}

Instrução do-while

A instrução do-while (também chamada ciclo do- while) difere do ciclo anterior porque
executa o bloco de instruções uma vez antes de avaliar a condição. Continua a executar o
bloco enquanto determinada condição for verdadeira. A sua sintaxe é:

do
{
bloco
} while (condição);

11 | 25
Introdução à Programação em Linguagem C

Instrução for

A instrução for (também chamada ciclo for), adapta-se particularmente às situações em


que o número de iterações é conhecido à partida. A sua sintaxe é:

for (inicializações; condição; pós-instruções)


{
bloco
}

Exemplo:

int i;
for (i = 0; i <= 10; i++)
{
printf(‫\ܡ‬nO quadrado do numero %d e %d\n‫ܢ‬, i, i*i);
}

O programa acima escreve os quadrados dos números de 0 a 10. O seu funcionamento é


o seguinte:

1. Inicializa a variável inteira i a zero;


2. Se i <= 10 executa o bloco: printf(‫ܡ‬O quadrado do numero %d e %d‫ܢ‬, i,
i*i) senão passa para o passo 5.
3. Executa i++, isto é, incrementa a variável i;
4. Volta ao passo 2.
5. Termina

Instrução break

A instrução break (que é a mesma que é utilizada na instrução switch), quando aplicada
dentro de um ciclo, termina o correspondente ciclo, continuando na instrução
imediatamente a seguir a esse ciclo.

12 | 25
Introdução à Programação em Linguagem C

Exercícios

a. Escreva um programa que leia uma data, verifique se ela é valida e a escreva por
extenso (por exemplo: 01 01 2004 = 1 de Janeiro de 2004). Utilize no programa ambas
as instruções if-else e switch.

b. Escreva dois programas que escrevam no ecrã uma tabela de conversão de graus
Celsius para Fahrenheit. A tabela deve apresentar os graus Celsius de 0 a 40 de 2 em
2.
c. (Nota: º F = º C + 112)

i. Recorrendo à instrução for.


ii. Recorrendo à instrução while.

d. Escreva um programa que leia um inteiro n e escreva todos os números primos até n.

e. Escreva um programa que leia uma sequência de números inteiros, e determine e


imprima a soma, a média, o menor e o maior dos números:

i. Supondo que o comprimento da sequência é indicada previamente.


ii. Supondo que o fim da sequência é indicado pelo valor 0 (que já não faz parte
da sequência).

f. Escreva um programa que pede para escolher uma operação aritmética, e,


seguidamente, pede os dois operandos sobre os quais quer realizar essa operação. O
computador deve fazer a operação apropriada e escrever o resultado no ecrã. O
programa quando detectar uma divisão por zero deverá escrever uma mensagem
de erro.

g. Escreva um programa para calcular o factorial de um número de três formas: uma


usando a instrução for, outra utilizando a instrução while e uma terceira com a
instrução do ... while.

h. Escreva um programa para jogar ao jogo do galo.

13 | 25
Introdução à Programação em Linguagem C

III - Funções e Estruturas

A terceira secção deste documento é dedicada às funções e às estruturas na Linguagem


de Programação C. No final desta secção pretende-se que os alunos sejam capazes de
saber:

 Organizar o código em funções.


 O que é uma estrutura e como defini-la.
 Como aceder aos campos de uma estrutura.
 Utilizar estruturas dentro de estruturas.
 Passar estruturas para funções.

Funções

É indispensável que um programador domine a programação de funções. A utilização


de funções permite a organização do código e a sua reutilização. As funções possuem
algumas características:

 Cada função tem de ter um nome único.


 Uma função pode ser invocada a partir de outras funções.
 Uma função deve realizar uma única tarefa bem definida.
 Uma função deve comportar-se como uma caixa negra, isto é, não interessa como
funciona por dentro o que interessa é o resultado que calcula.
 O seu código deve ser o mais independente do programa possível, de forma a puder
ser reutilizado noutros projectos.
 Uma função pode receber parâmetros que permitem adaptar-se a situações
diferentes.
 Uma função não pode ter o nome de uma palavra reservada da linguagem.
 Não é aconselhada a utilização de letras com acentos, nem com cedilhas, visto que
a maior parte dos compiladores não aceita estes caracteres como admissíveis.

Num programa em C as funções têm a seguinte estrutura:

tipo_retornado nome_da_funcao(argumentos)
{
bloco
}

A primeira linha é composta pelo cabeçalho da função. Qualquer função em C tem de


ser seguida por parêntesis. Dentro de parêntesis vêm os argumentos que a função recebe. O
tipo_retornado consiste no tipo de dados do valor que a função retorna. Se a função retorna
não retorna nenhum valor o tipo retornado é: void. Se a função retorna algum valor então
tem de possuir, no bloco de instruções, pelo menos uma instrução:

return resultado;

e o tipo de dados do resultado tem de coincidir com o tipo_retornado. Todo o


código a executar é colocado entre { } e é chamado de bloco.

14 | 25
Introdução à Programação em Linguagem C

Exemplo:

#include <stdio.h>

int soma(int num1, int num2)


{
return num1 + num2;
}

main()
{
int i , j;

printf("Insira dois numero inteiros: ‫;)ܢ‬


scanf(" %d %d", &i, &j)
printf("A soma de %d com %d e: %d‫ܢ‬, i, j, soma(i,,j));
}

Passagem de arrays para funções

É possível passar arrays como argumentos de funções. No entanto essa passagem tem
um comportamento diferente dos outros tipos de variáveis. Quando se passa qualquer outro
tipo de variável como parâmetro de uma função, é inicialmente criada uma cópia dessa
variável e a função actua sobre essa cópia sem poder modificar a variável original que foi
passada (chama-se a esse mecanismo passagem por valor). Quando se passa um array não
se cria uma cópia; em vez disso é passado o endereço do primeiro elemento do vector de
forma automática e transparente para o utilizador. A consequência dessa forma de
passagem (passagem por referência) é que os elementos do vector que forem modificados
na função mantêm essas modificações, mesmo depois da função terminar.

Para arrays unidimensionais a passagem como parâmetro de uma função pode ser feita
como no exemplo seguinte:

void mostra(int size, int numeros[])


{
int i;
for (i=0; i<size; i++)
printf(‫ܡ‬Numero da posicao %d = %d‫ܢ‬, i, numeros[i]);
}

No cabeçalho da função o segundo argumento é um vector de inteiros. Note-se que


não é preciso especificar a dimensão (caso unidimensional) aquando da passagem como
parâmetro. Compete ao programador assegurar de forma absoluta que nunca é acedido
um elemento para além da real dimensão do vector.

Na passagem de arrays multidimensionais é necessários indicar todas as dimensões com


excepção da primeira.

Por exemplo:

void mostraNotas(int size, int notas[][4])


{
int i;
for (i=0; i<size; i++)
printf(‫\ܡ‬nAluno: %d \tNota 1: %d \tNota 2: %d \tNota 3: %d‫ܢ‬, notas[i][0],
notas[i][1], notas[i][2], notas[i][3]);
}

15 | 25
Introdução à Programação em Linguagem C

Estruturas de Dados

Até agora todos os dados eram armazenados em variáveis simples, isto é, variáveis dos
tipos char, int, float ou double. Quando queríamos armazenar vários conjuntos de
informação estes tinham de ser todos do mesmo tipo. O exemplo acima mostra como
armazenar números de alunos e as suas respectivas notas de três testes, mas, e se
quiséssemos armazenar também o seu nome? Isto não é possível com arrays dado que o
nome é do tipo char[] e o número e notas são, neste caso, inteiros.

A Linguagem C possui uma forma de armazenar conjuntos de informação de vários tipos


numa única entidade. Esta entidade chama-se estrutura. Uma estrutura é um conjunto de
uma ou mais variáveis (a que se chama campos ou membros) agrupadas sobre um único
nome, de forma a facilitar a sua referência. As estruturas podem conter elementos com
qualquer tipo de dados válidos em C.

A sua sintaxe é a seguinte:

struct [nome_da_estrutura]
{
tipo_1 campo_1, campo_2;
...
tipo_n campo_n;
}

Aconselha-se a declarar as estruturas num ficheiro de cabeçalhos (headers) e inclui-lo no


ficheiro.c.

Ficheiro data.h
#include <stdio.h>

struct data
{
int dia;
int mes;
int ano;
}

Ficheiro principal
#include <stdio.h>
#include ‫ܡ‬data.h‫ܢ‬

main()
{
struct data datas[100], data_inicio, data_fim;
}

A definição da estrutura Data (struct data) indica apenas que, a partir deste momento,
o compilador passa a conhecer um outro tipo, chamado struct data e que é composto por
dois inteiros e um vector de 10 caracteres.
Para declararmos uma variável do tipo struct data, basta indicar qual o tipo seguido
do nome das variáveis:

struct data datas[100], data_inicio, data_fim;

Note-se que a variável datas é um vector que contém 100 datas, isto é, cada posição do
vector é do tipo Data.

16 | 25
Introdução à Programação em Linguagem C

Acesso a campos de uma estrutura

O acesso aos campos da estrutura faz-se escrevendo o nome da estrutura seguido de “.”
seguido do nome do campo a que queremos aceder. Por exemplo:

main()
{
struct data datas[100], data_inicio, data_fim;
data_inicio.dia = 1;
data_inicio.ano = 2004;
data_inicio.mes = 1;
printf("\n%d de %d de %d", data_inicio.dia, data_inicio.mes, data_inicio.ano);

datas[0].dia = 2;
datas[0].ano = 2004;
datas[0].mes = 1;
datas[1].dia = 2;
datas[1].ano = 2004;
datas[1].mes = 1;
printf("\n%d de %d de %d", datas[0].dia, datas[0].mes, datas[0].ano);
printf("\n%d de %d de %d", datas[1].dia, datas[1].mes, datas[1].ano);}

Existem várias formas de inicialização de estruturas. Para o nosso exemplo, uma é a


descrita no exemplo acima, outra é:

struct data data_inicio = {1,1,2004};

Cuja sintaxe é a seguinte:

struct nome_estrutura nome_variável = {valor1, valor2,...,valorn};

Definição de tipos – typedef

Uma das desvantagens existentes na utilização de estruturas está na declaração das


variáveis que tem de ser sempre precedida pela palavra reservada struct seguida do nome
da estrutura. O ideal seria termos forma de criar um novo tipo, que seria utilizado da mesma
forma que os tipos simples da linguagem C. Isto é possível recorrendo à palavra reservada
typedef, cuja sintaxe é:

typedef tipo_existente sinónimo;

A palavra typedef não cria um novo tipo simplesmente permite que usemos o
tipo_existente referindo apenas o seu sinónimo. O uso de typedef não se restringe apenas
às estruturas, pode ser utilizado com qualquer tipo da linguagem:

typedef int inteiro;

Passaríamos a poder declarar as variáveis do tipo int das seguintes forma:

inteiro i;
/* ou */
int i2;

No caso do exemplo de estrutura poderíamos fazer:

typedef struct data


{
int dia;
int mes;
17 | 25
Introdução à Programação em Linguagem C

int ano;
} Data;

Podemos agora declarar variáveis da seguinte forma:

Data datas[100], data_inicio, data_fim;

Estruturas dentro de estruturas

Como foi dito, uma estrutura pode conter qualquer tipo da linguagem C. Isto quer dizer
que uma estrutura também pode conter estruturas. Um exemplo seria:

typedef struct Pessoa


{
char nome[30];
int idade;
Data data_nascimento;
} Pessoa;

A estrutura Pessoa contém a estrutura Data.

Passagem de estruturas para funções

A passagem de estruturas para funções faz-se indicando no parâmetro o tipo associado


à estrutura. Continuando o exemplo da estrutura Data:

#include <stdio.h>

int mostra(Data data) /* também podia ser: int mostra(struct data data) */
{
printf(‫ܡ‬%d de %d de %d‫ܢ‬, data.dia, data.mes, data.ano);
}

main()
{
Data data = {1,1,2004};

mostra(data);
}

18 | 25
Introdução à Programação em Linguagem C

Exercícios

a. Escreva um programa que leia dois inteiros que representam o valor dos lados de um
rectângulo e que escreve a sua área e perímetro, recorrendo a funções.

b. Escreva um programa que leia dois inteiros, x e n, e escreva xn recorrendo a funções.

c. O maior divisor comum (mdc) de dois inteiros x e y é o maior inteiro que divide tanto x
como y (com resto 0). Escreva uma função int mdc(int x, int y) capaz de calcular o maior
divisor comum de dois inteiros, seguindo a definição acima.

d. Transforme os exercícios da secção dois de forma a utilizar o maior número de funções


possível.

e. Escreva um programa que peça ao utilizador o número, nome e nota de dois testes dos
alunos de uma turma, guarde essa informação numa estrutura, e mostre a pauta com os
seguintes campos: número, nome, nota1, nota2, média.

f. Escreva um programa que leia os valores das coordenadas de dois pontos e que
calcule a distância entre eles.

19 | 25
Introdução à Programação em Linguagem C

IV - Ponteiros

Pretende-se nesta secção introduzir os apontadores (também chamados de ponteiros).


Os apontadores são fundamentais na Linguagem C e a sua implementação é um pouco
diferente das outras linguagens, pelo que será a matéria mais difícil de compreender. Os
apontadores são utilizados sobretudo em conjunto com arrays, estruturas e funções
produzindo código compacto e eficiente.

Ponteiros ou apontadores

Um apontador é uma variável que contém o endereço de memória de outra variável


(diz-se que aponta para ela). Declaração de apontadores:

tipo *nome_apontador;

Na programação com apontadores são utilizados dois operadores:

 &nome_variável que nos diz qual é o endereço da variável nome_variável.


 *nome_variável que nos diz qual o valor que a variável que está a ser apontada por
nome_variável guarda.

Quando se declara um apontador ele não aponta para nada. Há que colocar no
apontador um endereço válido, antes de o poder utilizar (o melhor é iniciá-lo logo quando é
criado).

Por exemplo:

float *ptr_pi, pi = 3.14; /* a variavel ptPi é um ponteiro para um real */

ptr_pi = &pi; /* a variavel ptr_pi aponta para pi (foi inicializada) */

*ptr_pi = 3.1415; /* o valor apontado por ptr_pi vai passar a ser 3.1415 */

*ptr_pi = *ptr_pi + 0.00009265; /* podem realizar-se operacoes aritmeticas sobre


ponteiros */

Há situações onde pode ser necessário declarar um apontador mas não o inicializar,
neste caso colocamo-lo a apontar para NULL.

Apontadores e Funções

Na Linguagem C, existem umas algumas coisas que só se conseguem fazer utilizando


apontadores. Uma delas é a modificação dos valores dos argumentos durante a execução
de uma função.

Imaginemos que queríamos programar uma função para trocar o valor de duas variáveis.
Uma primeira aproximação seria:

#include <stdio.h>

void troca(int x, int y)


{
int aux;

aux = x;
x = y;
y = aux;
}

20 | 25
Introdução à Programação em Linguagem C

main()
{
int a = 2, b = 5;

troca(a, b);
printf("%d %d", a, b );
}

Será que os valores são de facto trocados? Não!

Quando chamamos uma função passando como argumentos variáveis (neste caso
chamamos a função troca() passando como argumentos as variáveis a e b), procedemos à
cópia dos valores que essas variáveis possuem para as variáveis que são os argumentos da
função (ie, a variável x vai guardar uma cópia do valor de a e a y do valor de b) e a função
vai executar as suas operações sobre as variáveis dos argumentos (as variáveis x e y)
enquanto que as variáveis que foram passadas mantém os seus valores (ou seja, os valores
das variáveis x e y vão ser trocados mas os das varáveis a e b não).

Uma forma de alterar o valor de variáveis dentro das funções é utilizando variáveis globais
(o que é de evitar a todo o custo visto que torna os programas menos genéricos e diminui a
possibilidade de reutilização do código por outro programa pois vai depender de variáveis
que podem não existir. Outra é passando como argumento da função o endereço das
variáveis:

#include <stdio.h>

void troca(int *x, int *y)


{
int aux;

aux = *x;
*x = *y;
*y = aux;
}

main()
{
int a = 2, b = 5;

troca(&a, &b);
printf("%d %d", a, b);
}

Agora programámos a função troca() de forma a trabalharmos com os valores


apontados por x e y, e não criando cópias de valores que as variáveis a e b guardam. Assim
a função troca() vai realmente trocar os valores.

O porquê dos & no scanf()

O scanf é uma função que pretende modificar o valor de variáveis (as variáveis passadas
como argumentos vão passar a ser conter os valores que o utilizador introduzir), e a única
forma de o fazer é passando o endereço dessas variáveis.

Apontadores e arrays

Um vector é um bloco de memória onde são armazenados em posições consecutivas


valores do mesmo tipo:

int a[10], x;
int *ptr_a;

21 | 25
Introdução à Programação em Linguagem C

ptr_a = &a[0]; /* ptr_a fica a apontar para a[0] - endereço inicial do vector a[] */

x = *ptr_a; /* x passa a ser igual a a[0] */

Para aceder-se à posição i do vector é possível escrever:

*(ptr_a + i) que é equivalente a a[i]

É válido escrever:

ptr_a = a; em vez de ptr_a = &a[0];

(o endereço do primeiro elemento do vector é igual ao nome do vector)

Como a[i] é equivalente a *(ptr_a + i) temos que &(a[i]) é equivalente a ptr_a + i

Outra construção equivalente é:

ptr_a[i] e *(ptr_a + i)

No entanto, existe uma diferença entre arrays e apontadores:

 Um apontador é uma variável simples. Podem executar-se as seguintes instruções:


ptr_a = a e ptr_a++ .
 Um vector não é uma variável simples pelo que as seguintes construções são
inválidas: a = ptr_a e a++ .
 A passagem de um vector como argumento de uma função faz-se sempre por
referência, ou seja o que realmente é passado à função é o endereço da primeira
posição do vector, o que é equivalente a passar um apontador para essa posição
de memória. Por exemplo, a chamada à função int strlen(char s[]); (função
que retorna o tamanho da strings) pode ser feita de duas formas:

strlen(s) ou strlen(&s[0])

A declaração da função strlen() também poderia ser feita como:

int strlen(char *s);

22 | 25
Introdução à Programação em Linguagem C

Apontadores e Estruturas

É muito útil e fácil utilizar estruturas e ponteiros em simultâneo:

typedef struct cd
{
char titulo[50];
char grupo[30];
int ano;
} CD;

main()
{
CD *ptr_cd;

CD cd1;

ptr_cd = &cd1;
}

Para acedermos aos campos da estrutura utilizamos o operador: ->

Por exemplo:

strcpy(ptr_cd->titulo ,"By The Way");

strcpy(ptr_cd->grupo,"Red Hot Chili Peppers");

ptr_cd->ano = 2002;

23 | 25
Introdução à Programação em Linguagem C

Exercícios

a. Escreva uma função (e o respectivo programa de teste) que rode os seus 3


argumentos. Se estes se chamarem a, b e c, o valor de a vai para b, o valor de b vai
para c e o valor de c vai para a.

Escreva um programa que utilize uma função para calcular as raízes de uma
equação do segundo grau utilizando a fórmula resolvente.

24 | 25