12 Repetições com for
A linguagem C permite laços de repetição, sendo um deles dado pelo for
. Neste capítulo essa estrutura é abordada.
12.1 A estrutura de repetição for
O for
é um comando usado para repetições definidas, ou seja, para as quais o número de vezes que os comandos serão executados já é conhecida. Por exemplo, se houver um dado disponível para cada hora do dia, sabe-se de antemão que há 24 dados e uma repetição com esse número de vezes pode ser empregado.
Na linha das demais estruturas de fluxo, também o for
admite a repetição de um único comando, que pode ser simples ou composto. Suas demais partes são:
- A iniciação, a qual é composta pela atribuição inicial e é executada uma única vez antes das repetições;
- A condição_de_continuidade, cujo valor verdadeiro é condição para iniciar uma execução de comando;
- O incremento, o qual é usado para atualizar o valor da variável usada no laço.
O seguinte trecho de código pode ser usado como exemplo.
for (int i = 0; i < 10; i++)
("%d ", i); printf
Ele pode ser considerado como “para i
variando de 0 até 9” em um total de 10 repetições. A variável i
é declarada dentro do for
e, como tal, possui validade apenas nesse escopo. Seu valor inicial é zero e essa atribuição é feita antes das repetições. Antes de qualquer repetição, a condição i < 10
é avaliada e o printf
somente é executado se a condição for verdadeira. Terminada a execução do comando do for
, o incremento i++
é executado, alterando o valor de i
antes da próxima verificação de continuidade.
Em termos gerais, o for
exemplificado é absolutamente equivalente trecho seguinte.
{
int i = 0; // iniciação
while (i < 10) { // condição de continuidade
("%d ", i); // comando
printf++; // incremento
i}
}
Observar que todo o código está dentro de um comando composto (entre chaves) é importante, visto que i
tem validade exclusiva dentro do bloco de comandos.
Outros exemplos de repetição com for
são apresentados na sequência.
// contagem de 10 até 1
for (int i = 10; i > 0; i--)
("%d ", i); printf
// contagem de 1 até 100
for (int i = 1; i <= 100; i++)
("%d ", i); printf
// contagem de 0 a 1 de 0,1 em 0,1
for (double i = 0; i <= 1; i += 0.1)
("%d ", i); printf
12.2 for
versus while
Conforme apresentado na seção anterior, a estrutura do for
equivale à de um while
. A questão, então, é porque usar o for
?
A estrutura do for
é um recurso vastamente utilizada nas linguagens de programação e comum também no pseudocódigo. Como ela é indicada para repetições já previsíveis, ter todas as informações necessárias logo no início do comando ajuda a compreensão do propósito do trecho de código.
Em princípio, ao se olhar a linha em que está o for
já se tem ideia de como começa e como termina. O uso do while
, por sua vez, indica uma imprevisibilidade do término, o que leva um eventual leitor do programa a procurar como os dados são modificados e como isso afeta a condição da repetição.
Não se deve usar um for
para substituir um while
nem um while
para substituir um for
.
Quando o número de repetições é conhecido, o for
deve ser empregado; se esse número estiver em aberto, a melhor opção é o while
.
Porém, não é incomum o uso do while
em repetições definidas.
Um discussão mais ampla sobre o uso do for
, complementando esta dica, está na seção Capítulo 15.
12.3 Repetições baseadas na entrada
Uma forma de se processar uma sequência de valores é prefixá-la com a quantidade de valores de entrada. Assim, se existirem 25 dados para serem processados, o valor 25 é introduzido antes dos dados, o que viabiliza ter, antes da repetição, o número de vezes de execução e, assim, usar o for
adequadamente e com clareza.
Segue um exemplo simples de um programa que apresenta os primeiros \(n\) números ímpares naturais.
/*
Apresentação dos n primeiros números naturais ímpares
Requer: a quantidade n
Assegura: a apresentação dos n primeiros números ímpares
*/
#include <stdio.h>
int main(void) {
char entrada[160];
("Digite a quantidade desejada de ímpares: ");
printf(entrada, sizeof entrada, stdin);
fgetsint quantidade;
(entrada, "%d", &quantidade);
sscanf
for(int i = 0; i < quantidade; i++)
("%d ", 2 * i + 1);
printf("\n");
printf
return 0;
}
12
Digite a quantidade desejada de ímpares: 1 3 5 7 9 11 13 15 17 19 21 23
12.4 Exemplos
Nesta seção são apresentados alguns exemplos de programas simples com repetições para as quais o for
é a escolha mais direta.
12.4.1 Média de 24 temperaturas
Na linha do exemplo das temperaturas hora a hora é apresentado o Algoritmo 12.1, o qual determina a média das temperaturas colhidas a cada hora de um dia.
Algoritmo 12.1: Cálculo da média das temperaturas horárias de um dia
Segue, agora, a implementação desse algoritmo.
/*
Cálculo da média de 24 medidas de temperatura colhidas hora a hora durante um dia
Requer: uma sequência de 24 temperaturas em Celsius
Assegura: a média dessas temperaturas
*/
#include <stdio.h>
int main(void) {
("Digite as temperaturas.\n");
printf
double soma_temperaturas = 0;
for (int hora = 0; hora < 24; hora++) {
char entrada[160];
("Temperatura de %2dh: ", hora);
printf(entrada, sizeof entrada, stdin);
fgetsdouble temperatura;
(entrada, "%lf", &temperatura);
sscanf
+= temperatura;
soma_temperaturas }
("Média diária: %.1fºC.\n", soma_temperaturas / 24);
printf
return 0;
}
Digite as temperaturas.9.7
Temperatura de 0h: 9.6
Temperatura de 1h: 10.6
Temperatura de 2h: 8.1
Temperatura de 3h: 14.1
Temperatura de 4h: 14.5
Temperatura de 5h: 12.1
Temperatura de 6h: 18.2
Temperatura de 7h: 19.2
Temperatura de 8h: 20.7
Temperatura de 9h: 24.2
Temperatura de 10h: 24.5
Temperatura de 11h: 18.4
Temperatura de 12h: 23.1
Temperatura de 13h: 21.5
Temperatura de 14h: 21.9
Temperatura de 15h: 23.9
Temperatura de 16h: 23.7
Temperatura de 17h: 18.7
Temperatura de 18h: 20.4
Temperatura de 19h: 16.6
Temperatura de 20h: 14.2
Temperatura de 21h: 8.0
Temperatura de 22h: 9.5
Temperatura de 23h: Média diária: 16.9ºC.
12.4.2 Áreas de triângulos
O Algoritmo 12.2 é uma proposta de nível alto para a determinação da área de uma dada quantidade de triângulos. A quantidade de áreas a serem calculadas é a primeira entrada esperada pela solução.
Algoritmo 12.2: Cálculo da área de uma sequência de triângulos.
Para mais detalhes, segue a versão do Algoritmo 12.2 com menor grau de abstração. Nesta versão optou-se por fazer o cálculo da área por semiperímetro.
Algoritmo 12.3: Cálculo da área de uma sequência de triângulos usando o semiperímetro.
Uma implementação do Algoritmo 12.3 em C é apresentada na sequência.
/*
Cálculo da área de diversos triângulos definidos pelas coordenadas em R^2
de seus vértices
Requer: a quantidade de triângulos seguida pelas coordenadas $(x,y)$ de
cada vértice do triângulo
Assegura: a apresentação de cada área calculada
*/
#include <stdio.h>
#include <math.h>
int main(void) {
char entrada[160];
("Digite a quantidade de triângulos: ");
printf(entrada, sizeof entrada, stdin);
fgetsint quantidade;
(entrada, "%d", &quantidade);
sscanf
for (int i = 1; i <= quantidade; i++) {
("Triângulo %d:\n"
printf"Digite x e y do vértice 1: ", i);
(entrada, sizeof entrada, stdin);
fgetsdouble x1, y1;
(entrada, "%lf%lf", &x1, &y1); // (x1, y1)
sscanf("Digite x e y do vértice 2: ");
printf(entrada, sizeof entrada, stdin);
fgetsdouble x2, y2;
(entrada, "%lf%lf", &x2, &y2); // (x2, y2)
sscanf("Digite x e y do vértice 3: ");
printf(entrada, sizeof entrada, stdin);
fgetsdouble x3, y3;
(entrada, "%lf%lf", &x3, &y3); // (x3, y3)
sscanf
double lado1 = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
double lado2 = sqrt(pow(x1 - x3, 2) + pow(y1 - y3, 2));
double lado3 = sqrt(pow(x2 - x3, 2) + pow(y2 - y3, 2));
double semiperimetro = (lado1 + lado2 + lado3) / 2;
double area = sqrt(semiperimetro * (semiperimetro - lado1) *
(semiperimetro - lado2) * (semiperimetro - lado3));
("Área do triângulo %d: %.2f.\n\n", i, area);
printf}
return 0;
}
2
Digite a quantidade de triângulos:
Triângulo 1:0 0
Digite x e y do vértice 1: 0 1
Digite x e y do vértice 2: 1 0
Digite x e y do vértice 3:
Área do triângulo 1: 0.50.
Triângulo 2:-1.5 -1
Digite x e y do vértice 1: 1.5 -1
Digite x e y do vértice 2: 0 3.8
Digite x e y do vértice 3: Área do triângulo 2: 7.20.
12.4.3 Desenho de um “círculo”
O programa seguinte mostra o aninhamento de dois laços for
. Cada um deles vai de -10 a 10 e a saída é um *
caso a distância ao “centro” seja menor que 10. No programa, ao invés de calcular \({\sqrt{x^2 + y^2} \leq 10}\), optou-se por usar a expressão equivalente \({x^2 + y^2 \leq 10^2}\), que não requer calcular a raiz quadrada.
/*
Desenho de um círculo usando caracteres
Assegura: apresentação de um círculo tão razoável quanto possível
*/
#include <stdio.h>
int main(void) {
for (int x = -10; x <= 10; x++) {
for (int y = -10; y <= 10; y++)
if (x * x + y * y <= 100) // distância < 10
("XXX"); // no círculo
printfelse
(" "); // fora do círculo
printf("\n");
printf}
return 0;
}
XXX
XXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXX XXX
Como cada caractere escrito sempre tem altura maior que a largura, optou-se por usar três caracteres para cada posição para tentar compensar essa diferença e obter o “círculo” com menor distorção. A escolha por três caracteres foi feita por tentativa e erro.