Beruflich Dokumente
Kultur Dokumente
Programação
Programação Avançada com C 1. A linguagem de programação C.
2. Funções. A função main.
Avançada com C 3. As instruções do C.
4. Entradas e saídas.
por 5. Tipos de dados.
6. Variáveis.
Pedro Guerreiro 7. Operadores.
pg@di.fct.unl.pt 8. Vectores.
http://ctp.di.fct.unl.pt/~pg/ 9. Operadores ++ e ––
10. Operadores de afectação.
Departamento de Informática
11. Ficheiros.
Faculdade de Ciências e Tecnologia
12. Cadeias de caracteres.
Universidade Nova de Lisboa
13. Ciclo de leitura.
#include
#include <stdio.h>
<stdio.h> printf
main()
main() Uma função de biblioteca que serve para
escrever coisas.
{{
printf("Olá, "Olá, pessoal\n"
printf("Olá, pessoal\n");
pessoal\n");
}} Uma cadeia de caracteres.
'\n'
A representação do carácter newline.
Programação Avançada com C 5 Programação Avançada com C 6
if (place == 1)
printf("Ganhou 10 pontos.\n");
1.º 10 pontos else if (place == 2)
2.º 6 pontos printf("Ganhou 6 pontos.\n");
else if (place == 3)
3.º 4 pontos printf("Ganhou 4 pontos.\n");
else if (place == 4)
4.º 3 pontos printf("Ganhou 3 pontos.\n");
else if (place == 5)
5.º 2 pontos printf("Ganhou 2 pontos.\n");
else if (place == 6)
6.º 1 ponto printf("Ganhou 1 ponto.\n");
else
7.º em diante 0 pontos printf("Não ganhou pontos.\n");
return 0;
}
/***********************************************
* *
* *** * * * return
return 0;
0;
* * * * * *
* * *** **** *** * ** ** *
* * * * * * * * ** * * *
* * ***** * * * * * * * * Convencionalmente a função main devolve
* * * * * * * * * * * *
* *** *** **** *** * * * * 0 (zero), quando tudo corre bem!
* *
***********************************************/
int
int place;
place; printf("Ganhou
printf("Ganhou 10
10 pontos.\n");
pontos.\n");
place é uma variável inteira. A função printf escreve cadeias de
caracteres (e outras coisas também) no
ecrã do terminal.
O tipo int representa os números inteiros As cadeias de caracteres vêm entre aspas.
entre -32768 e 32767, nos computadores de \n é uma sequência de escape que
16 bits, e entre -2147483648 e 2147483647, representa o carácter newline.
nos computadores de 32 bits.
Para poder usar a função printf, é preciso
incluir o ficheiro <stdio.h>.
Programação Avançada com C 11 Programação Avançada com C 12
int
int points
points (int
(int place)
place) Não há potenciação!
{{
if
if (place
(place <=
<= 2)
2)
return
return 14
14 -- 44 ** place;
place; Operadores com a mesma priori-
else
else if
if (place
(place <=<= 6)
return
6) dade (* / %, + -) avaliam-se da
return 77 -- place;
place;
else
else esquerda para a direita.
return
return 0;
0;
}}
A divisão ( / ) de dois números
inteiros é a divisão inteira.
main() long x; Um
Um int:
int: 452
452
{ int i; OO long:
long: 452
452
long x; printf("Um int: ");
int i; scanf("%d", &i);
printf("Indique a base e o expoente: "); x = i; Um
scanf("%ld%d", &x, &i); printf("O long : %d\n", Um int:
int: 214523
214523
OO long:
long: 32767
32767
printf("%ld elevado a %d vale %ld\n", i);
x, i, lpow(x, i));
return 0;
} long x; Um
Um long:
long: 186
186
int i; OO int
printf("Um long: "); int :: 186
186
long lpow(long base, int n)
scanf("%ld", &x);
{ i = x;
return n ? base * lpow(base, n-1) : 1; Um
Um long:
long: 523214
523214
printf("O int : %d\n", OO int
} i); int :: -1074
-1074
||
|| disjunção (“ou”). void
void greetint(int
greetint(int h)
h)
{{
printf
printf
!! negação (“não”). (isbtwn(h,
(isbtwn(h, 4,11)
4,11) ?? "Bom
"Bom dia"
dia" ::
isbtwn(h,12,19)
isbtwn(h,12,19) ? "Boa tarde" ::
? "Boa tarde"
"Boa
"Boa noite");
noite");
Os operadores && e || avaliam-se da }}
esquerda para a direita e a avaliação pára
logo que o resultado da expressão fica int
int isleap(int
isleap(int y)y)
determinado: {{
return
return y%4
y%4 ==
== 00 &&
&& y%100
y%100 !=
!= 00 ||
||
Avalia-se x; se der 0 a expressão vale 0; y%400 == 0;
x && y se der diferente de 0 avalia-se y e o valor y%400 == 0;
}}
da expressão é 0 se o valor de y for 0 e 1
se não.
int
int daysof(int
daysof(int y) y)
Avalia-se x; se der diferente de 0 a {{
x || y expressão vale 1; se der 0 avalia-se y e o return
return 365
365 ++ isleap(y);
isleap(y);
valor da expressão é 0 se o valor de y for
}}
0 e 1 se não.
2.º subproblema:
2 2
(x1 - x2) + (y1 - y2) Escrever um programa para registar a
ordem de chegada dos pilotos.
Outros exemplos:
Declaração de um vector para registar a
chegada de 26 corredores:
#define
#define pi
pi 3.141592653
3.141592653
#define
#define e 2.718281828
e 2.718281828
int
int arrivals[26];
arrivals[26];
double
double sterling(int
sterling(int n) n)
Em C, os índices começam em 0. Por vezes, {{
convém ocupar o vector só a partir da return
return sqrt(2
sqrt(2 ** pi
pi ** n)
n) **
posição 1: pow(n / e, n);
pow(n / e, n);
int arrivals[27]; }}
/* índice 0 não utilizado */
Forma da declaração de um vector: As directivas (#define, #include) são
interpretadas pelo preprocessador.
tipo
tipo nome
nome [dimensão];
[dimensão];
#define MAX_ARRIVALS 26
int arrivals [MAX_ARRIVALS + 1]; Protótipo:
/* índice 0 não utilizado */
int n_arrivals; int
int get_arrivals (void); int get_arrivals
get_arrivals (void);
(void);
main ()
{ Chamada:
n_arrivals = get_arrivals ();
printf("Número de chegadas: %2d\n"
"Número de desistentes: %2d\n", n_arrivals
n_arrivals == get_arrivals
get_arrivals ();
();
n_arrivals, MAX_ARRIVALS -
n_arrivals);
return 0; Noutras circunstâncias, o valor da função
}
poderia ser descartado:
int get_arrivals (void)
{ ...;
...;
int i; get_arrivals
int number; get_arrivals ();
();
for (i = 1; i <= MAX_ARRIVALS; ++i) ...;
...;
{
printf("%2d.º lugar (0 p/ terminar): ",
i);
scanf("%d", &number); Se nunca quiséssemos o resultado (ou não
if (!number) houvesse mesmo um resultado para
break; devolver), o tipo da função seria void:
arrivals [i] = number;
}
return i - 1;
void
void get_arrivals
get_arrivals (void);
(void);
}
main()
main() Exemplos:
{{
int for
for (i
(i == 1;
1; ii <=
<= MAX_ARRIVALS;
MAX_ARRIVALS; ++i)
int i;
i; {{
++i)
for
for (i == 1;
(i 1; ii <=
<= 31;
31; ii == ii ++ 1)
1) printf("%2d.º
printf("%2d.º lugarlugar (0
(0 p/
p/ terminar):
terminar): ",
", i);
printf("%ld\n",
printf("%ld\n", lpow(2,
lpow(2, i));
i)); scanf("%d", &number);
i);
return scanf("%d", &number);
return 0;
0; if
if (!number)
(!number)
}} break;
break;
arrivals
arrivals [i][i] == number;
number;
long
long lpow(long
lpow(long base,
base, int
int n)n) }}
{{
long
long p;p;
int
int i;i;
pp == 1; if
if (number
(number >> MAX_NUMBER)
MAX_NUMBER)
1; {{
for
for (i(i == 1;
1; ii <=
<= n;
n; ii == ii ++ 1)
1) printf("ERRO:
pp == pp ** base; printf("ERRO: Número
Número inválido.\n");
inválido.\n");
base; ii == ii -- 1;
1;
return
return p; p; }}
}} else
else
arrivals
arrivals [i] [i] == number;
number;
Nota: Isto não fica assim!
Programação Avançada com C 55 Programação Avançada com C 56
x = 5;
printf("%d\n", x); 55
printf("%d\n", ++x); 66
Nota: printf("%d\n", x); 66
!number é o idioma C para number == 0. x = 5;
printf("%d\n", x); 55
printf("%d\n", x++); 55
printf("%d\n", x); 66
Programação Avançada com C 57 Programação Avançada com C 58
;
scanf("%d",
scanf("%d", &number);
&number);
if
if (!number)
(!number)
break;
break;
if
if (number
(number >> MAX_NUMBER)
MAX_NUMBER)
printf("ERRO:
printf("ERRO: Número
Número inválido.\n");
inválido.\n");
else
else
arrivals
arrivals [++i]
[++i] == number;
number;
}}
return
return i; i;
}}
void
void display_times(void)
display_times(void)
Muitas vezes descarta-se o valor:
{{
int
int i;
i; long
long lpow(long
lpow(long base,
base, intint n)
n)
for
for (i
(i == 1;
1; ii <=
<= MAX_NUMBER;
MAX_NUMBER; ++i)
++i) {{
if
if (times[i])
(times[i]) long
long p;
p;
{{
int
int i;
i;
printf("%2d
printf("%2d ", ", i);
i); for
for (p
(p == 1,
1, ii == 1;
1; ii <=
<= n;
n; ii == ii ++ 1)
1)
printtime(times[i]);
printtime(times[i]); pp == pp ** base;
base;
printf("\n");
printf("\n"); return
return p;p;
}}
}}
}}
Quando
Quandoum
umargumento
argumentoda dafunção scanfou
funçãoscanf ou
fscanf é uma cadeia, não se usa o &.
fscanf é uma cadeia, não se usa o &. Pode-se
Pode-seler
leruma
umalinha
linhado
doficheiro
ficheirodirecta-
directa-
mente
mentepara
paraas
asposições
posiçõesnos
nosvectores:
vectores:
Para
Paraler
leruma
umalinha
linhainteira
inteirado
doterminal
terminal(até
(atéao
ao
fim da linha inclusive), usa-se a função
fim da linha inclusive), usa-se a funçãogets.
gets. fscanf(f, "%d%s",
OOnewline
newlineéésubstituído
substituídopor
por'\0'.
'\0'. &numbers[i], names[i])
...
printf("Qual é o nome? ");
gets(name);
...
Programação Avançada com C 95 Programação Avançada com C 96
int
int indexof(int
indexof(int n) n)
int
int indexof(int
indexof(int n)
n) {{
{{ int
int int a;
a;
int i;
i; int
int ii == 1;
1;
for
for (numbers[0]
(numbers[0] == n,
n, ii == n_cars;
n_cars; int j = n_cars;
numbers[i] != n; int j = n_cars;
numbers[i] != n; while
while (i(i <=
<= j)j)
––i)
––i) if
;; if (n == numbers[a=(i+j)/2])
(n == numbers[a=(i+j)/2])
return
return a; a;
return
return i;
i; else
}} else ifif (n(n << numbers[a])
numbers[a])
jj == aa -- 1;
1;
else
else
ii == aa ++ 1;
1;
O número colocado na posição 0 funciona return
return 0;0;
}}
como sentinela.
temp = *x;
Exemplo: uma função para calcular as raízes *x = *y;
do polinómio ax2+ bx + c, devolvendo 0 se não *y = temp;
houver raízes e 1 se houver: }
typedef
typedef unsigned
unsigned long
long size_t;
size_t; int
int fscanfCar(FILE
fscanfCar(FILE *f,
*f, Car
Car *p)
*p)
{{
return
return fscanf(f,
fscanf(f, "%d%s",
"%d%s",
char
char *strncpy(char
*strncpy(char *,
*, char
char *,
*, size_t);
size_t); &(*p).number,
&(*p).number,
char
char *strncat(char
*strncat(char *,
*, char
char *,
*, size_t);
size_t);
int (*p).name);
int strncmp(char
strncmp(char *,
*, char
char *,
*, size_t);
size_t); (*p).name);
}}
size_t
size_t strlen(char
strlen(char *);
*);
int
int fprintfCar(FILE
fprintfCar(FILE *f,
*f, Car
Car *p)
*p)
(*p).x p –> x
{{
return
return fprintf(f,
fprintf(f, "%2d
"%2d %-16s",
%-16s", Exemplo:
(*p).number, int
(*p).number,
(*p).name); int fprintfCar(FILE
fprintfCar(FILE *f,
*f, Car
Car *p)
*p)
(*p).name); {{
}} return
return fprintf(f,
fprintf(f, "%2d
"%2d %–16s",
%–16s",
p–>number,
p–>number,
int p–>name);
p–>name);
int fscanfCar(FILE
fscanfCar(FILE *f,
*f, Car
Car *p)
*p) }}
{{
return
return fscanf(f,
fscanf(f, "%d%s", int
"%d%s", int fscanfCar(FILE
fscanfCar(FILE *f,
*f, Car
Car *p)
*p)
&(*p).number,
&(*p).number, {{
(*p).name); return
return fscanf(f,
fscanf(f, "%d%s",
"%d%s",
(*p).name); &p–>number,
}} &p–>number,
p–>name);
p–>name);
}}
typedef a)
Resolução: typedef struct
struct
{{ int
int number;
number;
Começa-se por carregar os dois ficheiros com char
char name
name [16];
[16];
}} Car;
Car;
os dados para vectores. Depois, durante a
introdução da chegada, para verificar se um int
int fscanfCar(FILE
fscanfCar(FILE *,*, Car
Car b)
carro, dado pelo seu número, participou *);
*);
int
int loadCars(FILE
loadCars(FILE *,
*, Car
Car *);
mesmo na corrida, faz-se uma busca dico- *);
tómica no vector dos carros, obtendo o nome c)
#define
#define MAX_CARS
MAX_CARS 26
26
do condutor. Usando esse nome, faz-se uma Car
Car cars
cars [MAX_CARS
[MAX_CARS ++ 1];
1];
int n_cars;
busca linear no vector dos pilotos e adi- int n_cars;
ciona-se o número de pontos. Trata-se de int d)
int carsindexof(int);
carsindexof(int);
uma busca linear muito simplificada pois há a
garantia de o elemento procurado existir (os
ficheiros de dados não têm erros), mas é a) Definição do tipo Car.
preciso ter cuidado para não registar por b) Declaração de duas funções que operam
engano duas vezes a chegada do mesmo sobre o tipo Car.
piloto. Finalmente, assim que termina a intro- c) Definição do vector cars, com MAX_CARS
dução manual da chegada, ordena-se o vec- + 1 elementos de tipo Car (a posição 0
tor da classificação por pontos e despeja-se não é ocupada).
para o ficheiro resultado. d) Declaração de uma função de busca
dicotómica no vector cars. (Este vector
estará ordenado pelo campo number.)
"%s%*c%c.%s%d"
cadeia, espaço, carácter, ponto, cadeia, número decimal.
O especificador %s “apanha” cadeias de Esquema de utilização:
caracteres não-brancos. Os caracteres brancos
FILE
FILE *f_drivers;
são o espaço (32), o tab (9), o newline (10), o ...
*f_drivers;
carriage return (13), o tab vertical (11), e o form ...
f_drivers
f_drivers == fopen("DRIVERS_BEFORE",
fopen("DRIVERS_BEFORE", "r");
"r");
feed (12). n_drivers
n_drivers == loadDrivers(f_drivers,drivers+1);
loadDrivers(f_drivers,drivers+1);
fclose(f_drivers);
O especificador %c “apanha” um carácter, ...
fclose(f_drivers);
...
mesmo que seja branco.
Um asterisco num especificador determina a
supressão da afectação.
Um carácter não branco na cadeia de formato
fora dos especificadores de conversão tem que
bater certo com o carácter lido.
Programação Avançada com C 147 Programação Avançada com C 148
Só com aritmética:
& conjunção bit a bit
| disjunção bit a bit #define BITS_PER_INT 16
#define BITS_PER_INT 16 0
A função calloc devolve um apontador para Uma função para criar uma cadeia nova, a
um espaço inicializado a zero onde cabem n partir dos n primeiros caracteres de uma
objectos de tamanho size, ou NULL, se não cadeia s, devolvendo um apontador para a
for possível. cadeia criada:
char
char *strnewn(char
*strnewn(char *s,
*s, size_t
size_t n)n)
{{
OOtipo void **ééum
tipovoid umtipo
tipogenérico,
genérico,usado
usadonas
nas return
funções para argumentos e resultados return strncpy(
strncpy(
funções para argumentos e resultados (char*)calloc(n+1,
(char*)calloc(n+1, 1),
1), s,
s, n);
n);
apontadores.
apontadores.Qualquer
Qualquertipo
tipoapontador
apontadorpode
pode }}
ser
ser convertido para void *,eeinversamente,
convertido para void *, inversamente,
sem
semperda
perdade
deinformação.
informação. Não há problemas com o terminador '\0', porque o espaço
é inicializado a zero.
void
void IncCounter(Counter
IncCounter(Counter *x)
*x) O ficheiro table.h é assim:
{{
++x
++x ->
-> count;
count; void
void ClearTable(void);
ClearTable(void);
}} void
void EnterWord(char *);
EnterWord(char *);
int
int NumberOfItems(void);
NumberOfItems(void);
Estas funções vêm definidas nos ficheiro counter.c, com int
header counter.h. int NumberOfEntries(void);
NumberOfEntries(void);
static
static int
int n_entries;
n_entries; void
void EnterWord(char
EnterWord(char *s) *s)
{{
int
int i;
i;
int
int NumberOfEntries(void)
NumberOfEntries(void) for
for (i == 0,
(i 0, items[n_items]
items[n_items] ==
{{
NewCounter(s);
NewCounter(s);
return
return n_entries;
n_entries; strcmp(items[i]
strcmp(items[i] -> -> word,
word, s);
s);
}}
++i)
++i)
;;
Limpar a tabela é anular os dois contadores IncCounter(items[i]);
gerais: IncCounter(items[i]);
n_items
n_items +=
+= ii ==
== n_items;
n_items;
void ++n_entries;
++n_entries;
void ClearTable(void)
ClearTable(void) }}
{{
n_items
n_items == 0;
0;
n_entries
n_entries == 0;
0;
}} Ver as variantes a seguir.
Os contadores criados de novo que não são Normalmente, quando se percorre um vector
utilizados ficam desaproveitados. É melhor linearmente é melhor usar apontadores:
libertar a espaço que eles ocupam. Para isso,
existe a função free:
void
void EnterWord(char
EnterWord(char *s) *s)
{{
void
void free(void
free(void *p);
*p); Item
Item *p;
*p;
for
for (p
(p == items,
items, items[n_items]
items[n_items] ==
A função free desaloca o espaço apontado NewCounter(s);
NewCounter(s);
pelo seu argumento, espaço esse que deve ser strcmp((*p)
strcmp((*p) -> word,
-> word, s);
s);
sido alocado anteriormente pelas funções ++p)
++p)
malloc ou calloc. ;;
IncCounter(*p);
IncCounter(*p);
Para desalocar um contador, primeiro if
if (p
(p ==
== items
items ++ n_items)
n_items)
desaloca-se a cadeia, depois o contador: ++n_items;
++n_items;
else
else
FreeCounter(items[n_items]);
FreeCounter(items[n_items]);
void
void FreeCounter(Counter
FreeCounter(Counter *x)
*x) ++n_entries;
{{ ++n_entries;
}}
free(x
free(x ->
-> word);
word);
free(x);
free(x);
}}
Nota: (*p) -> word é o mesmo que
Exemplo de utilização a seguir. (**p).word.
3 8 4
3 12
2 9 18
List
List liststhd(List
liststhd(List s,s, Item
Item x)
x)
{{ Depois:
ss ->
-> value
value == x;
x;
return
return s;s; s 1 2
}}
t
Só para listas não vazias! 3 4 5
Programação Avançada com C 223 Programação Avançada com C 224
Item
Item listhead(List
listhead(List s) s) int
int listlen(List
listlen(List s) s)
{{ {{
return
return ss ->
-> value;
value; int
int n;
n;
}} for
for (n
(n == 0;
0; ss !=
!= NULL;
NULL; ++n)
++n)
ss == ss -> next;
-> next;
Só para listas não vazias! return
return n;n;
}}
3 8 int
int itemlt(Item,
itemlt(Item, Item);
Item); /*
/* <=
<= */
*/
int
int itemeq(Item, Item); /* == */
itemeq(Item, Item); /* == */
1 7 10 Por exemplo, com os itens usados no
problema do processamento de texto, seria:
int
int itemlt(Item
itemlt(Item x,x, Item
Item y)
14 {{
y)
return
return
strcmp(x
strcmp(x ->
-> word,
word, yy ->
-> word)
word) <=
<=
Ao inserir um item numa árvore ordenada, é 0;
0;
preciso garantir que a árvore continua orde- }}
nada. Por exemplo, o item 5 seria pendurado int
int itemeq(Item
itemeq(Item x,x, Item
Item y)
y)
à direita do 3; o item 9 à esquerda do 10; o {{
return
item 12 à esquerda do 14. return
strcmp(x
strcmp(x ->
-> word,
word, yy ->
-> word)
word) ==
==
0;
0;
}}
Programação Avançada com C 235 Programação Avançada com C 236
continue;
segmento, para calcular o ponto médio,
mover o segmento, esticar o segmento, etc.