Stoa :: C/C++ :: Blog :: Histórico

Outubro 2007

Outubro 03, 2007

user icon

O que são os laços while e do ... while?

A palavra while em inglês significa enquanto e a expressão do ... while significa faça ... enquanto. O laço while é uma estrutura de controle de fluxo que permite que um conjunto de instruções seja executado enquanto uma condição estiver satisfeita. É também comum que seja dito que os laços while e do ... while são instruções de loop (comumente traduzidos para o português como laço). O laço do ... while é, assim como o laço while, uma estrutura de controle de fluxo, que será executado uma vez e depois será executado enquanto uma condição for verdadeira. Portanto a diferença entre o laço while e o laço do ... while é que o laço do ... while é sempre executado ao menos uma vez, enquanto que o laço while pode não ser executado nenhuma vez, caso a condição de controle de sua execução não seja satisfeita na primeira passagem do processador por esse laço. A sintaxe do laço while é:

 

while ( condição de execução )

{

/* Instruções a serem executadas */

}

 

A sintaxe do laço do ... while é:

 

do

{

/* Instruções que serão executadas ao menos uma vez */

}

while ( condição de execução );

 

O laço while e utilizado quando um determinado conjunto de instruções deve ser executado um número indeterminado de vezes, mas somente até uma certa condição ocorrer. O laço do ... while é utilizado quando há um conjunto de instruções a ser executado um número indeterminado de vezes, mas no caso em que esse conjunto de instruções deve ser executado ao menos uma vez, necessariamente.

 

O que é fluxo? O que é controle de fluxo? O que é loop?

Estas questões foram respondidas em "O laço for" - Aspectos básicos - parte 1.

 

Como é a sintaxe da instrução while? E da instrução do ... while?

A sintaxe da instrução while é:

 

while ( condição de execução )

{

/* Instruções */

}

 

A condição de execução é a expressão lógica que será avaliada pelo computador para determinar se as instruções do bloco serão executadas ou não. Se a expressão for verdadeira, o bloco é executado. Se a expressão for falsa, o bloco não é executado. Por exemplo, o laço a seguir nunca é executado:

 

while ( 0 > 1 )

{

printf("\nEu lhe devo R$1.000,00.");

}

 

A sintaxe do laço do ... while é:

 

do

{

/* Instruções */

}

while ( condição de execução );

 

Note que a instrução while, que fica após o bloco de instruções, tem um ponto-e-vírgula após os parênteses de sua condição de execução. É muito comum esquecer desse ponto-e-vírgula, portanto se ocorrer um erro nessa linha de um programa seu, verifique se esqueceu do ponto-e-vírgula após o laço do ... while!

A condição de execução do laço do ... while tem a mesma função que a condição de execução do laço while: o laço será executado enquanto essa condição for verdadeira. A diferença é que, no laço do ... while, a condição de execução é testada após a execução do bloco de instruções, de modo que mesmo que a condição nunca seja satisfeita, o bloco de instruções será executado ao menos uma vez. Por exemplo, o bloco abaixo ser'executado exatamente uma vez:

 

do

{

printf("\nAlberto esqueceu de pagar sua divida.");

}

while ( 0 > 1 )

 

 

Palavras-chave: laço, laço while, while

Postado por Renato Callado Borges em C/C++ | 0 comentário

Outubro 10, 2007

user icon

Ao encontrar uma instrução while tal como a do código abaixo, o computador segue uma certa sequência de passos, descrita logo a seguir.

 

int soma = 0, a = 1;

while ( a != 0 )

{

   printf("\nDigite um numero inteiro para somar, ou zero para terminar a soma: ");

   scanf("%d", &a);

   soma = soma + a;

}

printf("\nA soma é %d.", soma);

 

A primeira coisa que o computador faz é verificar se a condição de execução é satisfeita. No caso, como atribuímos o valor 1 à variável a, ela é diferente de 0, e portanto o bloco de instruções será executado. Nesse bloco, é feita uma atribuição de valor à variável a pelo usuário - note que portanto o usuário pode entrar com números diferentes de zero um número indeterminado de vezes - e o bloco será executado até que o usuário entre com o valor 0 para a variável a. Assim que a condição de execução deixa de ser satisfeita, o fluxo passa para a primeira instrução após o laço while, que no exemplo acima imprime o conteúdo da variável soma.

 

