Você está na página 1de 52

Elementos de Linguagem C

Parte I

Mário Simões Elementos de linguagem C – Parte I 1


2010.04
Linguagem C
• Eficiência da execução
– O código gerado corre de forma eficiente, mesmo em processadores modestos,
usados em sistemas embebidos
• Acesso ao hardware
– Manipulação directa da memória de dispositivos de I/O
• Portabilidade
– Disponibilidades de compiladores para numerosas arquitecturas
– APIs estabilizadas e suportadas em diversas plataformas
– Dependência da plataforma de execução
• O código compilado é especificamente gerado para uma determinada arquitectura
• Portar uma aplicação para outra plataforma implica, pelo menos, a recompilação do
código
• Automatismo reduzido na gestão da memória
– O alojamento dinâmico é controlado explicitamente
– Não existe garbage collection nem outros de gestão automática da memória alojada
dinamicamente

Mário Simões Elementos de linguagem C – Parte I 2


2010.04
Introdução
#include <stdio.h>

int main(void){
printf("Hello world!\n");
return 0;
}

Mário Simões Elementos de linguagem C – Parte I 3


2010.04
Variáveis – Tipos básicos
• Inteiros
– char 8 bits com ou sem sinal –
armazenamento de caracteres
– int com sinal, dimensão natural da
máquina – típico 16 ou 32 bits
• Vírgula flutuante
– float precisão simples (típico 32 bits)
– double precisão dupla (típico 64 bits)
Mário Simões Elementos de linguagem C – Parte I 4
2010.04
Variáveis – Qualificadores
• Aplicáveis a inteiros
– signed [char | int] valor com sinal
– unsigned [char | int] valor sem sinal
– short [int] inteiro curto – típico 16 bits
– long [int] inteiro longo – típico 32 ou
mais bits
• Aplicáveis a vírgula flutuante
– long double precisão extra (p. ex. 80 ou 96 bits)
• Outros, com significados diversos...
Mário Simões Elementos de linguagem C – Parte I 5
2010.04
Variáveis - Declaração
• Formato
tipo nome;
• Exemplos
char c; /* Uma variável do tipo char */
int x, y; /* Duas variáveis do tipo int */
unsigned u; /* Uma variável do tipo int sem
sinal */
short s; /* Uma variável do tipo short int */
long l; /* Uma variável do tipo long int */
double d; /* Uma variável do tipo double */

Mário Simões Elementos de linguagem C – Parte I 6


2010.04
Variáveis – Localização
• Exterior às funções – variáveis não automáticas
– Alojamento numa posição fixa da memória do sistema
• Interior às funções – variáveis automáticas
– No interior da função ou de qualquer scope
– Alojamento gerido dinamicamente, suportado pelo
stack do programa
– Resolução de nomes iguais – considera a variável do
scope corrente (não se recomenda o uso e abuso)

Mário Simões Elementos de linguagem C – Parte I 7


2010.04
Variáveis – Valor inicial
• Atribuído explicitamente
– Formato
tipo nome = valor;
– Variáveis não automáticas
• Valor carregado no acto de lançamento do programa
– Variáveis automáticas
• Valor carregado sempre que se inicia a execução do respectivo scope
• Atribuído implicitamente
– Variáveis não automáticas – valor 0
• carregado no acto de lançamento do programa
– Variáveis automáticas – indeterminado
• Não é carregado nenhum valor – a memória mantém o valor,
aleatório, que tem

Mário Simões Elementos de linguagem C – Parte I 8


2010.04
Variáveis – Exemplos
int a; /* variável com o valor por omissão: 0 */
int b = 10; /* variável com o valor atribuído: 10 */
int main(void){
char c = 'a'; /* variável com valor inicial */
while(...){
char d; /* variável sem valor inicial conhecido */
...
if(...){
float f = 1.23e-4; /* variável iniciada cada
vez que entrar no if */
}
...
}
...
}

Mário Simões Elementos de linguagem C – Parte I 9


2010.04
Constantes – Inteiros
• int – sequência de dígitos
1234 10 -20
• long – sufixo L ou l ou dígitos que excedem int
1234L 12345678l
• unsigned – sufixo U ou u
1234U 5678u
• unsigned long – combinação de sufixos
1234UL 5678ul

