Você está na página 1de 20

Faculdade de Engenharia da Universidade do Porto

LICENCIATURA EM ENGENHARIA INFORMTICA E COMPUTAO INTRODUO PROGRAMAO DE COMPUTADORES II - 1999/2000 EXERCCIOS Joo Pascoal Faria (jpf@fe.up.pt)

1. Introduo ao ambiente de programao


1.1. Siga o seguinte guio:
Arranque o Microsoft Visual C++ 5.0 a partir de Start Programs Microsoft Visual C++ 5.0 Microsoft Visual C++ 5.0. Crie um novo projecto e espao de trabalho ("workspace"), com a opo File New ... Projects, fornecendo os seguintes dados: Win32 Console Application Location = c:\temp (ou outro directrio com permisso de escrita) Project name = ip2 (ou outro nome sua escolha) Create new workspace Crie um ficheiro com a opo File New ... File, fornecendo os seguintes dados: C++ Source File File name = c:\temp\ip2\ip2.c (ou outro nome) Add to project Na janela de edio do ficheiro acabado de abrir, introduza o seguinte programa em C: #include <stdio.h> main() { printf("Ola!\n"); return 0; } Crie o executvel com a opo Build Build ip2.exe Corra o executvel com a opo Build Execute ip2.exe Corra o executvel fora do Visual C++, a partir do Windows Explorer e a partir da MS-DOS Prompt (o executvel estar em c:\temp\ip2\debug\ip2.exe) Experimente introduzir e executar outros programas apresentados nas aulas tericas. Explore sua vontade o ambiente de trabalho do Visual C++!

1.2. No sistema operativo Linux, crie um ficheiro de texto ola.c com o mesmo contedo do exerccio
anterior, usando um editor de texto sua escolha ( emacs, vi, pico, etc.). Compile o programa com o comando:

gcc ola.c -o ola Execute o ficheiro executvel ola criado por este comando.

2. Introduo programao em C
2.1. [Deitel 2.7] Identifique e corrija os erros em cada uma das instrues seguintes (Nota: pode existir
mais do que um erro por instruo): a) b) c) d) e) f) g) h) i) j) scanf("%d", value); printf("O produto de %d e %d %d\n", x, y); firstNumber + secondNumber = sumOfNumbers if (number => largest) largest == number; */ Programa para determinar o maior de trs inteiros /* Scanf("%d", anInteger); printf("O resto da diviso de %d por %d \n", x, y, x % y); if (x = y); printf(%d igual a %d\n", x, y); printf("A soma %d\n," x + y); Printf("O valor introduzido foi: %d\n, &value);

2.2. [Deitel 2.12] O que aparece escrito no ecr, se que aparece alguma coisa, em resultado da
execuo de cada uma das seguintes instrues em C? Suponha que x = 2 e y = 3. a) b) c) d) e) f) g) h) i) printf("%d", x); printf("%d", x + x); printf("x="); printf("x=%d", x); printf("%d = %d", x + y, y + x); z = x + y; scanf("%d%d", &x, &y); /* printf("x + y = %d", x + y); */ printf("\n");

2.3. [Deitel 2.15] Indique a ordem de avaliao dos operadores em cada uma das seguintes instrues
em C, e mostre o valor de x aps a execuo de cada uma das instrues. a) b) c) x = 7 + 3 * 6 / 2 - 1; x = 2 % 2 + 2 * 2 - 2 / 2; x = (3 * 9 * (3 + (9 * 3 / (3))));

2.4. [Deitel 2.19] Escreva um programa em C que leia 3 inteiros diferentes introduzidos pelo teclado, e
apresente no ecr a soma, a mdia, o produto, o menor e o maior desses nmeros. Use apenas a forma

de seleco simples (sem else) da instruo if. O dilogo deve aparecer no ecr com o seguinte aspecto: Introduza trs inteiros diferentes: 13 27 14 A soma 54 A mdia 18 O produto 4914 O menor 13 O maior 27

3. Introduo programao estruturada


3.1. [Deitel 3.11] Identifique e corrija os erros em cada uma das alneas seguintes (Nota: pode existir
mais do que um erro por alnea): a) if (age >= 65); printf("A idade maior ou igual que 65\n"); else printf("A idade menor que 65\n"); int x = 1, total; while (x <= 10) { total += x; ++x; } c) While (x <= 100) total += x; ++x; while (y > 0) { printf"%d\n", y); ++y; }

b)

d)

3.2. [Deitel 3.13] O que escreve o programa seguinte?


#include <stdio.h> main() {

int x = 1, total = 0, y; while (x <= 10) { y = x * x; printf("%d\n", y); total += y; ++x; } printf("O total %d\n", total); return 0;

3.3. [Deitel 3.31] Determine a sada produzida em cada uma das alneas seguintes, no caso em que x
= 9 e y = 11, e no caso em que x = 11 e y = 9. Note que o compilador de C ignora a "indentao". Note tambm que o compilador de C associa um else ao if mais prximo, a no ser que se indique outra coisa atravs de chavetas {}. (Sugesto: Comece por aplicar as convenes habituais de "indentao".) a) if (x < 10) if (y < 10) printf("*****\n"); else printf("#####\n"); printf("$$$$$\n"); if (x < 10) { if (y < 10) printf("*****\n"); } else { printf("#####\n"); printf("$$$$$\n"); }

b)