Neste exemplo, tivemos de atribuir um valor não-nulo à variável a antes do laço while pois se apenas declarássemos esta variável, seu valor inicial, que é comumento chamado de "lixo", poderia eventualmente ser igual a zero, e nesse caso o laço não seria executado nem mesmo uma vez, resultando em o programa imprimir o valor que estiver contido ena variável soma, no caso, 0. Uma maneira alternativa de resolver esse problema é utilizando o laço do ... while:

 

int soma = 0, a;

do

{

   printf("\nDigite um número inteiro para somar, ou zero para terminar a soma: ");

   scanf("%d", &a);

   soma = soma + a;

}

while ( a != 0 );

printf("\nA soma é %d.", soma);

 

 

Neste último exemplo, só será impresso que a soma é zero se o usuário digitar 0 como o primeiro número ao ser pedido que digite um número para somar.

 

 

Exemplo: obter o primeiro fatorial que é maior que 1000.

 

 

int fatorial = 1, n = 1;

do

{

   fatorial = fatorial * n;

    n++;

}

while ( fatorial <= 1000);

 

 

Exercício: obtenha o primeiro quadrado maior que 2000.

 

 

Exemplo: imprimir o produto de dois números até que esse produto seja maior que 1000 ou menor que 10.

 

 

int produto, a, b;

do

{

   printf("\nDigite um numero inteiro: ");

   scanf("%d", &a);

   printf("\nDigite outro numero inteiro: ");

   scanf("%d", &b);

   produto = a * b;

   printf("\na * b = %d.", produto);

}

while ( produto >= 10 && produto <= 1000);

 

 

Exercício: imprima a soma de dois números até que ocorra de uma soma ser ímpar.

 

 

Exemplo: somar e imprimir a soma de uma sequência de números inteiros estritamente crescente.

 

 

int anterior = -1001, atual, soma = 0;

do

{

   printf("\nDigite um numero real entre -1000 e 1000:");

   scanf("%f", &atual);

   if (atual > anterior)

       soma = soma + atual;

   anterior = atual;

}

while ( atual > anterior ); 

printf("\nA soma da sequencia estritamente crescente eh: %d", &soma);

 

 

Exercício: some e imprima a soma de números entre -1000 e 1000 de uma sequencia crescente até que a soma dos dois últimos termos seja igual ao dobro do termo atual. Suponha que o usuário só entrará com números em sequência crescente.

Palavras-chave: do ... while, laço, laço do ... while, laço while, while

Postado por Renato Callado Borges em C/C++ | 1 comentário

Outubro 17, 2007

user icon

Detalhe: o laço while nada mais é que um laço for sem a intrução de inicialização e sem a instrução de incremento. Ou seja, todo laço for pode ser convertido em um laço while com o seguinte formato:

 

instrução de inicialização;

while ( condição de término )

{

/* Instruções */

instrução de incremento;

}

 

Por outro lado, todo laço while pode ser escrito como um laço for da seguinte maneira:

 

for ( ; condição de execução; )

{

/* Instruções */

}

 

Quando usar while e quando usar for?

Isso pode ser decidido com o critério de utilizar o laço que tornará o código mais legível. Se um programador irá utilizar uma variável de controle que será incrementada, é mais razoável utilizar um laço for, pois dessa maneira um outro programador que ler seu código identificará imediatamente aonde estão e quais são as instruções de inicialização e incremento. Por outro lado, caso o programador não pretenda utilizar uma variável de controle, é mais legível utilizar um laço while, pois não haverão campos em branco (brancos como no exemplo acima).

Caso o programador queira utilizar o recurso de um bloco de instruções ser executado ao menos uma vez necessariamente, ele deve utilizar a instrução do ... while.

Palavras-chave: laço while, while

Postado por Renato Callado Borges em C/C++ | 0 comentário

Outubro 24, 2007

user icon

Bem-vindo(a)!

 

Estou escrevendo esta série de mensagens para que exista no Stoa um registro em português e totalmente livre ("as in free speech") sobre programação em C/C++.

 

Eu programo amadoristicamente em C++ há cerca de 15 anos, e, tal como muitos programadores, aprendi diretamente o C++, deixando o C "para depois". Por isso eu escrevo que este material é sobre C/C++: o intuito é que seja documentada especialmente a linguagem C, mas como eu conheço melhor a linguagem C++, pode acontecer de eu cometer algum deslize e escrever algo em C++ achando que funciona em C mas na verdade não funciona. Então fique atento, teste tudo e tenha em mente que livros como o de Kernighan e Ritchie é que são as referências canônicas para C.

 

