Ir para o conteúdo

Bases de Programação em C

Importante: Este artigo encontra-se desactualizado. Embora os princípios estejam correctos (a linguagem em si não mudou), existem práticas incentivadas por este artigo que são questionáveis.

Ideia: Eliminar a secção sobre o Dev-C++ e utilizar um IDE mais moderno como Code::Blocks, CodeLite, Eclipse CDT

O que é a programação?

A programação é a arte da criação (ou alteração) de um programa de computador, um conjunto concreto de instruções para um computador desempenhar. Computador, neste contexto, significa qualquer coisa que tenha capacidade de processamento. O programa é escrito numa linguagem de programação, embora seja possível, com alguma dificuldade, escrevê-lo directamente em linguagem de máquina. Diferentes partes de um programa podem ser escritas em diferentes linguagens.

Diferentes linguagens de programação funcionam de diferentes modos. Por esse motivo, os programadores podem criar programas muito diferentes para diferentes linguagens; muito embora, teoricamente, a maioria das linguagens possa ser usada para criar qualquer programa. Para mais informações sobre estes métodos, veja Linguagem de programação.

Software é um nome colectivo para programas de computadores e dados.

Há várias décadas que se debate ferozmente sobre se a programação é mais semelhante a uma arte (Donald Knuth), a uma ciência, à Matemática (Edsger Dijkstra), à engenharia (David Parnas), ou se é um campo completamente novo.

O que é um algoritmo?

Um algoritmo é, num certo sentido, um programa abstracto - dizendo de outra forma, um programa é um algoritmo concretizado. No entanto, os programas são, à excepção dos menores, visualizados mais facilmente como uma colecção de algoritmos menores combinados de um modo único - da mesma forma que uma casa é construída a partir de componentes.

Dessa forma, um algoritmo é uma descrição de como um computador pode ser levado a executar uma operação simples e específica, como, por exemplo, uma ordenação. Um programa, por outro lado, é uma entidade que na verdade implementa uma ou mais operações de forma que seja útil para as pessoas.

História

C é uma linguagem de programação estruturada e padronizada criada na década de 1970 por Dennis Ritchie e Ken Thompson para ser usada no sistema operativo UNIX. Desde então espalhou-se por muitos outros sistemas operativos, e tornou-se uma das linguagens de programação mais usadas. C tem como ponto-forte a sua eficiência e é a linguagem de programação de preferência para o desenvolvimento de software de sistemas, apesar de também ser usada para desenvolver aplicações. É também muito usada no ensino de ciências da computação, mesmo não tendo sido projectada para novatos.

Em que consiste?

C é uma linguagem de programação relativamente minimalista que opera bem próximo do hardware, e é mais semelhante à linguagem assembly do que as restantes linguagens. Certamente, C é por vezes referida como uma "assembly portátil". O código de C pode ser compilado para ser rodado em quase todos os computadores/sistemas operativos. C é típicamente chamada de uma linguagem de baixo nível ou de nível médio, indicando assim o quanto perto ela opera com o hardware. Essa propriedade não foi acidental; A Linguagem C foi criada com um objectivo em mente: facilitar a criação de programas extensos com menos erros recorrendo ao paradigma da programação algorítmica ou procedimental, mas sem nunca sobrecarregar o autor do compilador de C, cujo trabalho complica-se ao ter de realizar as características complexas da linguagem.

Vantagens

Para este fim, a linguagem C possui as seguintes características:

  • Uma linguagem nuclear extremamente simples, com funcionalidades não essenciais, tais como funções matemáticas ou manuseamento de ficheiros (arquivos), fornecida por um conjunto de bibliotecas de rotinas padronizadas.
  • A focalização no paradigma de programação procedimental
  • Um sistema de tipos simples que evita várias operações que não fazem sentido
  • Uso de uma linguagem de pré-processamento, o pré-processador de C, para tarefas tais como a definição de macros e a inclusão de múltiplos ficheiros de código-fonte.
  • Um acesso de baixo-nível à memória do computador, através do uso de ponteiros.
  • Parâmetros que são sempre passados por valor para as funções e nunca por referência (É possível simular a passagem por referência com o uso de ponteiros).
  • Definição do alcance lexical de variáveis
  • Estruturas de variáveis, (structs), que permitem que dados relacionados sejam combinados e manipulados como um todo

Desvantagens

Algumas características úteis que faltam à linguagem C, mas que são encontradas em outras linguagens incluem:

  • Segurança de tipo
  • Colecta automática de lixo
  • Classes ou objectos com comportamento (ver programação orientada por objectos)
  • Um sistema avançado de sistema de tipos
  • Funções aninhadas
  • Programação genérica
  • Sobrecarga de operadores
  • Meta-programação
  • Apoio nativo de multithreading e networking

Apesar da lista de características úteis que C não possui ser longa, isso não tem sido um impedimento à sua aceitação, pois isso permite que novos compiladores de C sejam escritos rapidamente para novas plataformas, e também permite que o programador permaneça sempre em controlo do que o programa está a fazer. Isto é o que por várias vezes permite o código de C correr de uma forma mais eficiente que muitas outras linguagens. Tipicamente, só código de assembly "afinado à mão" é que corre mais rapidamente, pois possui um controle completo da máquina, mas avanços na área de compiladores, juntamente com uma nova complexidade nos processadores modernos, permitiram que a diferença tenha sido rapidamente eliminada. Uma consequência da aceitação geral da linguagem C é que frequentemente os compiladores, bibliotecas e até intérpretes de outras linguagens de nível maior sejam eles próprios implementados em C.