Para cada um dos exerccios seguintes (3.4 a 3.9), deve proceder da seguinte forma:
1. Leia o enunciado do problema. 2. Formule o algoritmo usando pseudo-cdigo e refinamento sucessivo "top-down". 3. Escreva um programa em C. 4. Teste, depure e execute o programa em C.

3.4. Escreva um programa em C que leia uma sequncia de nmeros inteiros, e determine e imprima a
soma, a mdia, o menor e o maior dos nmeros, a) supondo que o fim da sequncia indicado pelo valor 0 (que j no faz parte da sequncia); b) supondo que o comprimento da sequncia indicado previamente. No caso da alnea (a), o programa deve tambm imprimir o comprimento da sequncia.

3.5. [Deitel 3.34] Escreva um programa que leia o comprimento do lado de um quadrado (entre 1 e 20)
e escreva no ecr um quadrado "oco" com asteriscos. Por exemplo, se o comprimento dado for 5, a sada do programa deve ser: ***** * * * * * * *****

3.6. [Deitel 3.35] Uma capicua um nmero ou um texto que se l da mesma maneira de trs para a
frente e da frente para trs. Por exemplo, os seguintes nmeros so capicuas: 12321, 555, 45554 e 11611. a) Escreva um programa que leia um inteiro de 3 dgitos e determine se ou no uma capicua. (Sugesto: Use os operadores de diviso e mdulo para separar o inteiro nos seus dgitos.) b) Generalize o programa da alnea (a) por forma a tratar inteiros com qualquer nmero de dgitos.

3.7. Escreva um programa que leia duas horas do dia no formato hhmm, em que hh indica as horas (de
0 a 23) e mm os minutos (de 0 a 59), e calcule e imprima a respectiva soma no formato d hhmm, em que d o nmero de dias (0 ou 1). Exemplo: Introduza a primeira hora no formato hhmm: 1845 Introduza a segunda hora no formato hhmm : 0620 A soma : 1 0105 Sugestes: Ler cada hora do dia para um inteiro; o quociente e o resto da diviso inteira por 100 do as horas e os minutos, respectivamente. Para escrever um inteiro n (representando horas ou minutos) em 2 casas preenchidas com zeros esquerda, usar a instruo: printf("%.2d",n);

3.8. [Deitel 3.42] Escreva um programa que leia o raio de um crculo (do tipo float) e calcule e
imprima o dimetro, o permetro e a rea do crculo, com 2 casas decimais. Use o valor 3.14159 para .

3.9. [Deitel 3.44] Escreva um programa que leia trs valores positivos do tipo float, e determine se
esses valores poderiam representar as medidas dos lados de um tringulo. (Sugesto: No possvel construir um tringulo com um lado maior do que a soma dos outros dois.)

4. Controlo de programa
4.1. [Deitel 4.5 a)-g)] Encontre e corrija os erros em cada uma das alneas seguintes:
a) For (x = 100, x >= 1, x++) printf("%d\n", x); switch (value % 2) { case 0: printf("Inteiro par\n"); case 1: printf("Inteiro mpar\n"); } c) O cdigo seguinte deve ler um inteiro e um caracter e imprimir os dois. Suponha que o utilizador introduz 100 A. scanf("%d", &intVal); charVal = getchar(); printf("Inteiro: %d\nCaracter: %c\n", intVal, charVal); d) for (x = .000001; x >= .0001; x += .000001) printf("%.7f\n", x); for (x = 999; x >= 1; x += 2) printf("%d\n", x);

b) O cdigo seguinte deve imprimir se um dado inteiro par ou mpar:

e) O cdigo seguinte deve imprimir os inteiros mpares de 999 at 1:

f) O cdigo seguinte deve imprimir os inteiros pares de 2 at 100: contador = 2; Do { if (contador % 2 == 0) printf("%d\n", contador); contador += 2; } While (contador < 100); g) O cdigo seguinte deve somar os inteiros de 100 at 150 (suponha que total inicializado com 0): for (x = 100; x <= 150; x++); total += x; h) O programa seguinte pretende responder questo 3.6.b): #include <stdio.h>; main { int n; do printf("Introduza um inteiro positivo: "); scanf("%f", n); while n > 0; int aux = n; int m = 0; do m = m * 10 + aux mod 10 while aux / = 10; /* Nesta altura, m deve ter os mesmos digitos que n, /* mas por ordem inversa. if (m = n) printf(n, " uma capicua\n") else printf(n, " no uma capicua\n"); } return 0

4.2. [Deitel 4.7] Escreva instrues for para imprimir cada uma das seguintes sequncias de valores:
a) 1, 2, 3, 4, 5, 6, 7 b) 3, 8, 13, 18, 23 c) 20, 14, 8, 2, -4, -10

4.3. Escreva instrues for para calcular a soma dos primeiros n termos (com n inteiro previamente
definido) de cada uma das sries seguintes: a) Srie que d o valor da constante matemtica :

4 4 4 4 4 + + +... 3 5 7 9 11 1 1 1 + + +... 1! 2 ! 3!

b) Srie que d o valor da constante matemtica e:

1+

(Sugesto: calcule cada termo a partir do termo imediatamente anterior.) c) Srie que d o valor de e-x (com x real positivo previamente definido):

x x2 x3 + +... 1! 2 ! 3!

(Sugesto: calcule cada termo a partir do termo imediatamente anterior.)

4.4. [Deitel 3.47, 4.14] O factorial de um nmero n no-negativo denotado por n! e definido da
seguinte forma: n! = n (n-1) (n-2) ... 1 n! = 1 (para n =0) (para n 1)