Antes de mais nada, me desculpem os que esperam acompanhar estas mensagens "semana a semana" como um curso, mas eu não tenho como estruturar um curso de C/C++ e seguir esse planejamento ao pé da letra. O que irei fazer é publicar a cada semana uma mensagem sobre algum aspecto da programação em C/C++, tentando ir mais ou menos dos aspectos mais básicos para os mais avançados. Entretanto, como o objetivo é criar um material de referência, mesmo no começo da redação do material, que será sobre a sintaxe de C/C++, certos usos mais complicados da sintaxe serão apresentados, pois futuramente alguém que queira se informar sobre um uso complicado de certa parte da linguagem irá consultar as mensagens sobre essa parte da linguagem - de outra forma seria um horror procurar a informação necessária.

 

Numa introdução a programação, geralmente há uma seção inicial sobre a história do computador, e sobre a história da linguagem a ser aprendida. Irei poupá-los desse intróito: vamos direto pôr as mãos na massa.

 

Para escrever programas em C/C++, tudo o que é necessário é papel e caneta. Entretanto, para que esses programas se transformem em software efetivamente "rodado" num computador, é necessário que esse programa seja escrito de forma digitalizada e que esse arquivo de texto com o código do programa (chamado código-fonte) seja enviado para um programa chamado compilador, que faz a tradução de um arquivo texto (o código-fonte) para um arquivo executável (seu software).

 

Na verdade, a coisa pode ser ligeiramente mais complicada: o código-fonte pode se "esparramar" em diversos arquivos de texto, e o executável final pode também ser um conjunto de arquivos executáveis ou não, de acordo com as especificações da chamada ao compilador. Entretanto, até que abordemos neste curso como compilar programas em C/C++ de maneira complexa, uma introdução simplificada será suficiente.

 

Como dito anteriormente, para fazer um programa é necessário escreve-lo numa linguagem de programação, no nosso caso em C, utilizando apenas expressões válidas nessa linguagem. Quais expressões são válidas será o tema de toda a primeira parte do curso: hoje veremos apenas como compilar um programa, que será uma atividade que você deverá realizar muitas e muitas vezes durante seu aprendizado de C.

 

Infelizmente, para cada compilador a maneira de compilar é diferente, e portanto seria impraticável explicar como se compila utilizando cada compilador existente (aliás, eu nem sei isso). Existem basicamente dois tipos de compiladores: os que são de "linha de comando", cujo principal exemplar é o GCC, e os de "IDE" (Integrated Development Environment - Ambiente Integrado de Desenvolvimento). Neste material, utilizaremos o GCC, e esperamos que você faça o mesmo, pelas seguintes razões:

 

O GCC é livre e é o padrão de facto da indústria de software.

O GCC é um compilador de muitas linguagens, o que significa que aprendendo a mexer com ele você já terá na manga um trunfo quando for aprender algumas outras linguagens. Além disso, o GCC é livre.

O GCC está disponível para praticamente qualquer computador, desde que esse computador possa rodar o linux, seja como sistema operacional seja como aplicativo (por exemplo, o Cygwin é um linux que roda dentro do Windows; você pode usar o GCC dentro do Cygwin, dentro do Windows). Isso sem contar que o GCC é livre.

E uma última grande razão: o GCC é software livre!

 

Pode ser encontrada a documentação do GCC no site da Gnu, afinal GCC quer dizer "Gnu Compiler Collection", ou seja, "Coleção de Compiladores Gnu". Recomendo que seja ao menos dada uma olhadela no manual do GCC, que pode ser obtida com o comando man no seu prompt de commando:

 

callado@tlaloc ~ $ man gcc

 

Para quem quer se aventurar com algum "outro" compilador, leia o manual e a documentação desse compilador. Para quem usa Windows, uma boa alternativa é utilizar o DJGPP, que é uma versão do GCC para Windows, mas que não é mantida pela Gnu.

 

Mão na massa: Abra um editor de textos e digite o texto abaixo:

 

#include<stdio.h>

 

int main() {

printf("\nOla, mundo da programacao!!!\n");

return 0; }

 

Salve o texto sem formatação, isto é, o arquivo deve ser de "texto puro", não podendo ser arquivo "do Word" nem nada parecido. Tampouco utilize acentos ou cedilhas. No Windows, um arquivo do Notepad serviria, mas depois você deverá eliminar a extensão ".txt" do arquivo. No linux, o Emacs salva em formato texto. Salve o arquivo com o nome "intro.c".

 

