.c
(letra minúscula)#include <stdio.h>
int main(void)
{
("To C or not to C, ");
printf("that is the question.\n");
printfreturn 0;
}
Para ser executado, um programa em C tem primeiro de ser traduzido para código-máquina.
A tradução é efetuada por programa compilador.
Nestas aulas: vamos usar o GCC (GNU Compiler Collection).
o pré-processador interpreta diretivas (linhas que começam
por #
)
o compilador traduz o código C para código-máquina
o ligador (linker) combina o código-máquina gerado com as bibliotecas necessárias
Em sistemas GNU/Linux: o pré-processador, compilador e ligador são
executados em sequência pelo comando gcc
.
Invocamos o compilador usando o interpretador de comandos Linux (shell):
$ gcc -o hello hello.c
Produz um ficheiro hello
que podemos executar:
$ ./hello
To C or not to C, that is the question.
directivas int main(void) { instruções }
#
;
e.g.: #include <stdio.h>
stdio.h
contém as definições associadas a
entrada/saidaprintf
está declarado neste
headerreturn
main
main
que é
executada quando o programa iniciamain
representa o código de
erro para o sistema operativoint main(void)
{
....
return 0;
}
return
(equivale a retornar
0)("To C or not to C, ");
printf("that is the question.\n");
printfreturn 0;
printf
e return
printf("...")
imprimem o texto entre aspas na
saida-padrão (terminal) To C or not to C, that is the question.
;
)(
printf"To C or not to C, "
);
("To C or "); printf("not to C, "); printf
/*
e termina com
*/
/* Isto é um comentário */
/*
Ficheiro: hello.c
Programa: Imprime uma mensagem de exemplo
*/
Atenção: esquecer de fechar um comentário pode fazer com que o compilador ignore parte do programa.
("To be "); /* comentário aberto
printf printf("or not to be; "); /* fechado */
("that is the question.\n"); printf
// Isto é um comentário
//
e termina no final da linhaint
e float
int
pode guardar valores inteiros
positivos e negativos; e.g.:
0 1 -23 397
int
dependem da
implementação; e.g.:
float
guarda valores de
vírgula-flutuante com precisão simples0.0253 -1.25 123.555
As variáveis têm de ser declaradas antes do uso:
int altura;
float raio;
Podemos declarar múltiplas variáveis do mesmo tipo duma só vez:
int altura, largura, profundidade;
float raio, massa;
Até C89: todas as declarações têm de ocorrer antes das instruções.
int main(void) {
/* declarações de variáveis */
int altura, largura;
float raio;
/* seguem-se instruções */
...
}
Em C99: declarações e instruções podem ser misturadas (desde que a declaração ocorra antes do uso).
Podemos definir ou modificar o valor de uma variável usando uma atribuição.
int altura; // declaração
= 8; // atribuição altura
altura
No lado direito duma atribuição podemos usar expressões
e.g.
constantes, variáveis e operações.
int altura, largura, area;
= 8;
altura = 3;
largura = altura * largura;
area // area é 24
Um programa para calcular o volume \(V\) de uma caixa retangular.
Exemplo:
\[ V = 11 \text{cm} \times 5 \text{cm} \times 6 \text{cm} = 330 \text{cm}^3 \]
#include <stdio.h>
int main(void) {
int l, w, h, v; // dimensões e volume
= 11; // comprimento
l = 5; // largura
w = 6; // altura
h = l*w*h; // cálculo do volume
v
("LxWxH: %d*%d*%d (cm)\n", l,w,h);
printf("Volume: %d (cm^3)\n", v);
printfreturn 0;
}
Podemos usar a função de bibloteca printf
para imprimir
valores das variáveis. Exemplo:
int alt;
= 6;
alt ("Altura: %d cm\n", alt); printf
Imprime o texto:
Altura: 6 cm
%d
é um campo que é substituido pelo valor duma
variável inteira em decimal.
Para valores float
usamos o campo %f
.
float custo;
= 123.45;
custo ("Custo: EUR %f\n", custo); printf
Resultado:
Custo: EUR 123.449997
float
!%f
apresenta o resultado arrendondado a 6 casas
decimaisPara forçar formatação com \(n\)
casas decimais usamos %
\(.n\)f
:
Exemplo:
("Custo: EUR %.2f\n", custo); printf
Resultado:
Custo: EUR 123.45
Podemos formatar vários valores num só printf
:
("Altura: %d cm; Custo: EUR %.2f\n",
printf, custo); alt
Atenção:
%d
para
int
, %f
para float)scanf
é usada para ler valores
da entrada-padrão (teclado)printf
o 1º argumento é o formato dos
dadosn
int n;
("%d", &n); scanf
&
antes do nome da variável a ler (mais tarde veremos porquê)Para ler um float
não necessitamos de especificar casas
decimais.
float x;
("%f", &x); scanf
Funciona com ou sem casas decimais na entrada; exemplos:
123
123.4
123.4567
Vamos alterar o programa de exemplo anterior para ler as dimensões da caixa.
#include <stdio.h>
int main(void) {
int l, w, h, v; // dimensões e volume
("L=?"); scanf("%d", &l);
printf("W=?"); scanf("%d", &w);
printf("H=?"); scanf("%d", &h);
printf= l*w*h; // cálculo do volume
v
("LxWxH: %d*%d*%d (cm)\n", l,w,h);
printf("Volume: %d (cm^3)\n", v);
printfreturn 0;
}
int x, y;
= x + 1; // variável x não-inicializada y
gcc
pode detetar variáveis
não-inicializadas usando a opção -Wall
int alt = 8;
int alt = 8, larg = 5, comp = 11;
int alt, larg, comp = 11;
// só inicializa uma variável (comp)
Exemplos válidos:
times10 get_Next_Char _done
Exemplos inválidos:
10times get-Next-Char máximo
get_next_char
get_next_Char
get_Next_Char
são identificadores diferentes (seria confuso usá-los num mesmo programa…).
Não podemos usar as seguintes palavras reservadas como identificadores.
auto enum restrict unsigned
break extern return void
case float short volatile
char for signed while
const goto sizeof _Bool
continue if static _Complex
default inline struct _Imaginary
do int switch
double long typedef
else register union
#define
para
definir macros#define INCHES_PER_METER 39.3701
/* factor de conversão:
polegadas por cada metro */
O pré-processador substitui as macros textualmente.
Exemplo:
inches = meters * INCHES_PER_METER;
após processamento fica:
inches = meters * 39.3701;
Um programa para calcular a área de uma circunferência.
A área de uma círcunferência de raio \(r\) é \[ A = \pi r^2 \] (onde \(\pi\) é a constante \(3.14159\ldots\)).
#include <stdio.h>
#define PI 3.14159
int main(void) {
float raio, area;
("Raio da circunferência?");
printf("%f", &raio);
scanf= PI * raio * raio;
area ("Área: %f\n", area);
printfreturn 0;
}
Um programa em C é uma sequência de símbolos (“tokens”):
Exemplo: a instrução
("Área: %f\n", area); printf
contém sete símbolos:
printf |
identificador |
( |
pontuação |
"Área: %f\n" |
cadeia de carateres |
, |
pontuação |
area |
identificador |
) |
pontuação |
; |
pontuação |
#include <stdio.h>
#define PI 3.14159
int main(void) {float raio,area;printf(
"Raio da circunferência?");scanf("%f",&raio);
area=PI*raio*raio;printf("Área: %f\n",area);
return 0;}
Devemos usar espaços, tabulações e mudança de linha para aumentar a legibilidade do programa:
#include <stdio.h>
#define PI 3.14159
int main(void) {
float raio, area;
("Raio da circunferência?");
printf("%f", &raio);
scanf= PI * raio * raio;
area // calcular a área
("Área: %f\n", area);
printfreturn 0;
}
adição | a+b |
subtração | a-b |
multiplicação | a*b |
divisão | a/b |
resto da divisão | a%b |
menos unário | -a |
mais unário | +a |
= +1;
i = -i; j
+
unário não tem qualquer efeito; é usado
principalmente para sinalizar constantes positivas+
, *
, e /
permitem misturar
operandos inteiros e vírgula-flutuanteint
e float
, o
resultado é um float
2+0.5
dá 2.5
; 3.5/2
dá
1.75
/
é o
quociente:
3/4
dá 0
10/3
dá 3
i%j
é o resto da divisão inteira de
i
por j
:
10%3
dá 1
12%4
dá 0
/
e
%
%
devem ser inteiros/
ou %
for 0, o
resultado é indefinido (divisão por zero)%
for negativo:
i%j
tem o mesmo sinal que i
i+j*k
?
i
com o resultado de multiplicar j
por k
”i
com j
e multiplicar o resultado
por k
”i+(j*k)
ou (i+j)*k
+
e -
unários*
, /
, %
+
e -
bináriosi + j * k |
equivalente a | i + (j*k) |
-i * -j |
equivalente a | (-i) * (-j) |
+ i + j/k |
equivalente a | (+i) + (j/k) |
+
, -
,
*
, /
, %
) associam à
esquerdai - j - k |
equivale a | (i - j) - k |
i * j / k |
equivale a | (i * j) / k |
- + j |
equivale a | -(+j) |
= 5; /* valor de i: 5 */
i = i; /* valor de j: 5 */
j = 10 * i + j; /* valor de k: 55 */ k
Se a variável e expressão não forem do mesmo tipo dá-se uma conversão implícita de tipos.
int i;
float f;
= 72.99; // valor de i: 72
i = 136; // valor de f: 136.0 f
Exemplo:
int i, j, k;
= 1;
i = 1 + (j = i);
k // j: 1, k: 2
Cuidado: usar atribuições no meio de expressões pode dificultar a compreensão de programas
Podemos atribuir um mesmo valor a várias variáveis:
= j = k = 0; i
Como a atribuição associa à direita, isto é equivalente a:
= (j = (k = 0)); i
= 12; // OK: i é um lvalue
i 12 = i; // erro: 12 não é um lvalue
1+j = 12; // erro: 1+j não é um lvalue
É frequente atribuir a uma variável um novo valor que depende do seu valor atual.
Exemplo:
= i + 2; i
Nestes casos podemos usar uma atribuição composta:
+= 2; i
+=
\(e\)adicionar \(e\) de \(v\), guardando o resultado em \(v\)
-=
\(e\)subtrair \(e\) a \(v\), guardando o resultado em \(v\)
*=
\(e\)multiplicar \(e\) por \(v\), guardando o resultado em \(v\)
/=
\(e\)dividir \(v\) por \(e\), guardando o resultado em \(v\)
%=
\(e\)calcular o resto de divisão de \(v\) por \(e\), guardando o resultado em \(v\)
É frequente somar ou subtrair uma variável inteira de uma unidade.
= i + 1;
i = j - 1; j
Também aqui podemos usar uma atribuição composta:
+= 1;
i -= 1; j
Em alternativa, podemos usar operadores de incremento ou decremento.
++i
ou --i
) ou pósfixa (i++
ou
i--
)++i; // equivalente a i = i + 1
--j; // equivalente a j = j - 1
++i
modifica a variável i
(incrementa de
uma unidade) e dá o valor resultante.
= 1;
i ("%d\n", ++i); // imprime 2
printf("%d\n", i); // imprime 2 printf
i++
dá o valor atual de i
e depois modifica
a variável i
(incrementa de 1 unidade).
= 1;
i ("%d\n", i++); // imprime 1
printf("%d\n", i); // imprime 2 printf
++i
incrementa imediatamente, enquanto i++
incrementa mais tardei
será
incrementada antes da próxima instruçãoO operador de decremento comporta-se de forma análoga ao de incremento:
= 1;
i ("%d\n", --i); // imprime 0
printf("%d\n", i); // imprime 0
printf= 1;
i ("%d\n", i--); // imprime 1
printf("%d\n", i); // imprime 0 printf
Pode ser difícil seguir o efeito de múltiplos ++
ou
--
em várias variáveis numa mesma expressão:
= 1;
i = 2;
j = ++i + j++;
k // i: 2, j: 3, k: 4
= 1;
i = 2;
j = i++ + j++;
k // i: 2, j: 3, k: 3
Recomendação: evite expressões com mútiplos incrementos.
= 5;
a = (b = a + 2) - (a = 1); c
Qual é o valor final de c
?
b = a + 2
o resultado é
6
a = 1
o resultado é
2
Logo: o comportamento deste programa depende da ordem de avaliação das subexpressões.
(a + b) * (c - d)
não sabemos se será
calculado primeiro (a + b)
ou (c - d)
(b = a + 2) - (a = 1)
= 2;
i = i * i++; j
O resultado final de j
depende da ordem de avaliação da
multiplicação (4
ou 6
).
c=(b=a+2)-(a=1);
ou
j=i*i++;
têm comportamento indefinido:
-Wall
: gcc -Wall -o programa programa.c
Re-escrever o primeiro exemplo para evitar comportamento indefinido:
= 5;
a = a + 2;
b = 1;
a = b - a; c
Desta forma o resultado final de c
é sempre
6
.