\[Adaptado do wikipedia.\]

Para que serve este tutorial e a quem é dirigido?

Serve para ficar com uma ideia muito básica de como programar na linguagem C, ficando com noções suficientes para poder criar programas também eles básicos nesta linguagem.

Obviamente que quem já sabe programar em C, não vai aprender aqui nada. Eventualmente quem sabe programar noutras linguagens, poderá comparar as diferenças de sintaxe entre esta linguagem e as suas conhecidas. No entanto, este tutorial dirigi-se mais a quem nunca teve programação, mas tem curiosidade e ansia de aprender alguma coisa nesta linguagem.

Onde programar?

Como já foi dito anteriormente, usa-se um compilador. Poderão fazer o download aqui.

Info: Source code : Delphi Source code of Dev-C++ is available for free under the GNU General Public License (GPL)
Authors : Colin Laplace : Main IDE Development; Hongli Lai: IDE updates, splash screen and icons
Mingw: Mumit Khan, Jan Jaap van der Heidjen, Colin Hendrix and GNU coders.
Status : Free Software (under the GNU General Public License)

Instalação do Dev-C++4

  1. Descompactar usando winzip ou winrar. Se não tiveres um destes programas descarrega daqui o winrar. (O winrar tem instalação simples, basta fazer "next"...)
  2. Correr o ficheiro 'setup'.
  3. Na janela de intalação proceder do seguinte modo: clicar 'yes' -> escolher 'typical' e 'next'. (Poderão alterar o directório para onde será instalado o programa, usando o 'browse'.)

Configuração inicial do programa

Possivelmente o programa não virá com 'default' as bibliotecas que se pretendem usar em C, portanto ter-se-á que alterar. O que deverão fazer:

  1. File
  2. New source file
  3. Se aparecer o seguinte, não terão que alterar nada, e podem passar à frente desta parte do tutorial. Código:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
       return 0;
    }
    
  4. Não aparecendo o código anterior deverão ir: Options -> Environment options
  5. Misc.
  6. Façam copy do código que em 3 mostrei e colem na parte do 'default code...'
  7. OK

Os botões mais usados (como usar o programa)

Embora o programa tenha muitos 'botões', vou apenas descrever os mais importantes e que se usam com maior regularidade. São apenas 3 botões fundamentais:

  1. O que está dentro do rectângulo vermelho serve para abrir um novo "documento de código" - "new source file". (File - New source file - ctrl+U)
  2. O que está dentro do rectângulo verde serve para gravar. Antes de correrem o vosso programa, deverão gravá-lo, pois só o gravado pode ser corrido com o compilador fechado (mais explicações a seguir sobre os ficheiros). (File -> Save unit - ctrl+S)
  3. O que está dentro do rectângulo azul serve para correr o vosso programa. (Execute -> Compile and run - ctrl+F10)

Os ficheiros usados pelo programa:

Sempre que abrem um novo source file e o gravam, no directório que escolheram surgem dois ficheiros.

O primeiro é o código do vosso programa, o qual para ser visto não precisa de ser aberto pelo compilador, mas, por exemplo, pelo bloco de notas, fazendo para tal “abrir com…”. O segundo executa o vosso programa. Deste modo, quando fazem um programa e o querem divulgar, obviamente que apenas divulgam o segundo ficheiro.

O que significa o código inicial?

Relembrando o código inicial, que aparecerá sempre, desde que tenham procedido como sugeri na configuração do programa, escrito em cima.

#include <stdio.h>
#include <stdlib.h>

int main()
{
  return 0;
}

Os includes são as bibliotecas de C a serem usadas pelo compilador, ou seja, para este reconhecer a sintaxe usada. Devido a isto, estes têm que aparecer antes de tudo (excepto de comentários, que mais à frente explicarei o que são e como fazer).