Abra sua linha de comando e digite "gcc -o intro intro.c":

 

callado@tlaloc ~ $ gcc -o into intro.c

 

E finalmente digite "./intro":

 

callado@tlaloc ~ $ ./intro

Ola, mundo da programacao!!!

No windows, você deve abrir uma janela de DOS e digitar o nome do programa sem o "./", ou seja, apenas "intro".

 

Se tudo deu certo, parabéns! Você acaba de compilar seu primeiro programa em C!

Postado por Renato Callado Borges em C/C++ | 1 comentário

Outubro 31, 2007

user icon

Retomemos o exemplo da parte 1 desta introdução:

 

1: #include<stdio.h>

2:

3: int main() {

4:         printf("\nOla, mundo da programacao!!!\n");

5:         return 0; }

6:

 

Este exemplo é típico das introduções à programação em C/C++, pois é um dos menores programas que é possível fazer nessa linguagem, e portanto serve como paradigma de qual é a estrutura que tem de estar necessariamente presente em um código-fonte de um programa em C.

 

As linhas do programa foram numeradas para facilitar o comentário sobre elas, que é o que será feito agora. Num código fonte de C para ser realmente compilado, não se deve numerar as linhas.

 

Na linha 1, o comando que é dado é um comando de pré-processador que ordena ao compilador que inclua, naquele ponto do código-fonte, todo o conteúdo do arquivo entre os símbolos < e >. Em outras palavras, é como se tivessemos aberto o arquivo "stdio.h" em nosso editor de textos e copiado e colado todo o seu conteúdo em nosso arquivo de código fonte.

 

Ora, portanto esse exemplo "mínimo" pode ser bem substancial, a depender do tamanho de "stdio.h"! Isso serve de aviso aos iniciantes: em programação muitas vezes são usados comandos como esse "include" (que, em português seria traduzido como "incluir") que com uma única linha "incham" o nosso programa com muitas e muitas páginas de código.

 

Mas por que incluir um outro arquivo?

A grande, na verdade a gigantesca vantagem de incluir um outro arquivo é o chamado "reuso" de código fonte. "Reuso" significa "utilizar novamente", ou seja, através da inclusão de outros arquivos em nosso código fonte, podemos utilizar comandos criados em outro momento, possivelmente por outras pessoas. É uma espécie de divisão do trabalho: João escreve as funções que lidam, por exemplo, com palavras, Mário utiliza essas funções escritas por João para escrever funções que lidam com frases, Zeca utiliza essas funções de João e de Mário para escrever funções que lidam com parágrafos e finalmente eu utilizo as funções de João, Mário e de Zeca para escrever um programa que lida com um texto de vários parágrafos, frases e palavras.

 

Isso que acabamos de ver são chamadas funções de biblioteca. Em inglês isso é chamado de library functions. A idéia por trás desse nome é que as funções seriam pequenos pedaços de código fonte que são armazenados como os livros de uma biblioteca, e que quando um programador precisa utilizar um desses livros (ou seja, uma dessas funções), ele "pede emprestado" esse livro da biblioteca e o utiliza.

 

Por exemplo, digamos que "motor" seja o nome de uma biblioteca que armazena as funções que efetuam comandos sobre um motor de um carrinho ligado ao computador por meio de rádio. Suas funções seriam "ligar", "acelerar", que pode ser negativa ou positiva e "desligar". Um programador poderá utilizar essa biblioteca de funções para criar os comandos de um carrinho mais inteligente, que por exemplo percorra uma pista de corrida predefinida, digamos um quadrado. Nesse caso, o programa será uma série de chamadas às funções da biblioteca, mais ou menos assim:

 

ligar

acelerar +10

acelerar -9

acelerar +9

acelerar -9

acelerar +9

acelerar -9

acelerar +9

acelerar -9

acelerar +9

acelerar -10 

desligar

 

É necessário desacelerar para virar nas curvas; acelera-se para percorrer as retas (os lados do quadrado) o mais rápido possível. Este programa não faria muito sentido se não houver uma forma de controlar a direção do carrinho, por exemplo usando a biblioteca "direcao", que exporta as funções "direita" e "esquerda". Aí nosso exemplo seria

 

ligar

acelerar +10

acelerar -9

esquerda

acelerar +9

acelerar -9

esquerda

acelerar +9

acelerar -9

esquerda

acelerar +9

acelerar -9

esquerda

acelerar +9

acelerar -10 

desligar

 