a) Escreva um programa que leia repetidamente nmeros inteiros no-negativos e calcule e imprima o seu factorial, terminando quando introduzido um nmero negativo. (Sugesto: utilize um ciclo for dentro de um ciclo while.) b) Qual o maior nmero cujo factorial calculado correctamente pelo programa da alnea (a)? Porqu? E se, em vez do tipo int, usasse cada um dos seguintes tipos: long, short e char? c) Escreva um programa que imprima uma tabela de factoriais dos nmeros de 1 a 15. (Sugesto: utilize um nico ciclo for.)

4.5. Escreva um programa para determinar as razes da equao quadrtica ax2+bx+c=0, sendo os
coeficientes a, b e c fornecidos pelo utilizador. O programa deve indicar se a equao tem 2 razes reais diferentes, 2 razes reais iguais ou 2 razes complexas conjugadas, e os respectivos valores (com 3 casas decimais). Utilize a funo sqrt da biblioteca de funes matemticas para calcular a raiz quadrada de um nmero em vrgula flutuante. Exemplo: Introduza os coeficientes: 2.5 -1 16 H 2 razes complexas conjugadas: 0.200+2.522i e 0.200-2.522i

4.6. O dia da semana correspondente a uma data pode obter-se atravs da seguinte frmula:
W = [D + (26 * M - 2) / 10 + Y + (Y / 4) + (C / 4) - 2 * C - (1 + L) * (M / 11)] mod 7 em que W - dia da semana: 0=domingo, 1=segunda, etc. M - ms: 1=Maro, 2=Abril, ..., 10=Dezembro=10, 11=Janeiro, 12=Fevereiro C - dois primeiros dgitos do ano (exemplo: 19) Y - dois ltimos dgitos do ano (exemplo: 98) D - dia do ms, a comear em 1 L - 1 se o ano for bissexto e 0 se o ano for comum Nesta frmula, o operador "/" refere-se ao quociente da diviso inteira. Os anos bissextos so os anos mltiplos de 4 que no so mltiplos de 100, e ainda os anos mltiplos de 400. Por exemplo, os anos 1996 e 2000 so bissextos, enquanto que os anos 1998 e 1900 so comuns. a) Escreva um programa que calcule e imprima o nmero de dias de um ms/ano indicado pelo utilizador. (Sugesto: utilize a instruo switch.)

b) Escreva um programa que mostre no ecr o calendrio de um ms/ano indicado pelo utilizador. Exemplo: Ms (1 a 12): 2 Ano (com 4 dgitos): 1999 Dom Seg Ter Qua 1 2 3 7 8 9 10 14 15 16 17 21 22 23 24 28 Qui 4 11 18 25 Sex 5 12 19 26 Sab 6 13 20 27

4.7. Um nmero primo se apenas for divisvel pela unidade e por si prprio. Diz-se que um nmero
a divisvel por um nmero b, se o resto da diviso inteira de a por b for zero. a) Escreva um programa que leia um nmero e determine se primo ou no. b) Escreva um programa que imprima os 100 primeiros nmeros primos. c) Escreva um programa que imprima todos os nmeros primos inferiores a 10000.

4.8. Escreva um programa que imprima o nmero Romano equivalente a um nmero decimal entre 1 e
1000 introduzido pelo utilizador.

4.9. Restruture o seguinte cdigo por forma a evitar o uso das instrues break e continue:
int n, i; while (1) { printf("Introduza um inteiro positivo (0 termina): "); scanf("%d", &n); if (!n) break; if (n < 0) { printf("No aceita nmeros negativos!\n"); continue; } for (i = 2; i * i <= n; i++) if ( ! (n % i) ) break; if (i * i <= n) printf("%d no primo!\n",n); else printf("%d primo!\n",n); }

5. Funes
5.1. [Deitel 5.50] Encontre os erros existentes em cada um dos seguintes segmentos de programas e
explique como os corrigiria: a) float cube(float); ... cube(float number) { return number * } /* prottipo */ /* definio */ number * number;

b) c) d)

register auto int x = 7; int randomNumber = srand(); float y = 123.45678; int x; x = y; printf("%f\n", (float) x);

e)

double square(double number) { double number; } return number * number;

f)

int sum(int n) { if (n == 0) return 0; else return n + sum(n); }

5.2. [Deitel 5.11] A funo floor pode ser usada para arredondar um nmero em vrgula flutuante
para um certo nmero de casas decimais. Por exemplo, a instruo: y = floor(x * 100 + 0.5) / 100; arredonda x para as centsimas (isto , para 2 casas decimais). Escreva uma funo double round(double x, unsigned n) que arredonda um nmero em vrgula flutuante ( x) para um certo nmero de casas decimais ( n), retornando o valor arredondado. Inclua essa funo num programa de teste que pede ao utilizador valores de x e n, e imprime o valor de round(x,n) com um nmero suficientemente grande de casas decimais, terminando quando o utilizador introduz x=0.

5.3. [Deitel 5.29, 5.42] O maior divisor comum (mdc) de dois inteiros x e y o maior inteiro que
divide tanto x como y (com resto 0). a) Escreva uma funo mdc(x,y) capaz de calcular o maior divisor comum de dois inteiros, seguindo a definio acima. b) sabido que mdc(x,y)=mdc(y,x mod y) e mdc(x,0)=x. Escreva uma verso recursiva da funo mdc(x,y) directamente a partir destas propriedades. 1 c) Desenvolva uma verso no recursiva da funo mdc(x,y) tirando partido das propriedades referidas em b).