O int main () { dá início à função principal, principal porque é aquela que gere todas as outras que possam ser criadas como mais à frente será explicado (esta função tem que ser única num programa!). Após o { deverá estar o vosso programa. No caso, a instrução que se segue é return 0, que qual serve para concluir o programa. Não esquecer o } que serve para fechar a função int main().

Noções básicas para começar a programar

Vamos então à sintaxe propriamente dita. Todas as instruções são seguidas de ;, excepto casos que serão referidos mais à frente.

Muitas vezes é útil escrever no compilador o que se está a fazer, para que mais tarde se perceba o que se fez. Para o fazer tem que se usar comentários, nos quais o programador escreve informações, as quais apenas poderão ser visualizadas pelo mesmo, no source code e nunca no programa. Estes comentários podem ser feitos em qualquer lado, e fazem-se do seguinte modo:

//comentário
ou
/*comentário*/

Em que no primeiro comentário, o compilador reconhece o comentário até ao fim da linha, enquanto que no segundo, reconhece como comentário tudo o que estiver entre /* e */, podendo o utilizador usar várias linhas se assim o pretender. Como se pode depreender, é preferível usar a segunda sintaxe, pois a possibilidade de errar será supostamente menor. Tenham em atenção as cores, estão lá para facilitar a visualização de potenciais erros, quer nesta, quer noutras instruções que seguidamente apresentarei.

Além de os comentários serem de elevado proveito para a compreensão futura do programa, também permitem ao utilizador “comentar” certas partes do programa, para depois o compilador não correr essas mesmas partes. Este procedimento é normalmente usado para encontrar erros no código.

Exemplos de código

A partir daqui opto por introduzir exemplos de programas simples, explicando-os devidamente. A base da programação são métodos numéricos, lógica e álgebra, como tal os dados de entrada são geralmente números, bem como os de saída. Associados a estes podem estar caracteres.

O que poderemos então fazer com isto? Começando por algo muito simples (e totalmente inútil).

(Para poupar espaço, vou omitir a parte do "código inicial", dando-vos a garantia que todo o código que se segue deverá ser colocado após o int main() { e antes do return 0;.)

Exemplo nº 1

printf("Que porcaria de tutorial!\n");

Como podem confirmar, ao colocar este código no compilador, e ao correrem, aparecer-vos-á a mensagem que está entre parentesis, sem o \n. Sugiro que experimentem a retirá-lo. O que sucede é que o compilador não muda de linha, ou seja, estes chamados caracteres especiais servem para mudar de linha. Existem mais, como é o caso:

Caractere Significado
\b retrocesso
\r enter
\t tabulação horizontal
\v tabulação vertical
\? ponto de interrogação
\' plica
\" aspas
%% caracter de percentagem
\a ou \7 bell
\\ barra

Como podem reparar, para colocar certos caracteres é preciso ter um cuidado especial, isto deve-se ao facto de estes estarem associados a certas instruções, como é o caso de %, que como será visto mais à frente, tem uma função especial. (É possível que alguns não funcionem em certos compiladores, nomeadamente no que eu propus que usassem.)

Se não perceberam para que servia algum, o melhor será experimentarem e verem.

Concluindo este exemplo, temos que a instrução printf serve para colocar mensagens para o utilizador que usa o programa. Normalmente é usado para pedir input ao utilizador e para guiar este na utilização do programa, como compreenderão com os seguintes exemplos. O modo de o usar é escrever: printf("mensagem a mostrar no ecrã ");, não esquecendo o ponto e vírgula no final da instrução. Quero ainda referir, que o uso de acentos, ou outros caracteres, não é recomendado, uma vez que o compilador não os “decifra” bem, como podem experimentar.

Recomendo ainda que de todos os caracteres especiais apresentados em cima, tenham particular interesse no que usei no exemplo 1, visto que para uma mais fácil leitura do programa será importante que se usem oportunas mudanças de linha.

Exemplo nº 2

int a;
printf("Coloca um valor inteiro para a variavel 'a'.\n");
scanf("%d", &a);
printf("O valor que colocou em 'a' foi %d.\n",a);

Comecem por experimentar a usar o programa. Primeiro este pede que se coloque um valor inteiro para a variável. Depois de colocado o número, deve-se carregar no ‘enter’ para que o programa receba o número. De seguida este apresenta-nos o número colocado.

Passando para o código, temos a instrução int a; que serve para indicarmos ao compilador que existe uma variável a. Este procedimento é fundamental: no princípio do nosso código devemos sempre (salvo excepções que agora não interessam) apresentar as variáveis. Primeiro temos que dizer de que tipo é essa variável. Neste caso era um inteiro, daí usar o int. Depois faz-se espaço e coloca-se um nome para a nossa variável. Este nome não pode começar por algarismos, nem conter certos caracteres, que creio não valer a pena referir quais são especificamente, deixo apenas o apelo para que usem letras (mas não o ç), números e o _ que dá sempre jeito para dividir palavras, caso seja necessário (notar que não se pode usar o espaço). Acrescento ainda que tenham cuidado com o nome que dão, pois existem nomes que estão associados a certas instruções e que portanto não devem ser usados.

Além do int para inteiros, tem-se outro tipo de variáveis:

  • char para caracteres
  • double para números reais
  • float para números reais, mas com uma escala menor que o double (gasta menos bits, mas está mais limitado).

Seguidamente tem-se um printf que como explicara anteriormente serve, neste caso, para pedir ao utilizador para ele colocar o número. Podem achar isto um pouco estúpido, na medida em que quem usa o programa poderão ser vocês, logo sabem o que colocaram no código e não precisam de instruções, mas a verdade é que os programas aumentam de tamanho e estas instruções são cruciais.

Apresenta-se então uma instrução nova: scanf, serve para o utilizador colocar a partir do teclado um número/caracter para a variável que está dentro deste scanf. Passo então a explicar esta sintaxe: depois de escrever scanf abre-se parêntesis e coloca-se de imediato entre aspas a simbologia de programação associada à variável. Ou seja, sendo neste caso um inteiro (int), é %d, se fosse um caracter (char) seria %c, se fosse double teríamos %lf e um float seria %f. Faz-se vírgula, para de seguida colocar & seguido do nome da variável, concluindo com o fechar de parêntesis e o inevitável ponto e vírgula. (O & nem sempre é necessário, pois por vezes trabalha-se com ponteiros, os quais são muito úteis quando se criam funções, no entanto, eles não serão tratados neste tutorial, quem quiser saber o que são e para que servem, perguntem depois, ou pesquisem nos links que indico no final do tutorial.)

Por fim, mais um printf, tendo este a particularidade de ser capaz de apresentar o valor de variáveis. Para se fazer isto basta usar a tal simbologia que indica o tipo de variável, sendo que o compilador ao correr o programa, vai colocar no sítio onde metemos o (neste caso) %d o valor da variável que esteja após a mensagem, mas dentro do printf. Para separar a mensagem da variável, tem que se usar uma vírgula. Caso se pretenda ter várias variáveis, basta colocá-las todas pela ordem que se desejar a serem apresentadas na mensagem. Por exemplo:

int a=1;
double b=1.2;
char c='L';
float d=1.2;
printf("A:%d.\nB:%lf.\nC:%c.\nD:%g.\n",a,b,c,d);

Tenham em atenção no facto de que para apresentar números decimais se usa o ponto e não a vírgula, bem como no facto de que enquanto num número, este poderá ter quantos algarismos se desejar, que será sempre apenas um número, já no caso de caracteres o mesmo não acontece. Um conjunto de caracteres será uma string, as quais serão abordadas mais à frente. Ter ainda em atenção no modo em como eu aqui fiz a declaração das variáveis, usando apenas o identificador igual (=), tendo especial atenção em que no caso de caracteres não se pode esquecer de colocar estas entre pelicas. Este tipo de declaração é muito usual e dá jeito quando não se pretende que o utilizador dê o valor para a variável, mas sim que esta tenha um valor independente do procedimento que se der ao programa, tendo o cuidado de não repetir nomes de variáveis, nem de usar variáveis já definidas, em scanf, embora tal procedimento não seja errado.

Notar que fazer int a=1; ou int a; <mudar de linha> a=1; é exactamente a mesma coisa, podendo talvez por vezes ser preferível usar a segunda possibilidade na medida em que o a=1; poderá ser colocado em qualquer parte do programa, o que poderá em certos casos ser uma mais-valia. (Nota: o <mudar de linha> não é obrigatório, mas muito aconselhável, na medida em que se se colocar o código todo seguido, a sua leitura será grandemente dificultada.)

Exemplo nº 3

int a;
double b,c;
printf("Introduza um valor para 'a'.\n");
scanf("%d",&a);
printf("Introduza um valor para 'b'.\n");
scanf("%lf",&b);
printf("O valor da soma de 'a' com 'b' e' %lf.\n",a+b);
c=a+b;
printf("O valor de 'c' e' %lf.\n",c);

Como podem testar, este programa pede dois números ao utilizador e depois soma-os, mostrando também que o que tem na variável c é o resultado dessa soma.

Peço primeiro atenção para a inicialização das variáveis, em que digo que b e c são do tipo double, sem que para isso tenha que escrever duas vezes double, ou seja, pode-se agrupar todas as variáveis que se tenham do mesmo tipo, separadas por vírgulas. O outro procedimento (double b; <mudar de linha> double c) é igualmente correcto, mas convém sempre economizar espaço, tempo e trabalho.

Como depois podem constatar, é possível colocar uma operação dentro do próprio printf, embora eu não recomende tal procedimento.

Realço ainda outra questão: sendo b do tipo double, mas a do tipo int, convém que o resultado da soma venha em double, como penso ser evidente, embora seja um erro algo frequente, que não se tenha o cuidado de verificar se a variável resultado está em consonância com o tipo de variáveis das quais depende.

Além da operação soma (e atribuição =), temos também:

  • -Subtracção
  • * Multiplicação
  • / Divisão (inteira)
  • % Resto da divisão
  • ++ Incremento
  • -- Decremento

As últimas duas é possível que não percebam para que servem, mas são a mesma coisa que ter:

  • x = x + 1;
  • x++;

De modo similar para o decremento.

Como já podem ter reparado, eu fiz sempre a atribuição de uma variável do lado esquerdo, para algo que está do lado direito, ou seja, é correcto fazer: a = 2 + 3;, mas incorrecto fazer 2 + 3 = a;.

Quanto ao que fiz em cima, é muito usual fazê-lo em ciclos, como poderão ver mais à frente. Refiro-me ao incremento, em que se soma uma unidade à variável x.

Referi-me à divisão, como sendo divisão inteira, isto porque se fizerem a = 3 / 2;, o resultado não será 1.5, mas 1, ou seja, é a parte inteira do resultado. Caso se pretenda o número real, ter-se-á que fazer a = (double) 3 / 2;. Notar que o % usa-se do seguinte modo: d = 3 % 2;. O resultado de d será 1, isto porque se fizermos a divisão de 3 por 2, o resto inteiro será 1.

Como na Matemática, também aqui existe a precedência de operadores: parêntesis sobrepõe-se a tudo, segue-se a multiplicação, divisão e resto da divisão, acabando na soma e subtracção, ou seja, é exactamente como a Matemática, a diferença surge nos operadores incremento e decremento. Vejamos o próximo exemplo:

Exemplo nº 4

int a,b;
double c,d;

a=2;
b=6;
c=1.5;
d=--a*b/c+a*c+++a--;
printf("%lf\n %lf\n %d\n",d,c,a);

Se correrem, verão que d será igual a 6.5, c igual a 2.5 e a igual a 0. Ora isto parece não fazer sentido, pois se logo no princípio é subtraído a a uma unidade, este ao multiplicar por c deveria ser neutro, mas tal não acontece, embora ao operar sobre a divisão de b por c, já toma o valor de 1. Ou seja, o que se passa é, começando pelo fim, a -- só é feito após o ciclo, pois caso se o retirarmos, podem ver que o valor de d passa para 5.5, ou seja, o a valia 1 e não zero, ou seja, o decremento é só feito depois da soma com tudo o resto. Antes disso, sabemos pelo valor que toma o c e d, que a já era 1, ou seja, o decremento --a já tinha sido feito, assim podemos concluir de tudo isto que o decremento/incremento feitos atrás da variável (--a) têm precedência em relação à multiplicação, enquanto que o decremento/incremento feitos a seguir à variável são os últimos a serem feitos, mesmo após a adição/subtracção.

Quem não percebeu, que tente exemplos no compilador, que rapidamente irá compreender.

Para outras operações que se desejem, como a raiz, expoente, logaritmo, etc., deverá ser incluída uma biblioteca que contenha essas funções (por exemplo, #include <math.h>, quem estiver interessado nisso que procure nos links que estão no final do tutorial).

Exemplo nº 5 – Instruções Condicionais

int a,b;
char i;

printf("Quer somar ou subtrair dois numeros?\nSe quer somar, clique 1 e 'enter'.\nSe quer subtrair, clique outra tecla que nao 1 e 'enter'.\n");
scanf("%c",&i);
if (i=='1')
{
  printf("Coloque dois numeros inteiros.\n");
  scanf("%d", &a);
  scanf("%d", &b);
  printf("A soma de %d com %d e' %d.\n",a,b,a+b);
}
else
{
  printf("Coloque dois numeros inteiros.\n");
  scanf("%d", &a);
  scanf("%d", &b);
  printf("A subtraccao de %d com %d e' %d.\n",a,b,a-b);
}

O que podem fazer com este programa? Somar ou subtrair dois números, podendo escolher o que fazer. Ou seja, existe uma condição. Se o utilizador colocar 1, o programa irá seguir um certo rumo, se colocar outra coisa, irá seguir outro rumo. Para isto se tem lá o if, que como sabem significa “se”, ou seja, se o utilizador colocar 1 na variável i, irá seguir o rumo que está entre { }, se não fará o else que significa “senão”, ou seja, se i não é 1, então irá fazer o que se segue entre { }.

Por outras palavras, a sintaxe da condição é muito simples e intuitiva:

if (condição) /\*condição tem que estar entre parêntesis\*/
 { instruções }
else
 { instruções }

Notar que o else pode ser omitido, quando se pretenda que o programa não faça nada, caso a condição não se verifique.

Quanto à condição, temos ==, ou seja, significa que o que está de um lado é igual ao que está ao de outro, portanto nada tem a haver com a atribuição =, pois nesse caso estar-se-ia não a verificar uma condição, mas a criá-la, sendo sempre certa, portanto não esquecer que numa condição de igualdade não se usa =, mas sim ==.

Podemos ter outras condições, como:

  • > maior
  • < menor
  • >= maior ou igual
  • <= menor ou igual
  • != diferente

Exemplo nº 6 - switch

Além do if, temos também o switch, que serve para selecção múltipla, ou seja, para quando se quer colocar vários casos, e o uso do if se torna um pouco trabalhoso e espaçoso no programa. Vejamos então o próximo exemplo.

int a,b,c,i;
a=1;
b=2;
c=3;
printf("Se deseja somar 1 com 1, clique 1.\nSe deseja subtair 3 com 2, clique 2.\nSe deseja multiplicar 1 com 3, clique 3.\n");
scanf("%d",&i);
switch (i)
{
  case 1:
    c=a+a;
    printf("1+1=%d\n",c);
    break;
  case 2:
    a=c-b;
    printf("3-2=%d\n",a);
    break;
  case 3:
    b=a*c;
    printf("1*3=%d\n",b);
    break;
  default:
    printf("Ups, nao existe essa opcao.\n");
    break;
}

Como podem constatar, se fossem meter um if para cada caso, dava-vos mais trabalho, além de piorarem a leitura do programa. O modo de usar o switch também é intuitivo:

switch (variável a verificar) {
case /*caso*/ valor_que_a_variável_pode_tomar /*notar que se fosse um caracter necessitaria das pelicas*/
instruções /*aqui não é necessário o uso dos parêntesis { } */
break; /*serve para terminar o caso*/
(um todo outro conjunto de cases, e caso se queira: )
default: /*para todos os outros casos não incluídos nos anteriores, ou seja, como se fosse um ‘else’*/
instruções
break;
} /*fim do switch*/

O if é muito importante também para uma outra coisa: e se o utilizador se engana a colocar, no exemplo anterior um número, ou seja, por exemplo, em vez de um número coloca um caracter.

Ora, com o if poder-se-á verificar se o utilizador se enganou e mandá-lo recolocar o número, caso tal tenha acontecido, no entanto, como podem pensar, este tipo de procedimento não faria sentido, pois o utilizador poderia continuar a enganar-se e nós que fazemos o código, não saberíamos quantos if, precisaríamos, para isso serão de grande utilidade as condições repetitivas, ou seja, ciclos, que serão vistos de seguida.

Exemplo nº 7 – ciclos

int i,a;

a=1;
while(a){
  printf("Coloque o numero 1.\n");
  fflush(stdin);
  scanf("%d",&i);

  if (i==1)
    a=0;
}

Antes de mais, importa dizer que em programação, 1 significa verdadeiro e 0 falso.

Como sabem, while significa “enquanto”, portanto, enquanto uma certa condição, o ciclo que se segue será processado, ou não. Como podem depreender pelo que disse inicialmente e pelo código que apresento, while (verdadeiro) faz correr as instruções que o ciclo tem dentro dos { }. Dentro do while o que tenho é um printf que não levanta dúvidas, seguido de um fflush(stdin);. Não vou perder muito tempo a explicar o que isto é, digo-vos apenas que deve ser usado quando se dá a uma certa variável valores segundo ciclos, ou seja, serve para limpar a memória, pois se experimentarem a neste caso a retirarem isto e a correrem o código, se na primeira vez se não colocarem o 1, então não terão oportunidade de voltar a tentar, pois começará a aparecer sem parar a mensagem do printf, ou seja, o scanf é feito automaticamente com a memória do que foi colocado automaticamente, assim, se a memória for limpa em cada ciclo, o programa chega ao scanf e volta a precisar que o utilizador dê um novo valor para a variável i.

Seguidamente tenho um if, em que vai ver se o que foi colocado foi mesmo o 1 que se pretendia. Se foi, então será processada a instrução: a passará a ser igual a 0. Então, ao voltar ao while, a condição deixará de ser verdadeira, para ser falsa, logo o que está dentro do while não será corrido, e portanto o programa acabará, visto que não tem nada mais além do while.

Com este “artifício” (ou com algo similar), poderão verificar sempre se o que foi colocado pelo utilizador está correcto. Se não perceberam, não se preocupem, que utilizarei esse procedimento em exemplos posteriores.

Exemplo nº 8

Algo também muito usual, é querer fazer um ciclo que repita um dado número de vezes. Como poderão ver no seguinte exemplo:

int a,contador,c;
contador=0;
a=2;
printf("Vejam a tabuada do 2:\n");
while(contador<10)
{
  contador++;
  c=a*contador;
  printf("%d\n",c);
}

Como podem ver, o ciclo irá ser executado até que o contador tenha adquirido o número 10.

Exemplo nº 9

Um outro modo de fazer exactamente a mesma coisa, e que encurta espaço, é usar um ciclo for. No próximo exemplo mostro um programa um pouco mais complexo, e que engloba algumas das coisas que já referi que estes ciclos permitem fazer, além de um outro tipo de ciclo parecido com o while, que é o do ... while.

int a, contador, b;
do {
  printf("Introduza o numero positivo e menor que 100 para o qual pretende ver a tabuada.\n");
  fflush(stdin);
  scanf("%d",&a);
} while (a<=0 || a>=100);
printf("Tabuada do %d:\n",a);
for(contador=1; contador<11; contador++)
{
  b=contador*a;
  printf("%d\n",b);
}

Suponho que estejam a pensar: finalmente algo pode ser minimamente útil, a verdade é que com os conhecimentos que já têm, poderão já efectuar programas bem úteis, principalmente para quem trabalha com somatórios, os quais não passam de um ciclo como estes que tenham apresentado.

Mas voltando ao código, como podem comprovar, este programa começa por pedir um número entre 1 e 99, sendo que se não o colocarem, ele voltará a pedir até que lhe façam a vontade.

Se experimentarem a retirar a condição do while, verificam que se colocarem uma letra, o programa pegará num número “esquisito” e fará a tabuada desse. Ora isto deve-se ao código ASCII, no qual a cada caracter está associado um número. No fim de lerem este tutorial e de o testarem, sugiro (caso ainda tenham vontade) que pesquisem no Google por esse código e depois tentem fazer programas com base nesse código de modo a poderem manipular como desejarem os caracteres.

Ora, temos então aqui algo novo: do { instruções} while( condição || condição);. Este tipo de ciclo é muito semelhante ao while, tendo a particularidade de que a condição é apenas testada no fim das instruções serem corridas e não o contrário, o que implica que a primeira vez será sempre corrida, independentemente das condições. Na parte da condição está lá algo que me esquecera de referir logo nos ifs: podemos ter mais que uma condição, separadas por || (duas barras verticais) que significa “ou”, ou então separadas por && que significa “e”. Podem então questionar: neste caso era suposto termos ‘uma condição’ <e> ‘outra’ e não uma <ou> outra, como lá está. No entanto, como podem verificar, o ciclo será repetido se a condição for verdadeira, e não repetido quando for falso, deste modo, o que se pretende é que o utilizador coloque algo que satisfaça a negação da condição. (Para quem não percebeu, recomendo vivamente que estude um pouco de lógica, ou que me peça para a explicar em mais detalhe.)

Seguidamente o programa faz o mesmo que o do exemplo 8, com a diferença que em vez de se usar o while, usa-se for (para), o qual tem uma sintaxe um pouco mais complicada e menos intuitiva. Ora bem um for funciona do seguinte modo:

for (inicio; condição; incremento/decremento que altera a variável de início)
 { instruções }

Ou seja, um for é uma forma condensada de fazer o mesmo que se fazia com o while nas situações em que se usava um contador. Notar que no local da condição podemos ter várias, bem como no início podemos ter várias variáveis de início, as quais são alteradas por mais expressões no local a seguir à condição.

Exemplo nº 10

int i,j,a,contador;

for(i=0, j=6,contador=1; i<10 && j>3; i++, j=j-i,contador=contador+1)
{
  a=j*i;
  printf("'a' toma o valor de %d no ciclo numero %d\n",a,contador);
}

Como podem ver, podem-se ter várias variáveis dentro da parte do início, bem como da do incremento/decremento, separadas por vírgulas. Talvez seja importante interpretar este ciclo do ponto de vista do compilador, visto que ainda não o fiz e pode haver dúvidas sobre isso.

Primeiro ciclo: Inicializado i=0, j=6 e contador=1. São verificadas as condições: i é menor que 10, visto que i é 0, j é maior que 3, visto que j é 6. a = i * j, ou seja, a = 0 * 6 = 0.

Segundo ciclo: É executada a instrução de incremento/decremento: i++ (ou seja, i = 0 + 1 = 1), j = j - i (ou seja, j= 6 - 1 = 5), contador = 2 (notar que esta variável serve para que no printf se indique o número do ciclo). São verificas as condições: i continua menor que 10 e j continua maior que 3. a = i * j, ou seja, a = 1 * 5 = 5.

Terceiro ciclo: i++ (ou seja, i = 1 + 1 = 2), j = j - i (ou seja, j = 5 - 2 = 3), contador = 3. As condições são apenas parcialmente verificadas, ou seja, embora o i continue inferior a 10, o j deixou de ser superior a 3. Deste modo, as instruções dentro do for não são executadas.

Exemplo nº 11

Falta ainda explicar melhor a instrução break, bem como a continue, para isso vejamos o próximo exemplo.

int c;
do
{
printf("Coloque um numero para ver o seu dobro.\nColoque 0 para sair.\nSe colocar -1 para voltar a esta opcao\n");
fflush(stdin);
scanf("%d",&c);
if (c==0)
  break;
if (c==-1)
  continue;
else
{
  printf("O dobro de %d, e' %d\n",c,c*2);
}
} while(1);

Este exemplo serve apenas para introduzir o continue e consolidar o break. Como podem constatar ao usar o programa, ao carregarem -1, o programa volta atrás, ou seja, é executado o continue, o qual tem a função de passar à frente de tudo o que haja no ciclo, passando para a iteração (repetição) seguinte, no caso de um for, o continue iria fazer com que a condição de incremento/decremento fosse executada e de seguida a condição de teste para que a iteração seja executada, ou não. O break, tal como no switch, produz uma saída imediata do ciclo, seja ele while, do ... while, ou for.

Um à parte: proponho vivamente que quem está a ver programação pela primeira vez, e tem estado a seguir tudo até agora apenas copiando o código que tenho colocado, deva fazer uma pausa e começar a tentar fazer coisas que pensem, ou se não têm nenhuma ideia do que fazer, proponho que tentem fazer este exemplo simples: criar um programa que faça a média das vossas notas. Tentem complicar ao máximo, usando tudo o que já supostamente aprenderam, ou podiam ter aprendido, ou seja, façam um controlo dos dados de entrada do utilizador, sem saber quantas notas serão colocadas, mas usando um valor bandeira, como no exemplo 10. Se depois necessitarem, eu poderei colocar a solução do problema.

Exemplo nº 12 – Vectores

Se fizeram o que propus, talvez comecem a sentir falta de algo: vectores/matrizes. Não é de modo algum viável criar cem variáveis, apenas porque se pretende manipular cem valores, portanto convém criar algo que as armazene, sem que sejam variáveis para cada valor. Para quem nunca teve álgebra, é possível que desconheça o que é um vector, nesta situação, podendo estar a associar aos vectores da física, os quais estão relacionados, mas para agora, o melhor é considerarem que um vector neste contexto é um conjunto de números dispostos em linha, ou coluna. Uma matriz será uma tabela de números, com duas ou mais dimensões. Não irei mostrar como usar matrizes, mas se pedirem, depois poderei dar um exemplo usando-as.

int i,recibos[5],soma=0;
for(i=0; i<5; i++)
{
  printf("Coloque o valor que recebeu\n");
  scanf("%d",&recibos[i]);
}
printf("Tudo o que recebeu foi:\n");
for(i=0;i<5;i++)
{
  printf("%d\n",recibos[i]);
  soma=soma+recibos[i];
}
printf("Tudo somado da:%d\n",soma);

Temos então a inicialização de algo novo: recibos[5]. Será então um vector com memória para 5 inteiros. Do mesmo modo se podia criar um float ou double, (quanto a char, é outra “conversa”, tratar-se-á de uma string, das quais falarei no exemplo seguinte).

Como podem reparar, para usar um vector, normalmente tem que se usar um ciclo, pois só deste modo se poderá percorrer o vector de modo a preenchê-lo. Um dado importante é o facto de i começar em 0 e acabar em 4, em vez de começar em 1 e acabar em 5, como se poderia esperar. Em C tem-se que o índice do vector começa em zero e acaba uma unidade antes do seu comprimento. Notar que o número que faz de índice tem que ser um inteiro, caso contrário, o programa dará erro. Outro dado importante é que o vector tem que ser definido logo no início, o que implica algo que pode ser constrangedor: temos que saber até onde poderá ir o utilizador, dando a este um limite. Podem experimentar a alterar a condição no for, para que o i vá “mais longe”. Apesar de não dar erro, e de o programa parecer correr na perfeição, com o vector a ser aumentado além do que previamente fora predefinido, tal procedimento é errado e noutros casos causará erros.

Exemplo nº 13 – Strings

char frase[100];

printf("Escreve ai alguma coisa, ate um maximo de 100 caracteres.\n");
gets(frase);

printf("O que escreveu foi:\n");
puts(frase);

printf("nA frase escrita teve %d caracteres.\n",strlen(frase));

Como podem deduzir, o gets é como que um scanf, mas para um conjunto de caracteres, sem precisar de criar um ciclo, como se fez para os vectores, embora tal procedimento esteja correcto. No entanto, se fizerem tal coisa, tenham em atenção algo que distingue uma string, de um vector de caracteres: a string precisa de um último espaço para um caracter especial que indica o fim da string: \0. Deste modo a string indicada não terá espaço para 100 caracteres, mas sim para 99. Caso usem um ciclo, que por vezes dá jeito, não se esqueçam portanto de na última iteração colocarem o \0 na string, senão esta não será uma string, mas sim um vector de caracteres o que significará que não a poderão manipular como tal.

O puts, como podem deduzir também, é como que um printf específico para strings. No último printf aparece outra coisa nova: strlen, uma função que serve para verificar qual o tamanho de uma string. Notar que esta função devolve sempre um número inteiro. Para poder manipular strings de um modo mais amplo, convém adicionar uma biblioteca: #include &lt;string.h&gt. Caso tenham interesse nisto, procurem nos links que estão no final do tutorial esta biblioteca, para verificarem quais as suas potencialidades. Acrescento ainda que uma string funciona como um ponteiro, daí, caso se não pretenda usar o gets, pode-se usar na mesma o scanf, da seguinte forma: scanf("%s", frase);. Notar que não leva o &, por se tratar de um ponteiro, por outro lado o tipo string usa %s para ser invocado, do mesmo modo que num printf se pode colocar o %s para mostrar o que contém a string.

Exemplo nº 14 – Funções

#include <stdio.h>
#include <stdlib.h>

double factorial(double x)
{
  int i,n;
  double y;
  for (i=1; i<=x; i++)
  {
    y=i;
    for (n=1; n<i; n++)
      y=y*n;
  }
  return y;
}

int main()
{
  double a;
  printf("Coloque um numero para ver o seu factorial.\n");
  scanf("%lf",&a);
  printf("O factorial de %lf e' %lf.\n",a,factorial(a));

  return 0;
}

Antes de mais, espero que saibam o que é o factorial de um número.

Como podem ver, uma função apresenta-se fora do int main, ou seja, fora da função principal, exactamente porque é uma função. Esta função pode ser chamada sempre que se deseje, sem que alguma vez seja alterada. Qual a estrutura de uma função?

<Tipo de dado de saída> <nome da função>(<tipo do dado de entrada> <nome que o dado de entrada tomará dentro da função>, ...) /*poderá ser mais que um que dado, sendo que nesse caso estarão separados por vÍrgulas */
{
  <intruções, notar que as variáveis aqui são independentes do int main, e têm que ser inicializadas, tal como o são na função principal>;

  return <variável que se pretenda que seja o output da função>;
}

Notar que a função não precisa de obrigatoriamente ter output. Nesse caso não poderemos definir o tipo de variável será o de saída, logo no princípio. Nesses casos usa-se void, ou seja, no sítio onde colocariam o tipo de variável de saída, colocam void.

Do mesmo modo uma função pode não ter dados de entrada, ficando por isso livre o espaço entre parêntesis após o nome da função, não podendo por isso omitir os parêntesis. Acrescento ainda que não é de modo algum incorrecto usar scanf, printf, etc., dentro de uma função. A única coisa que não pode ser esquecida, é que a função só será corrida através do int main, portanto não esquecer de aí a “chamar”, para ela ser executada.

Para “chamar” a função, basta usar o nome que lhe foi dada, colocando a seguir a este entre parêntesis os valores de entrada, caso os tenha, caso não os tenha, colocam-se apenas os parêntesis.

Conclusão

Dou as explicações por concluídas, apesar de haver ainda muita coisa por falar, como o uso de estruturas (struct), a manipulação de ficheiros (nomeadamente de .txt), ponteiros, e todo um conjunto de particularidades que se poderiam acrescentar ao que disse, isto entre muitas outras coisas mais complexas e que poderão aprender apenas com a força da curiosidade e vontade de aprender mais. Receio que a dada altura do tutorial começaram a ver que as minhas explicações eram mais descuidadas, mas tal foi propositado, visto que se não entendem por poucas palavras, com algumas ideias implícitas que devem deduzir por vós, tal significa que o que está para trás não está totalmente assimilado, como tal devem voltar atrás e analisarem o que não perceberam, podendo recorrer a outros meios, além deste tutorial.

Ideia: O conselho é mesmo: experimentar e tentar inventar por vós. Programar não se aprende lendo, mas sim programando!