Introducao Linguagem C
Introducao Linguagem C
Introducao Linguagem C
INTRODUÇÃO À LINGUAGEM
1. INTRODUÇÃO À LINGUAGEM C
1.1. Introdução
A linguagem C foi desenvolvida nos laboratórios Bell na década de 70, tendo surgido
a partir da necessidade de escrever programas, que utilizassem as potencialidades
da linguagem máquina, mas de uma forma mais simples e portátil que esta. Usada
inicialmente para a programação de sistemas, viria pela sua flexibilidade e poder, a
tornar-se numa linguagem de uso geral nos mais diversos contextos, sendo
actualmente muito utilizada pelos programadores profissionais.
A linguagem C pode ser considerada uma linguagem de médio nível, porque para
além de possuir instruções de alto nível e ser tão estruturada como por exemplo o
PASCAL, também possui instruções de baixo nível.
1.2. Características
As suas principais características são:
- Potencialidades e conveniência das linguagens quer de alto nível quer de baixo
nível.
- Pequeno conjunto de palavras reservadas.
- Permitir a criação de novos tipos de dados pelo utilizador.
- "Portabilidade", isto é, os programas escritos em linguagem C podem ser
transportados entre máquinas de diferentes arquitecturas com um número muito
reduzido de alterações.
- Eficiência, através de uma boa ligação aos recursos da máquina.
----------------------------------------------------------------------------------
a Esconder certa complexidade
return expressão;
nome_função(prim_arg, seg_arg,... )
Exemplo2: O seguinte programa chama uma função mul(), que multiplica dois
números inteiros e retorna o resultado. O valor retornado passa a ser o argumento
da função printf que o imprime.
Os dois parâmetros a e b da função mul(), recebem respectivamente os dois
argumentos 5 e 4, com que a função é chamada.
#include <stdio.h>
main()
{
1.4. Instruções
Uma expressão seguida de ‘;’ é uma instrução. As expressões podem ser formadas
por constantes, variáveis e operadores, combinados de uma forma válida. As
instruções dividem-se em simples e compostas. Simples quando se trata de apenas
uma instrução, e compostas quando se trata de um conjunto (bloco) de instruções.
Estes conceitos, de instrução simples e composta, farão mais sentido quando, no
capítulo 3, forem discutidas as instruções de controlo de sequência.
- Instrução simples:
expressão;
Exemplo:
{
instrução
instrução
...
}
Exemplo:
{
x = 10;
y = x + x;
}
2. OPERANDOS E OPERADORES
2.1. Introdução
Na base de qualquer programa estão os operandos e operadores, pois é através
destes que se constroem as expressões que acabarão por formar um programa. As
variáveis e as constantes constituem os operandos que representam os dados,
enquanto os operadores determinam o que lhes fazer. Os operandos classificam-se
através de três atributos:
nome
tipo
classe de armazenamento
As próximas secções tratam exactamente destes atributos, fundamentais para um
correcto entendimento da linguagem C.
2.2. Nomes
Um nome, ou identificador, é uma sequência de letras ou dígitos que começa
obrigatoriamente por uma letra. O sinal _ ("underscore") conta como uma letra, e é
normalmente usado para simular um espaço num nome.
Nomes com letras maiúsculas são diferentes de nomes com letras minúsculas.
Assim sendo, A e a representarão dois nomes distintos. Normalmente em C, usam-
se letras minúsculas para representar as variáveis, e letras maiúsculas para
representar as constantes. Esta utilização de maiúsculas e minúsculas não é uma
regra da linguagem, mas ao ser seguida pelos programadores facilita a leitura dos
programas.
As palavras reservadas int, if, else, etc. da linguagem C, não são permitidas como
nomes. Em seguida apresenta-se a lista das palavras reservadas do C.
Palavras Reservadas
O qualificador short aplica-se a inteiros e tem como objectivo reduzi-los para metade
do seu tamanho (ex: numa máquina em que os inteiros sejam de 4 bytes, o short int
será de 2 bytes). O long aplicado a inteiros tem a função inversa do short. O
qualificador long também se aplica ao tipo double, mas com efeitos que dependem
da sua implementação no compilador.
Os qualificadores signed e unsigned são aplicados ao tipo char ou a qualquer inteiro,
e indicam se o número tem ou não sinal. No caso dos signed o seu bit mais
significativo está reservado ao sinal. Números unsigned são sempre superiores ou
iguais a zero, enquanto os signed poderão ser negativos. Exemplificando, para o
caso do char, uma variável signed char tomaria valores entre -128 e 127, enquanto
que se fosse unsigned char, tomaria valores entre 0 e 255. Isto significa que uma
variável char pode conter qualquer carácter ASCII, mais exactamente os respectivos
códigos, pois estes variam de 0 a 127a.
Todas as variáveis devem ser declaradas antes de serem utilizadas. Uma
declaração especifica um tipo, e contém uma ou mais variáveis desse tipo.
int ano,mes,dia;
declara três variáveis do tipo inteiro cujos nomes são ano, mes e dia.
declara uma variável do tipo char sem sinal, e cujo nome é tamanho. Para este caso
o compilador "alocaria" espaço para um carácter (1 byte). As variáveis podem ser
inicializadas no momento da sua declaração:
int x = -691;
double media = 0;
2.4. Constantes
As constantes são, como o seu nome diz, valores fixos que não podem ser alterados
durante o programa e, têm associado a cada uma delas um determinado tipo de
dado.
Os tipos de constantes inteiras são:
decimal 7 11
octal 07 013
hexadecimal 0x7 0xb
Para identificar o tipo de dado como unsigned usa-se o sufixo u ou U, enquanto para
significar long usa-se o sufixo l ou L, e o sufixo ul ou UL para unsigned long. O tipo
int é assumido por defeito desde que a constante seja inteira e portanto não
necessita de sufixo.
Exemplos:
Um ponto decimal numa "string" (cadeia) de dígitos indica que o objecto é do tipo
double. O expoente pode ser denotado usando e ou E. Uma constante de vírgula
flutuante com o sufixo l ou L é considerada do tipo long double. Para significar float
usa-se o sufixo f ou F.
Os caracteres são denotados através de plicas, por exemplo ‘q’, representa o
carácter q. Os caracteres têm uma representação interna numérica. No código ASCII
o carácter ‘q’ é representado pelo inteiro (em octal) 0161. Então,
\n newline
\t tab
\b backspace
\\ backslash
\r carriage return
Qualquer carácter pode ser especificado pelo seu equivalente numérico usando a
notação ‘\ddd’, onde ddd é um inteiro octal, ou por '\xddd', onde ddd é um inteiro em
hexadecimal.
Exemplo:
char c=´\0161´;
char c=´\033´;
char c=´\1b´;
main()
{
printf ("%s", "OLA\n");
}
a sua representação interna seria o conjunto de caracteres, 'A' 'R' 'R' 'A' 'Y' '\0'.
Exemplo:
#include <stdio.h>
main()
{
int c;
c = 0xa + 010 + 21; /* 0xa é 10 em decimal e 010 é 8 em decimal */
printf ("0xa + 010 + 21 = %x em hexadecimal\n",c);
printf ("0xa + 010 + 21 = %o em octal\n",c);
printf ("0xa + 010 + 21 = %d em decimal\n",c);
printf ("Impressao da string %s\n","ARRAY");
}
2.5. Operadores
Os operadores em C podem dividir-se nas três classes:
aritméticos, relacionais e lógicos bit a bit ( binários )
Consoante os operadores envolvam um, dois ou três operandos, classificam-se em
unários, binários e ternários.
x++ ; <=> x = x + 1;
y = x++; <=> y = x;
x = x + 1;
y = ++x; <=> x = x + 1;
y=x;
Lógicos:
&& e (and)
|| ou (or)
! negação (not)
Exemplo:
Implicitamente é avaliada primeiro a condição x!=y , e depois se, e só se, a esta tiver
resultado lógico verdadeiro, será avaliada a segunda condição a>b. Se ambas forem
verdadeiras, então será executada a instrução --n.
Neste caso, para o compilador ter ou não ter parêntesis nas condições é
exactamente igual. O interesse é tornar a expressão mais clara. Noutras situações
poderá ser o de alterar as precedências.
Exemplo: A instrução
x = a > b ? a : b;
if ( a > b )
x = a;
else
x = b;
Os operadores bit a bit (binários) permitem, como o nome o diz, operações ao nível
dos bits. São seis os operadores bit a bit, os quais só poderão ser aplicados a
expressões do tipo inteiro:
x = 10111011
y = 10101010
~x 01000100
x << 2 11101100
y >> 2 00101010
x&y 10101010
x|y 10111011
x^y 00010001
Atenção ! Ter sempre cuidado em não confundir os operadores lógicos && e ||, com
os operadores binários & e |.
a&b
a|b
a^b
a <<= b
b >>= a
2.6. Precedências
O conhecimento da ordem de precedência dos vários operadores é fundamental
para que se possam construir expressões correctamente. A tabela seguinte lista as
precedências por ordem decrescente bem como o sentido de avaliação
(associatividade). Ter em atenção que alguns dos operadores indicados na tabela
ainda não foram discutidos.
Operadores Associatividade
Por vezes surge a necessidade de trabalhar operandos cujos tipos de dados diferem
uns dos outros. Nestas situações há que proceder à conversão de tipos, isto é
conversão desses diferentes tipos num tipo comum, de forma a possibilitar a
resolução das expressões. As conversões caem em três classes: automática,
requerida pela expressão e forçada.
ii) Requerida pela expressão: Quando há mistura de tipos, sendo necessária para a
resolução da expressão.
Exemplo:
int x;
double y;
x=x+y; /* conversão num double seguida de */
/* uma conversão num inteiro */
iii) Forçada ( "cast" ): Este tipo de conversão pode ser requerida pelo utilizador
sempre que este a considere necessária, e faz-se precedendo a variável pelo novo
tipo entre parêntesis. Ter em atenção que a conversão para tipos menores pode
truncar a variável.
Forma geral:
Neste exemplo o "cast" tornou-se necessário para que o resultado da divisão fosse
um inteiro, perdendo-se a parte fraccionária.
2.8. Typedef
Se um tipo de dado é precedido pela palavra typedef então o identificador na
declaração é entendido pelo compilador como um novo nome para esse tipo de
dado.
/* Programa area.c */
#include <stdio.h>
main()
{
AREA x;
float lado1, lado2;
printf ("\nIntroduza os valores dos lados: ");
scanf ("%f%f", &lado1, &lado2);
/* scanf lê dados do teclado com o tipo indicado
entre aspas. Neste caso 2 floats %f%f */
x = lado1*lado2;
printf ("A área é igual a %f",x); /* %f indica um float para escrita */
}
Ter em atenção que em última instância a variável x é um float, como se prova pela
formatação (com %f) utilizada no printf.
2.9. Exercícios
1. Escrever um programa que leia três inteiros correspondentes a uma hora em
horas minutos e segundos, a converta em segundos, e imprima o resultado.
Supondo as seguintes variáveis para as horas minutos e segundos, a leitura poderia
ser:
int horas, minutos, segundos;
long int result_em_segundos;
...
scanf("%d%d%d", &horas, &min, &seg); /* notar mais uma vez o operador & */
3.1. Introdução
A linguagem C, como já foi dito, apresenta características de uma linguagem
estruturada. Assim sendo, possui instruções de controle de sequência, que permitem
especificar a ordem pela qual são executadas as instruções de um programa. As
instruções de controle de sequência são de dois tipos: condicionais (if e switch) e de
ciclo (while, do/while e for). Ter em atenção que quando se tem mais do que uma
instrução (instrução composta) estas deverão ser colocadas entre chavetas, como já
foi afirmado anteriormente.
Existem duas instruções que permitem alterar a sequência normal de execução dos
ciclos: a instrução break e a instrução continue. A instrução break interrompe
definitivamente a execução do ciclo, enquanto que, a instrução continue interrompe
a execução de uma iteração saltando para o início da iteração seguinte. A instrução
break é também usada na instrução switch.
3.2. Instrução IF
Esta é a instrução mais simples para controle de sequência. O seu funcionamento é
o seguinte: faz-se a avaliação de uma expressão, e caso ela seja verdadeira é
executado um primeiro bloco contendo uma ou mais instruções, em contrário, será
executado se existir, um segundo bloco iniciado pela palavra else. Há duas formas
de utilização:
if (expressão)
instrução;
ou
if (expressão)
instrução;
else
instrução;
Exemplo1: Neste exemplo, a função idade, verifica em que intervalo se situa uma
idade i dada como argumento. No caso de i ser maior do que 70 imprime "Idoso",
senão se for maior do que 30 imprime "Adulto", senão imprime "Jovem".
/* Programa bissexto.c */
#include <stdio.h>
main()
{
int ano;
printf ("\n Qual o ano que pretende testar: ");
scanf ("%d", &ano);
/* ano % valor == 0 - Testa se ano é divisível por valor (resto 0) */
if ( ano % 400 == 0 || (ano % 4 == 0 && ano % 100 != 0) )
printf ("\nO ano de %d É bissexto!\n", ano);
else printf ("\nO ano de %d NÃO é bissexto\n", ano);
}
Sintaxe:
switch (expressão)
{
case constante1 : instrução;
break;
case constante1 : instrução;
break;
...
default : instrução;
break ;
}
Exemplo: A função seguinte verifica se uma cor, dada como argumento, pertence
ao sistema RGB e imprime mensagens de acordo com a situação.
Como se pode ver neste exemplo vários cases podem conduzir à execução da
mesma instrução.
A instrução break permite sair (quebrar) do switch. Caso esta não seja incluída todas
as instruções abaixo do case seleccionado também seriam executadas até que
surgisse um break ou surgisse a chaveta que termina o switch. No caso do exemplo,
supondo que a cor era 'G', se não tivesse a instrução break, as instruções
correspondentes aos cases seguintes e default seriam executadas.
A instrução default é opcional e é avaliada quando nenhuma das constantes
coincide com o resultado da expressão.
Sintaxe:
while (expressão)
/* Programa contach.c */
#include <stdio.h>
main()
{
long caracteres_lidos=0;
char carácter;
scanf ("%c", &carácter);
while( caracter!=EOF) {
caracteres_lidos++;
scanf ("%c", &carácter);
}
printf ("\nForam lidos %ld caracteres!\n", caracteres_lidos);
}
Exemplo2: Programa que testa a função pot_int_pos que calcula a potência inteira
positiva de um número.
/* Programa pot.c */
#include <stdio.h>
main()
{
int base, exp;
printf ("Introduza uma base e um expoente (inteiros >0): ");
scanf ("%d%d", &base, &exp);
printf ("%d levantado a %d = %d", base, exp, pot_int_pos(base,exp));
}
Sintaxe:
do
instrução simples ou composta
while (expressão);
Exemplo1: Programa que testa uma função que apenas lê dígitos. A função lê
caracteres do teclado até que um seja dígito. O dígito é depois retornado.
/* Programa ledigito.c */
#include <stdio.h>
main()
{
char digito;
digito=le_digito();
printf ("O digito lido foi: %c\n",digito);
}
char le_digito()
{
char c;
do /* Como o ciclo contém apenas uma instrução não
necessita de chavetas. */
scanf ("%c",&c);
while (c<'0' || c>'9');
return c;
}
Sintaxe:
for (início; teste; incremento)
instrução
#include <stdio.h>
main()
{
int i;
printf ("i = %d\n", i);
}
e cuja saída será: 0
1
Exercício: Reescreva o programa do exemplo 2 da secção 3.3 para o ciclo while (de
cálculo de uma potência), usando desta vez um ciclo for.
#include <stdio.h>
main()
{
char carácter;
long int caracteres_lidos=0;
scanf ("%c", &carácter);
while( caracter!=EOF) { /* Enquanto carácter lido diferente de
caracteres_lidos++; EOF executa ciclo */
if(caracter>='A' && caracter<='Z')
caracter=caracter - 'A' + 'a';
printf ("%c",carácter);
scanf ("%c", &carácter);
}
printf ("\nForam lidos %ld caracteres!\n", caracteres_lidos);
}
3.7. Exercícios
1. Converta o seguinte algoritmo em pseudo-código, que calcula o maior e o
menor de 3 números inteiros, para C. O programa determina o maior e o
menor entre apenas dois dos valores. Posteriormente determina o máximo e o
mínimo entre o terceiro valor e o maior e o menor dos dois anteriores.
Prog MaiorMenor
Ler(v1,v2,v3)
Se v1>v2
Então max <- v1
min <- v2
Senão max <- v2
min <. v1
Fse
Se v3>max
Então max <- v3
Senão Se v3<min
Então min <- v3
Fse
Fse
Escrever('O maior =', max, ' e o menor =', min)
Fprog
que implica um ciclo para esses produtos sucessivos, e uma variável que recebe
os valores desde (número -1) até 1.
/* Programa fatorial.c */
#include <stdio.h>
/* Como num já foi decrementado, o primeiro produto vai ser entre num e
o número imediatamente abaixo deste. Notar ainda a inexistência da
primeira expressão no ciclo for. */
main()
{
int numero;
printf ("\nCALCULO DO FACTORIAL\n");
printf ("\nIntroduza um número: ");
scanf ("%d", &numero);
printf ("%d! == %ld\n", factorial(num));
}
5. Escreva um programa que após ler três inteiros referentes ao dia, mês e ano
de uma data, bem como a duração de uma tarefa em dias, determine qual a
data de conclusão dessa tarefa.
4.1. Introdução
Nos capítulos anteriores utilizaram-se algumas funções de entrada e saída de dados
que, só agora serão explicadas com mais pormenor. Estas facilidades, não são
intrínsecas à linguagem, tendo sido desenvolvidas à parte e encontram-se em
bibliotecas (conjunto de ficheiros fonte compilados e agrupados num ficheiro). As
funções básicas de "input" (entrada) e "output" (saída) disponíveis em todas as
implementações de C constituem a "biblioteca de rotinas padrão" ("Standard library
routines"). Várias declarações e macros necessárias a estas rotinas são incluídas
num programa através da linha
# include <stdio.h>a
printf (s_control, arg1, arg2, ...): escreve a "string" de controle s_control no terminal.
sprintf ((buf, s_control, arg1, arg2, ...): o mesmo que printf excepto que a saída é
colocada num "buffer" (i.e., um vector) especificado por buf.
c: um simples carácter.
d: inteiro notação decimal.
o: inteiro notação octal (não esquecer o zero do número que deve
ser incluído explicitamente).
x: inteiro em notação hexadecimal; não esquecer o 0x do número
u: inteiro sem sinal em notação decimal.
s: vector de caracteres: os caracteres são imprimidos em sucessão até o
carácter nulo ser alcançado.
f: float ou double, imprimido em notação decimal de acordo com a
especificação opcional descrita abaixo.
e: float ou double imprimido em notação científica de acordo com a
especificação opcional descrita abaixo.
g: float ou double, imprimindo como um %e ou %f.
a Alguns dos compiladores actuais, incluem automaticamente as funções da standard library, não
necessitando desta linha
Qualquer outro carácter é imprimido literalmente; por exemplo, printf ("%%") imprime
o sinal de percentagem. Os números são escritos justificados à direita. As
especificações podem opcionalmente incluir (na ordem seguinte):
-Um sinal menos que indica que o argumento deve ser justificado à esquerda no
campo de saída.
-Uma “string” de dígitos que especifica a largura mínima do campo para este
argumento. Se o argumento convertido tiver menos caracteres é encostado à
esquerda (ou à direita se o argumento é um ente justificado à esquerda).
-Um ponto que separa a largura do campo da precisão.
-Uma “string” que especifica o nº máximo de caracteres a ser imprimidos da
“string”, ou (se foi imprimido um nº de vírgula flutuante) o nº de dígitos a ser
imprimido à direita do ponto decimal. Se isto é omitido para nº de vírgula
flutuante, a precisão por defeito é 6.
-O carácter l indica que o argumento é um long.
int i;
scanf ("%d",i);
tal, no entanto não funciona, porque os argumentos da scanf devem ser endereços.
Assim, dever-se-á escrever,
scanf ("%d",&i);
em que & é o operador que permite obter o endereço da variável. Deve-se ter em
atenção que a situação é distinta quando se pretende ler uma “string”, pois o nome
da “string” é um endereço, como se discutirá no capítulo sobre "arrays". Um dos
erros mais comuns com scanf é esquecer isto; fazer sempre com que todos os
argumentos da função scanf sejam endereços.
A função
funciona mais ou menos como a scanf excepto que lê dados de uma “string” buf em
vez de os ler do teclado.
A “string” de controle das funções scanf, ou sscanf pode conter espaços brancos (os
quais são ignorados), especificações de conversão, e caracteres vulgares.
int c;
c = getchar();
putchar(c);
char string[80];
puts(string);
gets(string);
#include <stdio.h>
main()
{
int carácter;
caracter=getchar();
while(caracter!=EOF) {
putchar(carácter);
caracter=getchar();
}
}
c = getche();
c = getch();
Idêntica à anterior, apenas com a diferença de não mostrar o carácter lido. O facto
de estas funções não necessitarem que a tecla Return seja premida, faz com que
seja de grande interesse a sua utilização. Normalmente, é necessário a inclusão da
instrução,
#include <conio.h>
#include <stdio.h>
#include <conio.h>
le_digito()
{
char c;
do
c=getch();
while (c<'0' || c>'9');
putchar(c);
return c;
}
4.6. Exercícios
1. Escreva um programa que conte e imprima o número de dígitos, vogais e
consoantes lidas do teclado.
5. FUNÇÕES
5.1. Introdução
Um programa em linguagem C pode ser composto por uma (função main) ou mais
funções, distribuídas por um ou mais ficheiros. As funções são a única forma de se
agruparem as instruções que se pretendem executar, constituindo assim uma
unidade básica na programação em C. A linguagem C está feita de modo a que se
construam facilmente funções muito eficientes, de tal forma que podem ser utilizadas
em diferentes programas sem alterações.
5.2. Definição
Relembrando do primeiro capítulo, a forma geral da definição de uma função é:
classe_armazenamento tipo_dado nome (declarações_lista_de_parâmetros)
{
declarações das variáveis locais
instruções
}
Sempre que se pretenda que uma função retorne um valor, então deverá ser
incluída a instrução return.
As variáveis da lista de parâmetros podem ser consideradas como variáveis locais,
que são inicializadas com os valores dos argumentos da chamada da função. O tipo
de dado que precede o nome da função é o tipo do objecto que a função retorna.
Por exemplo, a definição double raiz(double num) significa uma função que retorna
um double. Os tipos podem ser portanto os mesmos que os definidos para as
variáveis.
Se o tipo de uma função não é declarado explicitamente, então o tipo retornado por
defeito é int. E se algum dos parâmetros não tiver a declaração explícita do tipo, este
é também assumido como int.
Uma função retorna automaticamente quando atinge o fim do corpo da função, a não
ser que antes encontre a instrução return. A sintaxe da instrução return:
return (expressão);
Se uma função retorna um não inteiro então qualquer rotina que a chame deve
declarar o tipo do objecto que ela retorna. Eis a distinção entre:
Em main é declarada a função raiz(), para que o compilador saiba qual o tipo de
dado que ela retorna.
/* Programa raiz.c */
main( )
{
float a, r, raiz( ); /* declaração da função raiz */
printf ("\nIntroduza um número:");
scanf ("%f",&a);
r = raiz(a);
printf ("A raiz quadrada de %f é %f",a,r);
}
{
float y, z;
y = x;
do {
z = y;
y = (z + x/z)/2;
} while (z != y);
return y;
}
No contexto das funções existem dois conceitos importantes que por vezes dão
origem a alguma confusão:
{
...
Quanto à classe de armazenamento de uma função pode ser:
O equivalente em Fortran::
SUBROUTINE TROCA(X,Y)
INTEGER X,Y,TEMP
TEMP=X
X=Y
Y = TEMP
RETURN
END
troca(x,y)
int x,y;
{
int temp;
temp = x;
x = y;
y = temp;
}
Esta rotina troca unicamente os valores das variáveis da função (na "stack"), e deixa
os valores originais da rotina que chama inalteráveis. Supondo que troca() era
invocada do seguinte modo:
Como se pode observar x e y são variáveis distintas das dos argumentos (a e b),
limitando-se a receber os valores destas, como se queria demonstrar.
Para que na função se pudessem alterar os valores das variáveis da função que
chama, haveria que passar os endereços dessas variáveis, e os parâmetros da
função teriam de ser apontadores. Então a função troca() seria invocada do seguinte
modo:
atoi(char s[])
{
double atof();
return atof(s);
}
int n;
double x, log();
x = log((double)n);
/* Programa printarg.c */
#include <stdio.h>
main (int argc, char argv[][])
{
int i;
for (i = l; i < argc; i++)
/* argv[i] representa 1 argumento, mais concreta/e o seu
endereço */
printf ("Arg. %d é\t(%s)\n", i,argv[i]);
printf ("E o programa chama-se %s\n",argv[0]);
}
Arg. 1 é (1)
Arg 2 é (2)
Arg3 é (ultimo)
E o programa chama-se printarg.exe
5.6 Conclusão
Como conclusão, recapitulam-se em seguida alguns aspectos mais importantes
sobre as funções:
- Permitem dividir o programa em partes funcionais mais pequenas.
- Podem residir em bibliotecas e/ou noutros ficheiros fonte.
- A comunicação do exterior para a função é feita através dos argumentos.
- A comunicação da função para o exterior é feita através de um valor de retorno,
sendo este do mesmo tipo da função.
- Todas as funções têm um determinado tipo associado.
- A definição da função pode ser feita em qualquer ponto.
- A função pode invocar-se a si própria (recursividade).
- Uma função cujo tipo é antecedido por static só é visível no ficheiro aonde está
definida.
5.7. Exercícios
3. Escreva uma função que retorne o número de dígitos que compõem a parte inteira
de um número real positivo, passado como argumento da função, Escreva também
um programa que teste a função.
6. VECTORES
6.1. Introdução
Vamos supor, que se pretendia um programa para ler a média das notas de cada um
dos cerca de 3000 alunos do ISEP, calcular a média das médias, e depois para cada
aluno determinar o desvio da sua média relativamente à média das médias. Uma
solução para guardar cada uma das médias, consistiria em definir 3000 variáveis,
por exemplo:
float med_1, med_2, med_3, med_4, med_5, med_6, med_7, med_8, med_9,
med_10, med_11, med_12, med_13, med_14, med_15, med_16, med_17, med_18,
med_19, . . .
float media[3000];
int num;
Deste modo, para a leitura das 3000 médias, poder-se-ia utilizar um ciclo, como a
seguir se ilustra:
----------------------------------------------------------------------------------
a Neste texto é usado o também o termo array para significar vector.
int a[4];
diz que a é uma variável do tipo vector de 4 elementos do tipo int. A sua
representação será:
a[0] = 1;
a[1] = 2;
a[2] = 3;
virá:
a == 100
&a[0] == 100
&a[1] == 102
&a[2] == 104
&a[3] == 106
Em virtude de ser uma constante, não é possível atribuir valores ao nome do vector,
como se ilustra no seguinte caso:
int a[4];
a = 2;
a[0] =2;
a[0]++;
a[1]=2*a[0];
int ecra[25][80];
irá definir (criar) um vector de quatro inteiros e inicializar a[0] a 1, a[1] a 2 e a[2] a 3.
No entanto a definição:
m[0][0] é igual a 1
m[0][1] é igual a 2
m[0][2] é igual a 3
m[1][0] é igual a 11
m[0][0] é igual a 11
m[1][1] é igual a 22
m[1][2] é igual a 33
Exemplo 1: O programa media.c lê 100 notas para um vector, e calcula a média das
notas.
/* Programa media.c */
#include <stdio.h>
main()
{
int i;
float notas[100], soma;
/* Ciclo que lê 100 notas e armazena-as no vector notas.*/
for( i = 0; i < 100; i++) {
printf ("Nota %d=?",i+1);
scanf("%f,¬as[i]);
}
/* A variável acumuladora soma inicializada a zero. */
soma=0;
/* Ciclo que soma as 100 notas. */
for( i = 0; i < 100; i++)
soma = soma + notas[i];
printf ("A média é =%f",soma/100);
}
#include <stdio.h>
main( )
{
int v[2];
v[0]=2;
v[1]=3;
troca( v );
printf ("v[0] = %d,v[1] = %d", v[0],v[1]);
}
em que ao nome do vector x corresponderá o valor 200, ou seja, x será igual a 200.
main( )
{
int v[4];
v[2]=2;
v[3]=3;
troca( ? );
printf ("v[0] = %d,v[1] = %d", v[2],v[3]);
}
pense como faria a chamada da função troca(), se pretendesse agora trocar os dois
elementos v[2] e v[3] do vector.
Exercício 2: Escrever uma função que some duas matrizes e coloque o resultado
numa terceira.
Resolução:
M_COL é uma constante (as constantes serão estudadas no capítulo 8). lin e col são
respectivamente o número de linhas e colunas das matrizes. No ciclo externo são
percorridas todas as linhas, e para cada uma são percorridas todas as colunas.
char pal[11];
a saída é OLA.
compara s1 com s2, e devolve 0 se s1 igual a s2, > 0 se s1> s2 e < 0 se s1<s2.
Uma lista completa destas funções pode ser encontrada nos manuais de qualquer
compilador de C. Para a utilização destas funções, é requerida a linha
#include <string.h>
O vector é percorrido até ser encontrado o carácter nulo. Por cada posição
percorrida conta é incrementado.
return (i);
}
Esta função, no caso de o valor pesquisado existir no vector retorna a posição onde
foi encontrado. No caso de não existir retorna um i igual ao número de elementos do
vector.
6.6. Exercícios
1. Escreva uma função que multiplique duas matrizes dadas como argumentos.
Faça um programa que teste a função. Para a leitura das matrizes desenvolva uma
função.
2. Escreva uma função que dado como argumento um vector de inteiros o ordene
por ordem crescente ou decrescente consoante o valor de uma opção dada também
como argumento.
3. Desenvolva a sua versão das funções strcpy, strcmp e strcat. Desenvolva também
um programa que as teste. As declarações e objectivos destas funções são os
seguintes:
- strcmp(char str1[], char str2[]), compara str1 com str2. Retorna >0 se
str1>str2, <0 se o inverso e zero se iguais;
- strcat(char str1[], char str2[]), concatena (acrescenta), str2 a str1.
4. Escreva uma função que dada uma “string” (como argumento) a converta num
inteiro.
6. Escreva uma função que dado um vector de “strings”, o ordene. Cada “string” do
vector é uma palavra. Escreva também o programa que lê o vector e testa a função.
7. [Exame] Escreva uma função que dadas duas “strings” pesquise a existência da
segunda na primeira, e caso a encontre retorne o índice correspondente à sua
posição. Se não existir a função deverá retornar -1. A posição a partir da qual se
inicia a pesquisa é passada como argumento. Não deve usar a função já existente
do C strstr(). A primeira linha da função deverá ser:
8. Escreva uma função que dada uma “string”, como argumento, a inverta. Escreva
também um programa que a teste.
7. O PRÉ-PROCESSADOR
7.1. Introdução
O pré-processador é o responsável pela primeira fase da compilação de um
programa em C. Nesta fase são processadas todas as linhas começadas pelo
carácter #. São várias as directivas de pré-processamento.
7.2. Include
Se um programa em C contém a linha
# include FILE
então o pré-processador irá substituir essa linha pelo conteúdo do ficheiro referido
por FILE. Isto é feito antes de qualquer compilação. Isto é por vezes usado por
ficheiros "header" contendo definições dos dados usados em ficheiros diferentes.
'FILE' pode ter uma das duas formas:
# include "pilha.h"
# include < stdio.h >
# include < ctype.h >
# include < math.h >
7.3. Define
Se um ficheiro contém uma linha da forma
então cada ocorrência do identificador nome no resto do ficheiro irá ser substituida
por string. Isto é feito pelo pré-processador antes da compilação.
É um bom estilo de programação usar #define para todas as constantes. É muito
mais simples alterar uma linha da forma.
pode ser usado exactamente como se existisse uma função que determine quando é
que o carácter c é um digito. Outro exemplo é a definição,
y = ABC (a+ b)
y = (a + b < 0 ? -a + b : a +b);
#define NEG(x) -x
int a=1;
printf ("%", - NEG(a) );
Em
não deverá ser deixado qualquer espaço entre o identificador nome e o parêntesis
esquerdo.
O uso abusivo do #define com argumentos pode levar a alguns erros aborrecidos.
Notar que a macro anterior ABS tem a vantagem de que trabalhará para variáveis de
diferentes tipos. Se uma macro tem uma “string” de substituição muito longa ou
complicada, talvez seja preferível implementá-la como uma função.
Existem outras instruções de pré-processamento que não são aqui referidas, mas
que poderão ser encontradas em qualquer manual.
ÍNDICE
1. INTRODUÇÃO À LINGUAGEM C ...........................................................................................2
1.1. INTRODUÇÃO.................................................................................................................................2
1.2. CARACTERÍSTICAS.......................................................................................................................2
1.3. ESTRUTURA DE UM PROGRAMA ..................................................................................................2
1.4. INSTRUÇÕES ................................................................................................................................4
2. OPERANDOS E OPERADORES................................................................................................6
2.1. INTRODUÇÃO ...............................................................................................................................6
2.2. NOMES .........................................................................................................................................6
2.3. TIPOS DE DADOS .........................................................................................................................6
2.4. CONSTANTES ...............................................................................................................................8
2.5. OPERADORES ..............................................................................................................................10
2.5.1. Operadores Aritméticos ........................................................................................................10
2.5.2. Operadores Incremento e Decremento..............................................................................10
2.5.3. Operadores relacionais e Operadores lógicos ..................................................................11
2.5.4. Operador Condicional ...........................................................................................................11
2.5.5. Operadores Bit a Bit ..............................................................................................................11
2.7. PRECEDÊNCIAS ...........................................................................................................................12
2.8. CONVERSÃO DE TIPOS ................................................................................................................13
2.9. TYPEDEF ......................................................................................................................................14
2.10. EXERCÍCIOS ...............................................................................................................................15
3. INSTRUÇÕES DE CONTROLE DE SEQUÊNCIA..................................................................17
3.1. INTRODUÇÃO.................................................................................................................................17
3.2. INSTRUÇÃO IF..............................................................................................................................17
3.3. INSTRUÇÃO SWITCH..................................................................................................................18
3.4. CICLO WHILE .............................................................................................................................19
3.5. CICLO DO – WHILE ...................................................................................................................21
3.6. CICLO FOR..................................................................................................................................22
3.7. EXERCÍCIOS .................................................................................................................................23
4. OPERAÇÕES DE ENTRADA / SAÍDA......................................................................................25
4.1. INTRODUÇÃO ...............................................................................................................................25
4.2. SAÍDA FORMATADA......................................................................................................................25
4.2.1. Especificações da Saída Formatada ..................................................................................25
4.3. ENTRADA FORMATADA.................................................................................................................26
4.3.1. Especificações da entrada Formatada ...............................................................................27
4.4. OUTRAS FUNÇÕES DA BIBLIOTECA STANDARD ..........................................................................28
4.5. OUTRAS FUNÇÕES ......................................................................................................................29
4.6. EXERCÍCIOS .................................................................................................................................29
5. FUNÇÕES......................................................................................................................................30
5.1. INTRODUÇÃO ...............................................................................................................................30
5.2. DEFINIÇÃO ...................................................................................................................................30
5.3. PARÂMETROS DE UMA FUNÇÃO ..................................................................................................32
5.4. CONVERSÃO DE TIPOS ................................................................................................................34
5.5. ARGUMENTOS DA LINHA DE COMANDO ......................................................................................34
5.6. CONCLUSÃO ................................................................................................................................35
5.7. EXERCÍCIOS .................................................................................................................................36
6. VECTORES ...................................................................................................................................37
6.1. INTRODUÇÃO ...............................................................................................................................37
6.2. VECTORES NA LINGUAGEM C......................................................................................................38
6.3. VECTORES COMO ARGUMENTOS DE FUNÇÕES ..........................................................................40
6.4. "STRINGS" (CADEIAS DE CARACTERES) .....................................................................................42
6.5. ORDENAÇÃO E PESQUISA ...........................................................................................................45
6.5.1. Ordenação por Selecção......................................................................................................45
6.5.2. Ordenação por Inserção .......................................................................................................45
6.5.3. Pesquisa Sequencial.............................................................................................................46
6.5.4. Pesquisa Binária ....................................................................................................................47
6.6. EXERCÍCIOS .................................................................................................................................47
7. O PRÉ-PROCESSADOR .............................................................................................................50
7.1. INTRODUÇÃO.................................................................................................................................50
7.2. INCLUDE ........................................................................................................................................50
7.3. DEFINE. .........................................................................................................................................50
7.4. DEFINE COM ARGUMENTOS ..........................................................................................................51