5.4. Pretende-se implementar uma funo

double PotenciaNatural(double x, unsigned n) que retorne o valor de xn, sem recorrer biblioteca de funes matemticas. a) Escreva uma implementao iterativa desta funo, usando um ciclo for. b) Uma implementao directa desta funo gasta n-1 multiplicaes em vrgula flutuante. No entanto, o nmero de operaes em vrgula flutuante pode ser drasticamente reduzido se atendermos a que: xn = [xn/2]2, se n fr par (2); xn = x[x(n-1)/2]2, se n for mpar (3) x2 = xx; x1 = x; x0 = 1 Por exemplo, x40 pode ser calculado com apenas 6 multiplicaes em vrgula flutuante (e mais algumas operaes aritmticas com inteiros, muito mais rpidas). Escreva uma implementao recursiva da funo PotenciaNatural tirando partido destas frmulas.

c) Existe uma implementao iterativa (simples) que tire partido das propriedades indicadas na alnea anterior?

5.5. [Deitel 5.31] Escreva um programa que simule o lanamento de uma moeda. Para cada
lanamento, o programa deve imprimir Cara ou Coroa. O programa deve efectuar 100 lanamentos, contar o nmero de vezes que sai cada uma das faces, e imprimir os resultados. O programa principal deve chamar uma funo separada cara_ou_coroa, sem argumentos, que retorna 0 para cara e 1 para coroa.

5.6. Refaa o exerccio 4.7, escrevendo uma funo int primo(int n), utilizvel em todas as
alneas, que retorna 1 se n for primo e 0 no caso contrrio. Note que, para verificar se n primo, basta dividir n pelos nmeros de 2 a (int)sqrt(n).

5.7. Refaa o exerccio 4.8 (programa para imprimir o nmero Romano equivalente a um nmero
decimal entre 1 e 1000), dividindo o programa em funes para imprimir os milhares (nada ou M), as centenas (nada, C, ..., ou CM), as dezenas (nada, X, XX, ..., ou XC) e as unidades (nada, I, II, ..., ou IX). Cada uma destas funes deve receber como argumento um nmero entre 0 e 9 (excepto a funo para imprimir os milhares, que s recebe 0 ou 1). Por sua vez, cada uma destas funes deve ser implementada atravs de uma nica chamada a uma funo mais genrica com o seguinte prottipo: void para_romano(int digito, char letra1, char letra5, char letra10); O 1 argumento recebido por esta funo o dgito decimal, de 0 a 9, para imprimir em romano. Os argumentos seguintes indicam os caracteres a usar, de acordo com o peso do dgito (milhares, centenas, dezenas ou unidades). Por exemplo, para imprimir 6 centenas em romano, bastaria invocar para_romano(6, 'C', 'D', 'M');

Conforme o leitor j deve ter reparado, o itlico usado para expresses matemticas, e o Courier bold para cdigo C.

6. "Arrays"
6.1. [Deitel 6.13, a)-d)] Encontre os erros existentes em cada um dos seguintes segmentos de
programas: a) b) c) d) Suponha que foi definido: char str[3]; scanf("%s", str); /* O utilizador introduz ola */ Suponha que foi definido: int a[3]; printf("%d %d %d\n", a[1], a[2], a[3]); float f[3] = {1.1, 10.01, 100.001, 1000.0001}; Suponha que foi definido: double d[2][10]; d[1, 9] = 2.345;

6.2. Escreva um programa para gerar vrias apostas do totoloto todas diferentes entre si, at um
mximo de 20 apostas. O nmero de apostas a gerar dado pelo utilizador. (Sugesto: Represente cada aposta por um vector de 6 nmeros crescentes (compreendidos entre 1 e 49), e represente o conjunto de apostas por um vector de at 20 apostas.)

6.3. Escreva um programa para imprimir o tringulo de Pascal de altura 14, isto , os valores de nCk
para 0kn13. O programa deve produzir um resultado do seguinte tipo (os cabealhos de linhas e colunas so dispensveis): n\k* 12 13 0 1 2 3 4 5 6 7 8 9 10 11

********************************************************************* ****** 0 * 1 1 * 1 1 2 * 1 2 1 3 * 1 3 3 1 4 * 1 4 6 4 1 5 * 1 5 10 10 5 1 6 * 1 6 15 20 15 6 1 7 * 1 7 21 35 35 21 7 1 8 * 1 8 28 56 70 56 28 8 1 9 * 1 9 36 84 126 126 84 36 9 1 10 * 1 10 45 120 210 252 210 120 45 10 1 11 * 1 11 55 165 330 462 462 330 165 55 11 1 12 * 1 12 66 220 495 792 924 792 495 220 66 12 1 13 * 1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1 (Sugesto: Utilize um vector para guardar os valores da linha corrente. Para calcular a linha seguinte (n), basta acrescentar um 1 na coluna n e somar ao elemento da coluna k o elemento da coluna k-1, para k=n-1, ..., 1.)

6.4. Pretende-se escrever uma programa para efectuar operaes com polinmios. Cada polinmio
ser representado por um vector com os coeficientes em vrgula flutuante e por um inteiro sem sinal com o grau do polinmio. O programa aceitar polinmios com grau desde 0 at 20. a) Escreva uma funo int lePolinomio(float coefs[]) para ler um polinmio. A funo deve colocar os coeficientes no vector coefs e deve retornar o grau do polinmio.