Mário Simões Elementos de linguagem C – Parte I 10


2010.04
Constantes – Inteiros
• Representação em octal – prefixo 0
0123 (equivale a 83 em decimal)
0456 (equivale a 302 em decimal)
• Representação em hexadecimal – prefixo 0x
0xffff (equivale a 65535 em decimal)
0x0a (equivale a 10 em decimal)
• Estas formas também admitem os sufixos
U, u, L e l
Mário Simões Elementos de linguagem C – Parte I 11
2010.04
Constantes – Caracteres
• Valores inteiros gerados pelo compilador segundo
a tabela ASCII
'a' 'b' 'A' 'B' '0' '1' '2' '3' ...
• Sequências com significado especial
'\b' '\t' '\n' '\r' '\\' '\'' '\”'
• Valores expressos por dígitos
– em octal '\ooo'
'\0' '\033' '\007'
– em hexadecimal '\xhh'
'\x00' '\x1b' '\x07'

Mário Simões Elementos de linguagem C – Parte I 12


2010.04
Constantes – Strings
• Sequências de caracteres delimitadas por aspas
"uma frase com diversas palavras"
• Armazenamento em memória – sequência de bytes, com os
códigos dos caracteres, terminada por um byte com o valor
0 ('\0'), inserido automaticamente
• Admite a inserção dos caracteres especiais na sequência
"primeira linha \n segunda linha"
• Strings consecutivas formam uma única sequência em
memória
"uma frase com" " diversas palavras"
é equivalente a
"uma frase com diversas palavras"

Mário Simões Elementos de linguagem C – Parte I 13


2010.04
Constantes – Enumerados
• Definição de um conjunto de constantes com nome
enum boolean { NO, YES };

• Admite atribuição dos valores aos nomes


enum escapes {
BELL = '\a', BACKSPACE = '\b', TAB = '\t',
NEWLINE = '\n', VTAB = '\v', RETURN = '\r' };

• Admite atribuição de um valor, gerando os restantes em sequência


enum months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL,
AUG, SEP, OCT, NOV, DEC };

• Os nomes têm que ser distintos, mesmo em enumerados diferentes


• Os valores podem coincidir, em enumerados diferentes ou no mesmo

Mário Simões Elementos de linguagem C – Parte I 14


2010.04
Operadores
• Aritméticos
+ - * / %
• Incremento e decremento
++ --
• Relacionais e lógicos
> >= < <= == != && || !
• Bit a bit
& | ^ << >> ~
• Conversões de tipo
– Implícitas
• trunca ou expande adequadamente o número de bits
– Explícitas (cast)
(tipo) expressão
• Afectação
= += -= *= /= %= <<= >>= &= ^= |=
• Expressão condicional (operador trenário)
expr ? expr1 : expr2

Mário Simões Elementos de linguagem C – Parte I 15


2010.04
Precedência e Associatividade
Operators Associativity Comments
( ) [ ] -> . left to right
! ~ ++ -- + - * & (type) sizeof right to left Unary operators
*/% left to right Binary operators
+- left to right Binary operators
<< >> left to right
< <= > >= left to right
== != left to right
& left to right Bitwise and
^ left to right
| left to right
&& left to right
|| left to right
?: right to left
= += -= *= /= %= &= ^= |= <<= >>= right to left
, left to right

Mário Simões Elementos de linguagem C – Parte I 16


2010.04
Controlo
• Um Statemtent é
– Uma expressão seguida de ';'
expression;
– Ou uma sequência de statements delimitada por chavetas
{statement statement ... statement}

• If-else
if (expression)
statement1
else
statement2

Mário Simões Elementos de linguagem C – Parte I 17


2010.04
Controlo
• Else-if
if (expression)
statement
else if (expression)
statement
else if (expression)
statement
else if (expression)
statement
else
statement
Mário Simões Elementos de linguagem C – Parte I 18
2010.04
Controlo
• Switch
switch (expression) {
case const-expr: statements
case const-expr: statements
default: statements
}

Mário Simões Elementos de linguagem C – Parte I 19


2010.04
Controlo
• While
while (expression)
statement
• Do-while
do
statement
while (expression);

Mário Simões Elementos de linguagem C – Parte I 20