Para que o exemplo seja plenamente compreensível, seria necessário controlar quando o carrinho "vira à esquerda". Isto ocorreria após andar um espaço predefinido, por exemplo, o lado da pista, que seria, digamos, 10 cm. Isto poderia ser feito com a função "odômetro" da biblioteca "painel". Aí nosso exemplo seria:

 

ligar

acelerar +10

andar até odômetro = 5 cm

acelerar -9

esquerda

acelerar +9

andar até odômetro = 15 cm

acelerar -9

esquerda

acelerar +9

andar até odômetro = 25 cm

acelerar -9

esquerda

acelerar +9

andar até odômetro = 35 cm

acelerar -9

esquerda

acelerar +9

andar até odômetro = 40 cm

acelerar -10

desligar

 

Apenas para irmos nos acostumando com a sintaxe de C, aqui está o código fonte desse exemplo em C:

 

#include”motor.h”

#include”direcao.h”

#include”painel.h”

 

int main() {

            odometro odo;

 

ligar();

acelerar(10);

while(odo < 5);

acelerar(-9);

esquerda();

acelerar(9);

while(odo < 15);

acelerar(-9);

esquerda();

acelerar(9);

while(odo < 25);

acelerar(-9);

esquerda();

acelerar(9);

while(odo < 35);

acelerar(-9);

esquerda();

acelerar(9);

while(odo < 40);

acelerar(-10);

desligar();

return 0; }

 

Não se preocupe em entender completamente cada detalhe desse código; o importante é perceber que existe uma modularidade na programação em C: pequenos trechos de código são copiados de outros lugares e “justapostos” para produzir um novo programa.

 

Portanto, o uso de bibliotecas em um programa C faz com que a tarefa de programação se assemelhe à eletrônica, ou à mecânica, no aspecto de que o programador utiliza peças "prontas", feitas por outras pessoas, e combina essas peças para produzir um software novo, da mesma maneira que um engenheiro ou técnico eletrônico cria novos aparelhos utilizando componentes comercialmente disponíveis, ou um mecânico cria aparelhos com motores e engrenagens compradas prontas.

 

Quanto a esse último quesito, o da comercialização das peças, é importante fazer uma distinção entre o software comercial "normal" e o software livre: as bibliotecas comerciais são compráveis e só podem ser utilizadas legalmente caso o programador pague sua "licença de uso". Por exemplo, para utilizar uma biblioteca de sintetização de voz comercial é necessário pagar uma taxa para os detentores do direito autoral sobre esse software. Mas no caso de software livre, essa taxa de comercialização é opcional. Note bem: opcional. E quem determina a opção é o detentor dos direitos autorais, também. Isso significa que uma biblioteca de software livre pode exigir pagamento para ser utilizada, também. Afinal de contas, para produzir a biblioteca é necessário pagar programadores, então é razoável que quem crie bibliotecas como negócio, mesmo que o faça como software livre, o faça mediante pagamento.

 

Então qual a diferença entre uma biblioteca livre e uma comercial? A diferença é que a biblioteca comercial não oferece seu código fonte à consulta enquanto que a biblioteca livre permite a leitura e modificação de seu código fonte, desde que quaisquer modificações sejam disponibilizadas como software livre.

 

Se software fosse carro, e bibliotecas fossem motores, é como se as bibliotecas comerciais fossem motores em que é proibido abrir o capô e fuçar no motor; só o fabricante pode consertar o motor se ele quebrar. O software livre é como o carro que conhecemos: podemos abrir e mexer ou pagar a alguém que entenda de mecânica para que faça isso por nós. Isso significa que o software livre é o único software que tem chance de sobreviver por um longo tempo: porque mesmo que a empresa que o criou venha à falência, poderemos utilizar um programador para que faça a manutenção e até mesmo a melhoria desse software para nós.

 

Além disso, alguns softwares livres são também esforços de colaboração internacional, como, por exemplo, os software da Gnu. Por serem feitos colaborativamente, esses softwares são melhorados continuamente: todos os dias, para não dizer que muitas vezes todas as horas, é lançada uma nova versão de algum software Gnu. Isto significa robustez, segurança, confiabilidade: nenhum software comercial em toda a história da computação foi desenvolvido com tanta qualidade em tão pouco tempo.

 

Bom, chega de proselitismo. No próximo texto eu explico outras linhas do exemplo inicial.

Palavras-chave: Bibliotecas de Funções, Introdução à Programação, Introdução ao C

Postado por Renato Callado Borges em C/C++ | 0 comentário