b) Escreva uma funo void escrevePolinomio(int coeficientes[]), para escrever um polinmio.

grau,

const

float

c) Escreva uma funo float calculaPolinomio(int grau, const float coefs[], float x), para calcular e retornar o valor de um polinmio num ponto x. (Sugesto: Para minimizar o nmero de operaes em vrgula flutuante, atenda a que, por exemplo, a0+a1x+a2x2+a3x3 = a0+(a1+(a2+(a3)x)x)x. Esta segunda expresso pode ser calculada "de dentro para fora".) d) Escreva um programa para integrar e testar as funes anteriores, apresentando um menu do tipo: 1. 2. 3. 4. Introduzir polinmio Mostrar polinmio Calcular valor de polinmio num ponto Terminar

6.5.

Escreva uma funo void factoresPrimos(unsigned n, unsigned factores[32]) para decompor um nmero inteiro positivo n, entre 2 e 232-1, em factores primos. Os factores primos so colocados no vector factores[], por ordem no decrescente, seguidos de um 0 no fim. Use depois esta funo para achar o mmc (menor mltiplo comum) e o mdc (maior divisor comum) de pares de nmeros dados pelo utilizador. No 1 caso necessrio achar a "reunio" dos factores primos e no 2 caso necessrio achar a "interseco" dos factores primos.

6.6. Pretende-se construir um programa que permite efectuar operaes sobre matrizes quadradas.
a) Escreva funes para ler e escrever uma matriz. b) Escreva uma funo para transpor uma matriz. c) Escreva uma funo para multiplicar duas matrizes e colocar o resultado numa terceira. d) Diz-se que um elemento de uma matriz um mximo local se for superior a todos os seus vizinhos. Escreva um funo maximos_locais que imprima todos os mximos locais e respectivas posies, considerando que qualquer elemento da matriz pode ser um mximo local. Escreva um programa com um pequeno menu que permita integrar e testar todas as funes escritas nas alneas anteriores.

6.7. Pretende-se escrever um programa para jogar mastermind (sem visual grfico). As cores so
representadas por nmeros de 1 a 8. A chave uma sequncia de 5 cores diferentes. A chave gerada aleatoriamente pelo computador, e o utilizador tenta adivinhar a chave. A cada tentativa do utilizador, o computador responde com a respectiva pontuao (nmero de cores certas no stio certo e nmero de cores certas no stio errado). O computador deve ainda assinalar as tentativas inconsistentes com as pontuaes obtidas nas tentativas anteriores (uma tentativa inconsistente se as pontuaes anteriores se alterarem no caso da chave ser substituda por essa tentativa). O nmero mximo de tentativas 10.

6.8. [Baseado em Deitel 6.26] O problema das oito rainhas pode ser formulado da seguinte forma:
possvel colocar oito rainhas num tabuleiro de xadrez sem se atacarem mutuamente (i.e., sem que nenhumas duas rainhas estejam na mesma linha, na mesma coluna ou na mesma diagonal)? Escreva um programa para achar pelo menos uma soluo (ou todas as solues) para este problema. Sugesto: Considere as linhas e colunas de um tabuleiro de xadrez numeradas de 0 a 7, e as diagonais numeradas de 0 a 14. Sendo i o n da linha e j o n da coluna, as duas diagonais correspondentes podem ser numeradas i+j e i+7-j. Para representar uma soluo do problema, use um vector int S[8], em que S[i] indica a coluna (entre 0 e 7) em que se encontra a rainha que se encontra na linha i (entre 0 e 7). Esta representao impede que duas rainhas estejam na mesma linha. Suponha que este vector preenchido com os nmeros 0, 1, ..., 7 (o que quer dizer que a rainha da linha 0 est na coluna 0, a rainha da linha 1 est na coluna 1, etc.). Desta forma, no h duas rainhas na mesma coluna. No entanto, esto todas as rainhas na mesma diagonal! O problema inicial pode agora ser formulado da seguinte forma: encontrar uma permutao deste vector de 8 nmeros em que no fiquem duas rainhas

na mesma diagonal. Por exemplo, uma soluo possvel {3, 7, 0, 2, 5, 1, 6, 4}. Note que h 8! = 40320 permutaes possveis. Utilize vectores para marcar as diagonais ocupadas.

7. Apontadores
7.1. O que imprime cada um dos seguintes segmentos de programa?
a) int x = 1, y, *p1, *p2; p1 = &x; p2 = &y; *p2 = *p1; ++*p1; printf("%d %d %d %d\n", x, y, *p1, *p2); float x = 3.14, *p = &x; *p = x; printf("%.2f %.2f\n", x, *p); int v[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 0}, *p; for (p = v; *p; p++) printf("%d\n", *p); int a[4] = {0, 1, 2, 3}, *p; p = a; printf("%d %d %d %d ", a[0], p[1], *(p+2), *(a+3)); char *nomes[] = {"Joo", "Jos", "Joaquim"}; printf("%d %d\n", sizeof(nomes), sizeof(nomes) / sizeof(char *)); printf("%c%s %s %s\n", **nomes, nomes[0]+1, *(nomes+1), nomes[2]); void forall(int *v, int size, void (*f)(int)) { for ( ; size>0; size--) (*f)(*v++); } void mostra(int n) { printf("%5.2f%%\n", n / 100.0); } main() {

b)