2010.04
Controlo
• For
for (expr1; expr2; expr3)
statement
Equivalente a:
expr1;
while (expr2) {
statement
expr3;
}
Mário Simões Elementos de linguagem C – Parte I 21
2010.04
Controlo
• Break
– Provoca a saída imediata do ciclo interior ou de
um switch
• Continue
– Provoca a o fim da iteração corrente e regresso
à condição de teste do ciclo interior
• No caso do for, executa a expressão de incremento
– Não se aplica a switch – actua sobre o ciclo
interior que contém o switch
Mário Simões Elementos de linguagem C – Parte I 22
2010.04
Controlo
• Goto
– É útil quando não se pode aplicar break – por
exemplo, para quebrar um ciclo que não é o
interior
– Funciona associado a uma label, com o formato
nome:

Mário Simões Elementos de linguagem C – Parte I 23


2010.04
Funções
• As funções são as entidades que contêm
todo o código executável do programa
• O programa começa na função main,
chamada a partir do módulo de arranque
• A função main chama outras funções para
cumprir os objectivos do programa
• As funções recebem parâmetros e produzem
valores de retorno
Mário Simões Elementos de linguagem C – Parte I 24
2010.04
Funções
• Formato de escrita das funções
tipo_retorno nome( parâmetros ) {
statements
}
• Formato da invocação
... = nome( argumentos );
• Se uma função não tiver parâmetros, a invocação tem
igualmente os parêntesis – operador de chamada
... = nome();
• Se o valor de retorno de uma função não existir ou não for
útil, omite-se simplesmente a utilização
nome( argumentos );

Mário Simões Elementos de linguagem C – Parte I 25