c)

d)

e)

f)

int v[4] = {57, 63, 80, 90}; forall(v, 4, mostra); return 0;

7.2. [Deitel 7.6, a)-g)] Indique e corrija, se possvel, o erro existente em cada um dos seguintes
segmentos de programa. a) int *numero; printf("%d\n", *numero);

b)

float *realPtr; long *intPtr; intPtr = realPtr; int *x, y; x = y; char s[] = "isto um array de caracteres"; int contador; for ( ; *s != '\0'; s++) printf("%c ", *s); short *numPtr, resultado; void *genericPtr = numPtr; resultado = *genericPtr + 7; float x = 19.34; float xPtr = &x; printf("%f\n", xPtr); char *s; printf("%s\n", s); char s[] = "ola"; const char * p1 = s; char * const p2 = s; p1[2] = 'e'; p2[2] = 'e';

c) d)

e)

f)

g) h)

7.3. [Wirth] O Quicksort (tambm designado mtodo de ordenao por partio) um mtodo de
ordenao de arrays muito eficiente que se baseia num algoritmo recursivo do seguinte tipo: 1. Passo de partio: 1.1. Escolher um elemento arbitrrio (x) do array (v) no ordenado, por exemplo o do meio. 1.2. Partir o array em dois sub-arrays, com valores x do lado esquerdo e valores x do lado direito, da seguinte forma: 1.2.1. Inicializar i = primeira posio do array 1.2.2. Inicializar j = ltima posio do array 1.2.3. Enquanto i j fazer: 1.2.3.1. Enquanto v[i] < x, incrementar i 1.2.3.2. Enquanto v[j] > x, decrementar j 1.2.3.3. Se i j, trocar v[i] com v[j], incrementar i e decrementar j Passo recursivo: Efectuar o passo 1 para cada um dos sub-arrays (esquerdo e direito) no ordenados, desde que o seu comprimento seja maior do que 1, ou seja: 2.1. Se j > primeira posio do array, ordenar o sub-array entre a primeira posio e a posio j, inclusiv. 2.2. Se i < ltima posio do array, ordenar sub-array entre a posio i e a ltima posio, inclusiv. i 8 9 2 5 j 6 1 3 7

2.

A figura seguinte ilustra o passo 1 do algoritmo. x 4

j < i 3 1 x 2 4 5 6 9 x 8 7

a) Escreva uma funo recursiva quicksort para ordenar um array de inteiros pelo mtodo exposto, recebendo como argumentos o endereo do primeiro elemento e o nmero de elementos do array a ordenar. A funo deve ter o seguinte prottipo: void quicksort (int *v, int size); b) Escreva um pequeno programa para testar a funo anterior. c) Escreva e teste uma verso alternativa da funo quicksort, recebendo como argumentos os endereos do primeiro e do ltimo elemento do array a ordenar.

7.4. [adaptado de Deitel 7.25] A seguinte matriz de 0's e 1's representa um labirinto de 8 x 8 (com o
trajecto entre a entrada e a sada realado a bold): 1 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 0 1 1 1 1 0 1 1 0 1 1 0 0 0 1 1 0 0 1 0 1 0 1 1 1 1 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 1 1 1 1 1

Os 1's representam as paredes. Um mtodo simples para encontrar a sada garantidamente (no necessariamente pelo caminho mais curto), consiste em "seguir sempre pela direita". Se o labirinto no tiver nenhuma sada, acaba por se voltar posio de partida. a) Escreva uma funo atravessaLabirinto para atravessar um labirinto 8 x 8. A funo deve receber como argumentos a matriz de caracteres que descreve o labirinto, bem como a linha e coluna de entrada (na fronteira do labirinto). A funo deve substituir 0 por X ao longo do caminho percorrido, e deve marcar a entrada com E e a sada com S (caso exista sada). b) Escreva uma funo geraLabirinto para gerar aleatoriamente um labirinto 8 x 8 (no necessariamente com sada), tendo como argumentos a matriz de caracteres a ser preenchida com 0's e 1's, e apontadores para receber a linha e coluna de entrada. c) Escreva uma funo imprimeLabirinto para imprimir um labirinto. A funo deve receber como argumento a matriz de caracteres que descreve o labirinto. Generalizar as funes anteriores (acrescentado ou modificando argumentos se necessrio) para trabalhar com labirintos de qualquer dimenso, no necessariamente quadrados. (Sugesto: Atenda a que, numa matriz com m colunas, o elemento da coluna j da linha i tem um offset de m*i+j posies em relao ao elemento da 1 coluna da 1 linha.)

d) Escreva um programa para integrar e testar as funes anteriores. e)

7.5. Escreva uma funo void numExtenso(unsigned n), para escrever no ecr um nmero n,
entre 0 e 9999, por extenso. Por exemplo, numExtenso(2432) deve produzir: DOIS MIL QUATROCENTOS E TRINTA E DOIS Sugesto: Utilize arrays de strings para guardar as designaes das unidades, dezenas e centenas por extenso: char *unidades [] = {"ZERO", "UM" ,"DOIS" , ... ,"DEZANOVE"}; char *dezenas [] = {"", "DEZ", "VINTE", ... , "NOVENTA"}; char *centenas [] = {"", "CEM", "DUZENTOS", ... , "NOVECENTOS"};

7.6. Usando a funo do problema anterior, escreva uma funo void dataExtenso(int dia,
int mes, int ano), para escrever no ecr uma data por extenso. Por exemplo, dataExtenso(27,4,1998) deve produzir: VINTE E SETE DE MARO DE MIL NOVECENTOS E NOVENTA E OITO Escreva um pequeno programa para testar esta funo. Sugesto: Utilize um array de strings para guardar as designaes dos meses por extenso: char *meses[] = {"", "JANEIRO", "FEVEREIRO", ..., "DEZEMBRO"};

8. Caracteres e cadeias de caracteres (strings)


8.1. Escreva um funo int identificadorValido(char *str) que verifica se uma string
(str) contm um identificador vlido, isto , uma letra seguida de zero ou mais letras ou dgitos. (Sugesto: Use as funes isalpha e isalnum.)

8.2. Escreva uma funo double converteMontante(char *str) para converter uma string
com um montante em dinheiro para double. Na string, usado o cifro ( $) para separar os escudos dos tostes e centavos e usado o ponto ( .) para separar grupos de 3 dgitos. O montante pode ser precedido do sinal menos (-). Exemplos: -1.000$00 67.718$30 14$50 . (Sugesto: Use a funo isdigit.)

8.3. Escreva uma funo void formataMontante(double montante, char *str) com
o objectivo oposto da funo anterior.

8.4. Escreva uma funo void normalizaNome(char *nomePtr, char *normPtr) para
normalizar um nome (apontado por nomePtr) da seguinte forma: as minsculas so convertidas para maisculas; sequncias de vrios espaos ou tabs entre duas palavras so substitudos por um nico espao; espaos ou tabs no incio ou no fim so suprimidos; so removidas as palavras "DE", "DO", "DA", "DAS", "DOS" e "E". O nome normalizado colocado no array de caracteres apontado por normPtr. Considere que cada palavra do nome no tem mais de 40 caracteres. (Sugesto: Guarde as palavras a eliminar num array de strings e use as funes strtok, strcmp, toupper e strcat.)

8.5. Escreva um programa para ler nomes do "standard input" (um nome em cada linha, com 256
caracteres no mximo) e imprimir os nomes normalizados correspondentes no "standard ouput", usando a funo do problema anterior. O programa deve terminar quando aparece uma linha vazia. (Sugesto: Use as funes gets e puts.)

8.6. Escreva uma funo int contaOcorrncias(char *s1, char *s2) para contar o
nmero de ocorrncias no sobrepostas da string s1 na string s2. (Sugesto: Use a funo strstr.)

8.7. Refaa a funo numExtenso() do exerccio 7.5, por forma a escrever o nmero por extenso
numa string, em vez de o escrever no ecr. O prottipo da novo funo ser: void numExtenso(unsigned n, char *str) ; (Sugesto: Use a funo strcat.)

8.8. Escreva uma variante da funo quicksort do exerccio 7.3 (ver Resposta a exerccios
seleccionados), para ordenar um array de strings em vez de um array de inteiros. Usando essa variante, escreva um programa que leia vrias linhas do "standard input", at um mximo de 50 linhas de 80 caracteres, e escreva as mesmas linhas ordenadas alfabeticamente no "standard output".

8.9. Escreva um programa que copie caracteres do "standard input" para o "standard output",
suprimindo as sequncias de caracteres comeadas em "/*" e terminadas em "*/" (incio e fim de comentrio em C), bem como as sequncias de caracteres comeadas em "//" e terminadas com o caracter de mudana de linha. (Sugesto: Use as funes getchar e putchar.)

9. Estruturas, unies, enumeraes e manipulao ao bit


9.1. Suponha que se define o seguinte tipo de estrutura para representar datas:
struct data { int dia, mes, ano; }; Implementa e teste as seguintes funes: /* L uma data do "standard input", no formato dia/ms/ano, com o ms de 1 a 12 e o ano com 4 dgitos. Retorna a estrutura que descreve a data. */ struct data le_data(void); /* Escreve uma data no "standard output", no mesmo formato entendido por "le_data". */ void escreve_data(struct data d); /* Compara duas datas. Retorna 1, 0 ou 1 conforme a 1 data (d1) maior, igual ou menor do que a 2 data (d2). */ int compara_datas(struct data d1, struct data d2);

9.2. Suponha que, para implementar uma calculadora capaz de trabalhar com nmeros inteiros ou em
vrgula flutuante, se definem os seguintes tipos de dados e prottipos de funes: enum number_types {LONG, DOUBLE}; union number_value { long l_value; double d_value; }; struct number { enum number_types type; /* indica qual o campo usado na unio */ union number_value value; }; typedef struct number NUMBER; /* L um nmero do "standard input". Se o nmero for introduzido com o ponto decimal ou com o "E" da notao exponencial, l-o para um double. Seno, l-o para um long. Retorna a estrutura com o tipo e o valor lido. */

NUMBER read_number(void); /* Escreve o nmero descrito por "num" no "standard output", usando a notao apropriada ao tipo. */ void write_number(NUMBER num); /* Soma dois nmeros inteiros ou em vrgula flutuante e retorna a estrutura com o tipo e o valor resultante. Se pelo menos um dos nmeros for do tipo double, o resultado do tipo double. Seno, o resultado do tipo long. */ NUMBER add_numbers(NUMBER num1, NUMBER num2); a) Implementa e teste as funes anteriores. b) Implementa verses alternativas das funes anteriores, usando apontadores para estruturas em vez de estruturas na chamada das funes. Os prottipos passam a ser: void read_number(NUMBER *numPtr); void write_number(const NUMBER *numPtr); void add_numbers(const NUMBER *numPtr1, const NUMBER *numPtr2, NUMBER *sumPtr);