2010.04
Funções – Parâmetros
• Os parâmetros são sempre passados por valor
– No caso de se passar uma variável, a função não pode
modificá-la
• Se isso for necessário é a solução é passar o endereço – ver
adiante: ponteiros
• Se a função não tiver parâmetros, isso deve ser
indicado pela palavra void
tipo_retorno nome( void ){ ...
– Se não indicar nada, permite que a função aceite
quaisquer parâmetros (não se recomenda, por ser
propenso a erros)

Mário Simões Elementos de linguagem C – Parte I 26


2010.04
Funções – Retorno
• O valor de retorno pode ser de um tipo básico ou de outros, definidos pelo
programador
– Existe um tipo por omissão, que é int (contudo, recomenda-se a indicação explícita)
• A emissão do valor de retorno faz-se com o statement return
int add3int( int a, int b, int c ) {
return a + b + c;
}
float add3float( float a, float b, float c ) {
return a + b + c;
}
• Se uma função não produzir valor de retorno, isso deve ser indicado pela
palavra void e não é necessário o statement return
void nome(parâmetros){
...
}

Mário Simões Elementos de linguagem C – Parte I 27


2010.04
Comentários
• Sequências de caracteres ignoradas pelo
compilador
– Início: /*
– Fim: */
– Podem ocupar várias linhas de texto

Mário Simões Elementos de linguagem C – Parte I 28


2010.04
struct
• A struct é uma estrutura de dados que suporta armazenamento não
homogéneo (elementos cujo tipo pode ser diferente)
• Os elementos que formam uma struct são designados por campos ou
membros e têm nome
• O tipo de cada campo pode ser qualquer, válido na linguagem,
incluindo outras struct ou arrays
• É também admitida a definição de "bit fields" – campos inteiros com
um número arbitrário de bits
• O acesso aos campos de uma struct faz-se combinando o nome da
variável que a contém com o nome do campo, ligados por um ponto
• As struct são alojadas assegurando o alinhamento de cada um dos seus
campos
– a dimensão indicada pelo operador sizeof reflecte o alinhamento

Mário Simões Elementos de linguagem C – Parte I 29


2010.04
struct – definição e acesso
struct st1{
int a; /* campo inteiro */
float b; /* campo float */
char c[10]; /* campo array de char */
int d:4; /* bit-fild de 4 bits */
}x; /* a struct é alojada numa variável
com o nome x */

struct st1 y; /* outra struct idêntica com o nome y */

... = x.a; /* acesso ao campo a de x */


y.c[n] = ...; /* acesso ao campo c de y */
x = y; /* cópia integral de struct */

Mário Simões Elementos de linguagem C – Parte I 30


2010.04
struct – declaração de tipo
typedef struct st1{ /* Tag st1 opcional */
int a; /* campo inteiro */
float b; /* campo float */
char c[10]; /* campo array de char */
int d:4; /* bit-fild de 4 bits */
}S; /* S é, neste caso, um nome de tipo */

S x; /* uma struct S, alojada numa variável com o nome x */


S y; /* uma struct S, alojada numa variável com o nome y */

... = x.a; /* acesso ao campo a de x */


y.c[n] = ...; /* acesso ao campo c de y */
x = y; /* cópia integral de struct */

Mário Simões Elementos de linguagem C – Parte I 31


2010.04
Iniciação de variáveis struct
...

typedef struct st1{ /* Tag st1 opcional */


int a;
float b;
char c[10];
int d:4;
}S;

S x = {10, 1.234, “ola”, 2}; /* uma struct S,


alojada numa variável com o nome x, com valores
iniciais, todos explícitos*/
S y = {100, 12.34}; /* uma struct S, alojada numa
variável com o nome y com valores iniciais, alguns
explícitos e outros implícitos */

Mário Simões Elementos de linguagem C – Parte I 32


2010.04
Ponteiros
• Um ponteiro é uma variável que representa o endereço de outra variável
– Permite aceder a variáveis diversas, segundo as mudanças de valor do ponteiro
• A declaração de um ponteiro é indicada pelo operador unário *
int * p1; /* ponteiro para variáveis do tipo int */
float * p2; /* ponteiro para variáveis do tipo float */

• O acesso à variável apontada faz-se também com o operador *


• O endereço de uma variável pode obter-se com o operador unário & cujo tipo
é de ponteiro para variáveis do tipo mencionado
int a, b;
int * p;
...
p = &a; /* obtém o endereço de a */
*p = 0; /* equivalente: a = 0; */
b = *p; /* equivalente: b = a; */

Mário Simões Elementos de linguagem C – Parte I 33


2010.04
Arrays
• O array é uma estrutura de dados que suporta o armazenamento
homogéneo (colecção de elementos do mesmo tipo)
• O tipo dos elementos armazenados pode ser qualquer dos básicos ou
outro, definido pelo programador
• O acesso aos elementos de um array é seleccionado por um índice
• Os valores válidos para o índice são de 0 a N-1, em que N é o número
de elementos do array
• Declaração
tipo nome_array[dimensão];
• Utilização
... = nome_array[índice];
nome_array[índice] = ...

Mário Simões Elementos de linguagem C – Parte I 34


2010.04
ponteiros e Arrays
• O nome de um array (sem os parêntesis rectos nem o índice) é um
ponteiro para o primeiro elemento do array
Considerando a declaração de um array: tipo a[dimensão];
*a = ...; é exactamente o mesmo que a[0] = ...;
• O acesso a elementos através de um ponteiro pode ser feito
indiferentemente com o operador * ou com o operador []
*p = ...; é exactamente o mesmo que p[0] = ...;
• Aritmética de ponteiros:
– Se o ponteiro p contém o endereço do elemento i de um array, a
expressão p+n representa o endereço do elemento i+n
*(p+n) = ...; é exactamente o mesmo que p[n] = ...;
– O cálculo do endereço apontado é feito pelo compilador, de acordo com a
dimensão do elemento apontado
– A aritmética de ponteiros só é válida para aceder a elementos de um
mesmo array e não a quaisquer variáveis declaradas em separado

Mário Simões Elementos de linguagem C – Parte I 35


2010.04
ponteiros e Arrays
• Na declaração de parâmetros das funções pode ser
indiferentemente usada a notação de ponteiro ou
de array
int strlen(char * s){...
é exactamente o mesmo que
int strlen(char s[]){...
– em ambos os casos, o acesso aos dados representados
pelo parâmetro pode ser feito com a notação de
ponteiro ou de array
... = *s; ou ... = s[...];

Mário Simões Elementos de linguagem C – Parte I 36


2010.04
ponteiros e Arrays
• A declaração de variáveis ponteiro ou array tem
significados diferentes
– A declaração de um array reserva espaço em memória para os
elementos que ele irá conter
– A declaração de um ponteiro só reserva espaço para o próprio
ponteiro e não para quaisquer dados apontados
– Um ponteiro só tem significado válido depois de afectado com o
endereço de uma variável adequadamente alojada
– A afectação de um ponteiro pode ser realizada na declaração, na
forma de valor inicial
int a[...];
int b;
int *p1 = a;
int *p2 = &b;

Mário Simões Elementos de linguagem C – Parte I 37


2010.04
Arrays – Iniciação
• Na declaração de um array pode ser feita a sua iniciação
– Se a dimensão for omitida, o compilador calcula
– Se for indicada, preenche restantes com 0
– Se a dimensão indicada for insuficiente, é erro
int a[] = {1, 2, 3}; /* array de 3 int: valores 1, 2 e 3 */
int b[10] = {4, 5, 6}; /* array de 10 int:
os primeiros valem 4, 5, e 6;
os restantes valem 0 */
char c[] = "ola"; /* array de 4 char: 'o', 'l', 'a' e '\0' */
char d[3] = "ola"; /* erro!, não cabe o terminador '\0' */
• A declaração de ponteiros iniciados como se fossem arrays tem significado diferente
int *p = {1, 2, 3}; /* ponteiro para int, iniciado com o endereço
de uma área de constantes com os valores
1, 2 e 3 */
char *p = "ola"; /* ponteiro para char, iniciado com o endereço de
uma área de constantes com os valores
'o', 'l', 'a' e '\0' */

Mário Simões Elementos de linguagem C – Parte I 38


2010.04
Arrays multidimensionais
• Podem definir-se arrays de arrays
int a[10][20]; /* a é um array de 10 elementos, sendo cada
um deles um array de 20 inteiros */
char b[10][5][20]; /* b é um array de 10 elementos, sendo
cada um deles um array de 5 elementos que são arrays de 20 char
*/
• Se forem definidos parâmetros de funções como arrays
multidimensionais, é necessários especificar as dimensões,
excepto a primeira
void func(char x[][5][20]); /* O parâmetro x é o
endereço de um array cujos elementos são arrays de 5 elementos,
sendo cada um deles um array de 20 char */

Mário Simões Elementos de linguagem C – Parte I 39


2010.04
Argumentos de linha de comando
• Está previsto o acesso argumentos introduzidos na linha de comando
pelo utilizador
– Cada argumento é uma palavra
– O parâmetro argc indica o número de palavras, incluindo o nome do
executável
– O parâmetro argv representa o endereço de um array de ponteiros para as
localizações, em memória, das palavras
• Exemplo: mostrar todos os argumentos
int main(int argc, char * argv[]){
int i;
for(i = 0; i != argc; ++i){
printf("%s ", argv[i]);
}
}

Mário Simões Elementos de linguagem C – Parte I 40


2010.04
Campos ponteiro para struct
• Em estruturas de dados como listas e árvores, declaram-se campos
ponteiros para a própria ou outra struct

typedef struct st{


struct st *p; /* ponteiro para a própria
struct – usa a tag st */
int a; /* outros campos... */
int b;
}X;

X x1, x2; /* duas variáveis deste tipo de


struct*/
...
x1.p = &x2; /* acesso ao campo ponteiro

Mário Simões Elementos de linguagem C – Parte I 41


2010.04
Arrays e iniciação de struct
• Podem definir-se arrays de struct
typedef struct stx{
int a;
int b;
} X;

X ax[100];
...
ax[i].a = ...;
• Podem preencher-se com valores iniciais
X x = {10, 20}; /* x.a = 10, x.b = 20
X ax[] = {{10, 20}, {11, 21}, {12, 22}}; /* array de três
estruturas iniciadas. As chavetas interiores são opcionais, para legibilidade

Mário Simões Elementos de linguagem C – Parte I 42


2010.04
Ponteiros para struct
typedef struct stx{
int a;
int b;
} X;

X ax[100];
X *p;
...
p = ax; /* ou, por ex.: p = &ax[i];
equivalente a: p = ax+i; */
...
(*p).a = ...; /* acesso ao campo a da struct apontada,
operadores * e . */

p->a = ...; /* forma de escrita equivalente, com o


operador -> */

Mário Simões Elementos de linguagem C – Parte I 43


2010.04
Struct em parâmetros de funções
• Um parâmetro struct implica a passagem por valor, isto é,
a cópia do conteúdo da struct
typedef struct{...} X;
tipo_ret nome_func(X x){...
– Se não se pretender a cópia, define-se o parâmetro de modo a
passar um ponteiro para a struct
tipo_ret nome_func(X *xp){...
– Ou define-se o tipo de dados com a struct encapsulada num array
de um só elemento (um parâmetro array é um ponteiro)
typedef struct{...}X[1];
tipo_ret nome_func(X x){...

Mário Simões Elementos de linguagem C – Parte I 44


2010.04
Struct em retorno de funções
• O tipo de retorno de uma função pode ser struct
– O espaço para suportar este retorno é gerido pela função
chamadora
– A função chamada declara, normalmente, uma instância da struct
para usar em return
typedef struct {...}X;
X func(parâmetros){...
X x;
x.campo = ...;
...
return x;
}

Mário Simões Elementos de linguagem C – Parte I 45


2010.04
Struct e Union
• A declaração de variáveis union é idêntica à
de struct
• A diferença está no alojamento dos campos:
todos têm o mesmo endereço
– A union é uma forma de aceder ao mesmo
espaço de memória com tipos diferentes
– A dimensão total da union é a dimensão do
maior dos seus campos
Mário Simões Elementos de linguagem C – Parte I 46
2010.04
Funções com lista de parâmetros
variável
• A linguagem C suporta funções com parâmetros variáveis, indicados
por '...'
– A mesma função, em utilizações diferentes, recebe um número de
parâmetros diferente ou com tipos diferentes
– A função recebe, tipicamente, um parâmetro fixo que lhe permite
identificar os variáveis
– Exemplo: printf(char *fmt, ...);
int i;
char car;
char str[] = "frase";
...
printf("%d\n", i);
printf("%c\n", car);
printf("%c %d %s\n", car, i, str);

Mário Simões Elementos de linguagem C – Parte I 47


2010.04
Funções com lista de parâmetros
variável
• As funções definidas pelo programador também podem ter
lista de parâmetros variável
• Neste caso o acesso aos parâmetros variáveis pode se feito
usando um ponteiro iniciado a partir do último parâmetro
fixo
int addIntList(int count, ...){
int *p = &count + 1;
int res = 0;
while(count--){
res += *(p++);
}
return res;
}

Mário Simões Elementos de linguagem C – Parte I 48


2010.04
Parâmetros variáveis – stdarg.h
• Uma forma sistemática e flexível de acesso a parâmetros variáveis está
disponível no ficheiro stdarg.h, com o tipo va_list e macros
associadas

int addIntList(int count, ...){


va_list ap;
int res = 0;
va_start(ap, count);
while(count--){
res += va_arg(ap, int);
}
va_end(ap);
return res;
}

Mário Simões Elementos de linguagem C – Parte I 49


2010.04
ponteiros para função
• A definição de ponteiros para funções implica a especificação dos parâmetros
e retorno da função apontada
• Exemplos:
– Declaração de um ponteiro para função sem parâmetros nem valor de retorno
void (*fp)(void);

– Declaração de um ponteiro para função com dois parâmetros e retorno do tipo int
int (*fp)(int, int);

– Definição de tipos e declaração de ponteiros com esses tipos


typedef void (*fpt1)(void);
typedef int (*fpt2)(int, int);

fpt1 fp1;
fpt2 fp2;

Mário Simões Elementos de linguagem C – Parte I 50


2010.04
ponteiros para função
• A utilização do ponteiro para chamar a função é infdicada pelos parêntesis curvos – operador de chamada – que
contêm os parâmetros, se existirem
• Exemplos
void (*fp)(void);

void f(void){...}
...
fp = f;
fp();

void(*fpa[10])(void) = {f1, f2, ...};

...
for(...; ...; ...){
fpa[i]();
}

Mário Simões Elementos de linguagem C – Parte I 51


2010.04
ponteiros descomprometidos
• void * p;
– p aponta um tipo indefinido
– p é compatível com qualquer outro ponteiro
void * p; int * q;
p = q;
q = p;
– a mudança do tipo de ponteiro, de ou para void *, não altera o
endereço apontado
• É frequente como parâmetro ou retorno de funções
– Exemplos:
void *malloc(size_t size);
void free(void *p);
Mário Simões Elementos de linguagem C – Parte I 52
2010.04

Você também pode gostar