9.3. Refaa o exerccio 6.8 (ver exerccios resolvidos), usando dois inteiros, em vez de dois vectores, e
operaes bit-a-bit para tratar as duas diagonais. Comece por escrever instrues ou expresses para activar (colocar a 1), desactivar (colocar a 0) e testar (retornando 1 ou 0) o i-simo bit de uma varivel a do tipo unsigned, com i entre 0 e 31. Escreva tambm uma instruo para desactivar todos os bits.

9.4. A assiduidade de um funcionrio num ms pode ser codificada num inteiro de 32 bits sem sinal
(unsigned), em que o i-simo bit a 1 (0) significa que o funcionrio compareceu (faltou) ao trabalho no dia i (1in. de dias do ms). Implemente e teste as seguintes funes, baseadas nessa representao: /* L, codifica e retorna os dias de comparncia ao trabalho de um dado funcionrio num dado ms. */ unsigned le_dias_trab(char *nome_func, char *mes, int n_dias_mes); /* Imprime os dias de comparncia ao trabalho de um dado funcionrio num dado ms. */ void escreve_dias_trab(char *nome_func, char *mes, unsigned dias_trab); /* Conta os dias de comparncia ao trabalho de um dado funcionrio num dado ms (irrelevantes para o caso). */ int conta_dias_trab(unsigned dias_trab);

10. Manipulao de ficheiros


10.1. Suponha que as notas obtidas pelos alunos a um teste se encontram num ficheiro de texto
"notas.dat". A 1 linha do ficheiro tem o nmero de alunos que compareceram ao teste. Cada um das restantes linhas do ficheiro tem o nome do aluno e a nota respectiva, separados por um ou mais espaos ou "tabs". A nota indicada por um inteiro entre 0 e 20.

A partir dessas notas, pretende-se construir um ficheiro de texto "histograma.dat", com o nmero de ocorrncias de cada nota (0, 1, 2, ..., 20). Cada linha do ficheiro tem a nota e o nmero de alunos com essa nota, separados por um espao. Escreva um programa que construa o ficheiro "histograma.dat" a partir do ficheiro "notas.dat". Por uma questo de generalidade, o programa deve perguntar ao utilizador os nomes dos ficheiros no incio da sua execuo.

10.2. Escreva um programa para efectuar a manuteno de um ficheiro binrio "artigos.dat" com
dados de artigos em stock. O ficheiro constitudo por registos do seguinte tipo: struct artigo { char nome_artigo [40]; /* string */ float quantidade_em_stock; char unidade_medida [10]; /* string */ float preco_unitario; }; O programa deve comear por abrir o ficheiro. No caso do ficheiro no existir, o programa deve criar o ficheiro vazio. Seguidamente, deve apresentar um menu com as seguintes opes: 1. 2. 3. 4. 5. 6. Listar o contedo do ficheiro Inserir um novo artigo no fim do ficheiro Procurar um artigo pelo nome Procurar um artigo pela posio no ficheiro Modificar os dados do ltimo artigo procurado Terminar

Antes de terminar, o programa deve fechar o ficheiro.

11. Estruturas de dados dinmicas


11.1. Escreva um programa que l um conjunto de linhas do standard input e as escreve de volta no
standard output por ordem inversa. Suponha que as linhas de entrada no tm mais de 1000 caracteres. As linhas de entrada devem ser guardadas em memria numa lista ligada usada como pilha ("last in first out"). Cada n da lista deve conter dois campos: um apontador para o n seguinte; um apontador para uma string (array de caracteres terminado em '\0') alocada dinmicamente contendo uma linha lida do standard input. Sugesto: Use as funes gets(s) e puts(s). A funo gets retorna NULL quando encontra o fim dos dados de entrada (EOF). Quando se introduzem dados pelo teclado, o fim dos dados geralmente sinalizado com Ctrl-D em UNIX e com Ctrl-Z em DOS/WINDOWS.

11.2. (baseado em 10.2) Escreva um programa para efectuar a manuteno de uma lista de artigos.
Cada artigo descrito por uma estrutura do seguinte tipo: struct artigo { char nome_artigo [40]; /* string */ float quantidade_em_stock; char unidade_medida [10]; /* string */ float preco_unitario; };

A lista de artigos deve ser representada em memria por uma lista ligada. Cada n da lista deve ter uma estrutura do tipo indicado acima e um apontador para o n seguinte. A lista deve estar ordenada por nome de artigo. No podem existir dois artigos com o mesmo nome. No nico do programa a lista est vazia. O programa deve apresentar um menu com as seguintes opes: 7. 8. 9. Listar (imprime o contedo da lista em formato tabular) Inserir um artigo (pergunta os dados do artigo e insere na lista) Eliminar um artigo pelo nome (pergunta o nome do artigo, mostra os dados actuais, pede confirmao e s depois o elimina da lista) 10. Modificar um artigo (mantendo o nome) (pergunta o nome do artigo, mostra os dados actuais e pede os novos dados) 11. Procurar um artigo pelo nome (pergunta o nome do artigo e mostra os respectivos dados) 12. Terminar Antes de terminar, o programa deve libertar a memria ocupada pela lista.