| D | S | T | Q | Q | S | S |
|---|---|---|---|---|---|---|
| « nov | ||||||
| 1 | 2 | |||||
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |
Aulas de C
Aprendizado continuo. Linguagem antiga e moderna
Tipos de Dados e Variáveis
Publicado por em 08/11/2010
Olá a todos!
Devem ter “brincado” bastante com o HelloWorld.c, não? Então vamos começar agora a estudar de maneira mais aprofundada algumas coisas que já vimos nele. No caso, falaremos sobre os tipos de dados e variáveis. Portanto, vamos ver um programa um pouco mais complexo que o HelloWorld.c. Novamente digite o programa abaixo como ele está apresentado:
#include <stdio.h>
#include <stdlib.h>
/*
* (c) 2010 GPL
*/
int main (int argc, char** argv)
{
int primeiro=0, segundo=0, soma=0, resto=0, divisaoInteira=0;
float divisaoFlutuante=0;
char nome[80];
char palavra[20];
/*
* O comando abaixo inicializa as strings nome e palavra
*/
memcpy(nome,”\0”,sizeof(nome));
memcpy(palavra,”\0”,sizeof(palavra));
printf(“Olá! Digite seu nome, por favor!\n”);
fgets(nome,sizeof(nome),stdin);
printf(“Digite uma palavra que devo exibir e dois números para eu fazer umas contas.\n”);
scanf(“%s %d %d”,palavra,&primeiro,&segundo);
getc(stdin);
soma=primeiro+segundo;
divisaoInteira=primeiro/segundo;
resto=primeiro%segundo;
divisaoFlutuante=(float)primeiro/(float)segundo;
printf(“Olá, %s\n”,nome);
printf(“Você me pediu para exibir %s e os números %d e %d\n”,palavra,primeiro,segundo);
printf(“Algumas continhas!\n%d+%d=%d\n”,primeiro,segundo,soma);
printf(“%d:%d=%d(Resto %d)”,primeiro,segundo,divisaoInteira,resto);
printf(” ou %7.2f\n”,divisaoFlutuante);
printf(“Divertido, não? Aperte qualquer tecla para continuar…”);
getc(stdin);
return(0);
}
Como fizemos no HelloWorld.c, vamos dar uma “dissecada” no código. Porém, diferentemente do HelloWorld.c, não iremos explicar algumas partes do código, pois elas serão similares ao que vimos no Hello World. Perceba que o código guarda similaridades como a função main e o #include , portanto o que dissemos lá continua valendo. Vamos às explicações “únicas”.
Variáveis – declarando e inicializando:
Como você deve ter reparado, adicionamos um novo #include. No caso, estaremos incluindo a biblioteca string.h, que também é parte da biblioteca-padrão do C. string.h é uma biblioteca que é voltada, como o nome diz, à manipulação de strings, ou seja, cadeias de caracteres. Porém, como veremos logo, as strings em C são bem diferentes das suas similares em outras linguagens de programação, e seu comportamento deve ser bem avaliado.
Logo após main(), temos um trecho de código que não vimos no Hello World:
Logo após main(), temos um trecho de código que não vimos no Hello World:
int primeiro=0, segundo=0, soma=0, resto=0, divisaoInteira=0;
float divisaoFlutuante=0;
char nome[80];
char palavra[20];
Essas linhas fazem a declaração de algumas variáveis. Como o assunto é extenso, vamos gastar algum tempo falando sobre ele aqui.
Em C, as variáveis representam espaços de memória que o compilador irá preparar para determinadas funções para uso do programa. Toda variável tem um tipo pré-determinado (ou estático) e só pode receber valores daquele tipo pré-determinado. No caso, em C, os principais tipos são:
| Tipo | Num de bits | Intervalo | |
| Inicio | Fim | ||
| char | 8 | -128 | 127 |
| unsigned char | 8 | 0 | 255 |
| signed char | 8 | -128 | 127 |
| int | 16 | -32.768 | 32.767 |
| unsigned int | 16 | 0 | 65.535 |
| signed int | 16 | -32.768 | 32.767 |
| short int | 16 | -32.768 | 32.767 |
| unsigned short int | 16 | 0 | 65.535 |
| signed short int | 16 | -32.768 | 32.767 |
| long int | 32 | -2.147.483.648 | 2.147.483.647 |
| signed long int | 32 | -2.147.483.648 | 2.147.483.647 |
| unsigned long int | 32 | 0 | 4.294.967.295 |
| float | 32 | 3,4E-38 | 3.4E+38 |
| double | 64 | 1,7E-308 | 1,7E+308 |
| long double | 80 | 3,4E-4932 | 3,4E+493 |
A bem da verdade, nessa tabela os números de bits são indicados conforme a padronização C exige. Porém, existem casos em que essa padronização não é seguida e isso pode comprometer o uso de determinados tipos . Veremos uma solução ainda ao estudarmos esse programa.
De qualquer modo, podemos dividir os tipos de variáveis em C em três grupos fundamentais:
De qualquer modo, podemos dividir os tipos de variáveis em C em três grupos fundamentais:
- Caracteres;
- Inteiros e;
- Números de ponto flutuante;
Na realidade, os caracteres são entendidos como um subgrupo dos inteiros, mas em 99% das aplicações, não utiliza-se os caracteres como números, embora alguns truques interessantes apareçam daí (veremos algum deles em posts futuros, quando precisarmos lidar com condições lógicas em C).
Aqui é importante ser feita uma ressalva MUITO SÉRIA que não foi feita no Hello World porque não era exatamente o momento: a linguagem C é considerada CASE-SENSITIVE.
“Que diabo é isso?“, você deve estar se perguntando. Isso quer dizer que todo compilador C diferencia as letra maiúsculas das minúsculas. Isso quer dizer que para ele main e MAIN e Main são três coisas diferentes. Isso gera algumas coisas estranhas: por exemplo, o comando return, como vimos no Hello World, é uma palavra reservada e, portanto, não pode ter nenhum outro comando com esse nome. Porém, se você quiser criar uma função Return e outra RETURN, você PODE, uma vez que para o compilador C, cada uma dessas é diferente uma das outras e por sua vez são diferentes de return. Para facilitar a vida, existem certas convenções que são adotadas para evitar confusões, sendo que a principal é: variáveis e funções devem ser nomeadas em minúsculas, sendo que, caso sejam usadas duas palavras, as opções são (1) usar-se hifen (-) ou underscore (_) para separá-las ou (2) colocar a primeira letra de cada palavra à exceção da primeira em maiúsculo.
Dito isso, vamos a mais uma regrinha rápida: como criar um nome de variável válido. O C considera válido um nome de variável que obedeça às seguintes regras:
- Tenha no máximo 32 caracteres de tamanho: na realidade, para o código fonte o nome pode ser maior. Porém, apenas os primeiros 32 caracteres são considerados como nome da variável. Portanto, se o seu programa tiver umaVariavelCujoNomeEhGigantePorqueOProgramadorAchouLegal e tiver também umaVariavelCujoNomeEhGigantePorqueOProgramadorTambemAchouLegal, ou compilador não irá apresentar mensagens de erro, mas você terá erros de lógica, pois para o compilador o nome de ambas as variáveis será umaVariavelCujoNomeEhGigantePorq.
- Seja composto exclusivamente por:
- Letras sem acentos ou caracteres específicos (a-zA-Z);
- Números;
- Underscore (_);
- Não pode ser iniciados por número, embora underscore seja aceito;
- Não seja nome de variável ou função previamente declarada ou ainda de palavra reservada;
Considerando-se essas regras, para o compilador qualquer nome é válido. Isso porque o nome da variável serve apenas para identificar ao programador o valor a ser manipulado (na realidade, o compilador faz uso dos nomes de variáveis para traduzir os nomes em endereços a serem vistos quando o programa for compilado e executado. Veremos mais sobre isso quando entramos no assunto de ponteiros). Porém, é interessante que o programador tome cuidado ao dar os nomes de variáveis de modo a poder compreender o que elas fazem: embora abc123 seja um nome de variável aceitável para o compilador, notaDoAluno é um nome tão válido quanto e mais claro para o programado, então deveria ser uma opção mais acertada em um programa que a opção anterior.
Dito isso, vamos voltar aos tipos de variáveis: como dissemos, existem dois tipos numéricos importantes, os inteiros e os números de ponto flutuante. No caso, os inteiros são sempre identificado como int (à exceção de char e byte, que são reconhecidos como ponteiros, ainda que normalmente não sejam usados como tal), embora possam receber modificadores. Esses têm a ver com o tamanho em bits do mesmo (o que também afeta o valor máximo que o mesmo pode representar) e como o fato de ter sinal ou não (o sinal é sempre representado por um bit, e portanto pode modificar o valor máximo que o mesmo pode representar). O int básico é signed (tem sinal) e short (em seu menor tamanho). Na tabela anterior perceba que int, short int, signed int e signed short int tem o mesmo valor em número de bits (16) e valores mínimos e máximos (de -32768 a 32767).
Comparemos primeiro o int básico com o unsigned int (inteiro sem sinal). O número de bits é o mesmo, mas o valor mínimo muda para 0 (ou seja, essa variável não aceita valores negativos). Se compararmos o int com o long int (inteiro grande), embora o valor mínimo seja negativo, em ambas as pontas ele é maior que o int normal por ter um maior número de bits. É importante ter isso em mente ao criar-se um programa: em certas situações (por exemplo, contagem de mercadorias) um long int pode ser mais útil que um int. Em outras aplicações (por exemplo, uma aplicação de votação), usar um unsigned int pode permitir a você usar com maior eficiência a memória do sistema (ao não ser obrigado, por exemplo, a usar um long int).
Na parte dos números de ponto flutuante, o C utiliza float, double e long double. Em todos os casos, o C tem seus limites definidos em potências de 10. Porém, devido às conversões de base e perdas de precisão, é importante ter em mente que valores de ponto flutuante perderão precisão conforme o tipo utilizado: quanto mais bits, mais preciso o valor, e portanto menor chance de erros de cálculo serão sentidas. Porém, é importante lembrar que existe consumo de memória, e que dependendo da aplicação isso deve ser levado em conta.
De qualquer forma, existe pouca coisa a comentar a mais sobre os tipos de variáveis. Voltemos agora ao nosso código de exemplo:
int primeiro=0, segundo=0, soma=0, resto=0, divisaoInteira=0;
float divisaoFlutuante=0;
char nome[80];
char palavra[20];
São declaradas cinco variáveis inteiras (int), com os nomes primeiro, segundo, soma, resto e divisaoInteira. Se você só declarar uma variável, o valor inicial dela será aleatório. Não é considerado uma boa prática, ainda que permitido pelo C, declarar-se uma variável sem inicializá-la, pois isso pode ter conseqüências estranhas. No caso, as variáveis inteiras em questão foram inicializadas em 0, ao colocar-se diante delas um sinal de igual. O sinal de igual em C é um operando de atribuição de valor, ou seja, ele indica que a varíavel colocada antes do sinal de igual irá receber o valor colocado depois do sinal de igual. É importante deixar claro por causa dos operadores lógicos, que veremos em outro exemplo, e como funciona as comparações lógicas em C.
Uma coisa que é importante dizer é que uma variável pode ser declarada em uma linha e inicializada em outra. Embora o código como mostrado seja considerado mais claro e seja uma melhor prática em C, o código abaixo:
int primeiro, segundo, soma, resto, divisaoInteira;
primeiro=0;
segundo=0;
soma=0;
resto=0;
divisaoInteira=0;
Embora menos “elegante” é tão correto quanto no caso da linha int primeiro=0, segundo=0, soma=0, resto=0, divisaoInteira=0;. Essa prática de inicializar variáveis no momento da declaração, porém, impede de cometer-se erros em outros pontos, em especial quando utilizamos as variáveis de ponteiro, que veremos futuramente.
Bom, vamos continuar adiante. Após declarar os cinco inteiros, é declarado uma váriavel de ponto flutuante float divisaoFlutuante=0. Alguns autores sugerem que crie-se a prática de inicializar variáveis de ponto flutuante com 0.0, pois essa é, digamos assim, a forma de indicar um 0 de ponto flutuante sem provocar typecast (veremos isso adiante). Particularmente, não acho essa uma boa opção. O ganho de desempenho não é tão alto e a legibilidade fica um pouco confusa. Mas tem aplicações, quando você possui sistemas com baixa potência (microprocessadores, por exemplo), isso pode te oferecer um ganho de performance.
Após isso, temos duas strings sendo declaradas, uma chamada nome de 80 caracteres e uma chamada palavra de 20 caracteres. Aqui na realidade não estamos declarando uma strings, e sim uma matriz de caracteres. O C lida com tipos discretos, não possuindo tipos “compostos”, como uma string. No C, uma string é composta pelos caracteres e um símbolo especial de terminação, chamado caracter nulo, ou null-character em inglês. Essa declaração apenas separa o espaço necessário para armazenar 80 caracteres (incluindo o terminador null-character). Veremos mais sobre isso em matrizes e ponteiros. Por enquanto, você sabe que essa é a forma de criar uma string em C e que você não consegue criar uma string “dinâmica” (ou seja, de tamanho ilimitado) em C.
memcpy, sizeof e cuidados com memória:
OK…. Até agora vimos a declaração de variáveis e sua inicialização, assim como a questão das strings em C. Vamos seguir adiante que esse programa ainda tem muita coisa a ser vista.
Após as declarações de variáveis, vemos um novo comando:
Após as declarações de variáveis, vemos um novo comando:
/*
* O comando abaixo inicializa as strings nome e palavra
*/
memcpy(nome,”\”,sizeof(nome));
memcpy(palavra,”\”,sizeof(palavra));
O memcpy é um comando da biblioteca string.h que copia uma determinada string para outra um determinado número de vezes (memcpy vem de MEMory CoPY – Cópia de memória). Esse comando exige três parâmetros:
- O primeiro é o nome da váriável para a qual serão copiadas as informações (na verdade a leitura é um tanto mais complexa que isso. Iremos nos aprofundar ao lidar com ponteiros);
- O segundo é a string a ser copiada;
- O terceiro é o número de vezes que ela será copiada;
Na primeira linha, o primeiro parâmetro é a variável nome. O segundo parâmetro é “\”, uma string de um caracter só. No caso, estamos utilizando um caracter de controle similar ao \n do printf (que vimos no Hello World). No caso, “” é o caracter de controle que representa o terminador nulo que indica o fim de uma string.
O terceiro parâmetro é interessante de ser avaliado com calma, uma vez que ele mostra uma nova palavra reservada do C, chamada sizeof. O comando sizeof recebe como parâmetro uma váriavel e devolve, em bytes, o tamanho da mesma. No caso, estamos usando sizeof para obter esse valor em bytes e usá-lo como número de vezes em que o caracter nulo deverá ser executado.
Você pode estar se perguntando: “qual a vantagem disso, se sabemos o tamanho da string palavra?” O problema é que o C, em seu padrão, apenas RECOMENDA tamanhos mínimos para os tipos de variável, não os OBRIGA. Desse modo, quando precisamos de ter certeza, como nesse caso, é interessante que utilizemos sizeof para que seu valor seja correto durante a execução, tornando-o mais portável e evitando “números mágicos” de difícil análise em caso de erro. Isso é ainda mais importante quando temos que usar, por exemplo, alocação de memória dinâmica (que veremos no futuro) com tipos numéricos cujo tamanho pode variar de máquina para máquina (máquinas para processamento científico podem usar tipagens numéricas com um grande número de bytes para alcançar níveis de precisão condizentes às necessidades científicas). Por agora, basta saber que o uso de sizeof para determinar tamanhos de variáveis é considerado uma boa prática de programação.
Entrada de dados – fgets,scanf, entrada padrão, ponteiros e o operando de endereçamento &:
Uma vez inicializadas as variáveis, estamos em “ambiente seguro” para seguirmos em frente. Como a maioria dos programas, precisamos entrar alguns dados. No caso faremos isso de algumas formas diferentes, usando comandos diferentes mostrados no trecho de código abaixo:
printf(“Olá! Digite seu nome, por favor!\n”);
fgets(nome,sizeof(nome),stdin);
A linha em roxo mostra uma forma de ler-se informação de uma entrada de dados. No caso, utilizamos o comando fgets, que faz parte da biblioteca stdio.h. Esse comando possui três parâmetros:
- O primeiro parâmetro é o nome da variável que irá receber as informações (no nosso caso, nome);
- O segundo é o número máximo de caracteres a serem lidos (no caso, novamente usamos sizeof para obter o número máximo de bytes);
- O terceiro é um nome que indica qual a fonte dos dados a ser usada. No caso nosso, estamos usando o nome “stdin“.
fgets irá ler da fonte de dados indicada todos os caracteres possíveis até que (1) seja alcançado o limite de caracteres determinados no segundo parâmetro seja alcançado ou (2) um terminador nulo seja lido ou (3) seja lido um caracter de nova linha (\n). Na prática, essa última condição quer dizer que o ENTER do teclado tenha sido pressionado, sendo que o caracterdo ENTER (ASCII 13, ou \n) será armazenado.
O nome stdin, mostrado no terceiro parâmetro, é um símbolo padronizado do C, definido dentro do stdio.h. Esse símbolo representa a entrada padrão do programa C. Normalmente, a entrada padrão de um programa é o teclado, da mesma forma que a saída padrão é o monitor de vídeo. Porém, em muitos sistemas operacionais é possível utilizar-se estruturas e comandos que redirecionam a entrada e/ou a saída padrão para outras fontes (como a saída ou entrada de um programa anterior ou posterior, no que é chamado de piping). No nosso caso, estamos usado stdin para que o sistema leia o que vier do teclado do operador.
Você deve se perguntar: “Putz… que complicado… não dá para facilitar?”. Na realidade, até dá, mas aqui estamos adotando uma prática segura que é usar comandos em C que apenas utilizem a memória que foi determinada.
O C por natureza não controla o uso de memória. No caso das strings, isso é muito importante: embora declaremos um tamanho para a string, isso não quer dizer que esse tamanho será obedecido. Isso se deve ao fato de o C considerar que uma string é uma matriz ou um ponteiro de caracteres e o C não fazer nenhum controle de onde o ponteiro irá ir. Na realidade, entraremos mais aprofundadamente nesse conceito quando falarmos especificamente de ponteiros, mas aqui cabe o “parênteses”.
Existe uma função da biblioteca stdio.h, chamada gets. Ela exige apenas um parâmetro, o nome da variável que irá receber as informações, sendo muito mais simples e rápida que fgets. Porém, como ela não possui algo que diz a ela o tamanho dessa variável (na verdade, da matriz), ela irá escrever as informações onde der, inclusive sobrescrevendo qualquer coisa que esteja além da memória utilizada pela matriz uma vez que essa esteja “cheia”, não importa o que seja. Isso pode comprometer o sistema das mais diversas formas: como não há como saber o que está “imediatamente depois” da sua matriz na memória, você não tem como saber se, por exemplo, o seu código não está gravando sobre trechos de programas do sistema carregados em memória, dados de outras pessoas, etc… Por isso nossa opção por usar um comando mais complexo, mas que garanta que o programa funcionará como esperado.
Bem, acho que já demos a atenção devida ao fgets. Não se preocupe se não compreendeu totalmente o que dissemos agora: mais para frente voltaremos a esse assunto, quando tivermos com alguns conceitos mais bem detalhados, e aí as coisas ficarão mais claras.
Vamos à nossa segunda entrada:
printf(“Digite uma palavra que devo exibir e dois números para eu fazer umas contas.\n”);
scanf(“%s %d %d”,palavra,&primeiro,&segundo);
Aqui estamos usando outro comando de entrada de dados: no caso, estamos usando o scanf, que como os demais comandos de entrada de dados é parte da biblioteca stdio.h. scanf lê as informações da linha digitada e tenta encontrar coisas que casem com o formato desejado, e armazena essa informações nas variáveis desejadas. No caso, ele utiliza símbolos de formato similares aos de printf para “quebrar” a entrada da maneira adequada. No comando apresentado, ele lê uma string (%s) que irá acabar no primeiro espaço lido (importante notar isso), e em seguida lerá dois inteiros (%d), separados por espaço, e armazenará os valores lidos nas variáveisa palavra, primeiro e segundo.
Aqui, você deve ter reparado nos e-comerciais (&) na frente de primeiro e segundo. Isso se deve pelo fato de scanf precisar dos endereços das variáveis em questão, e para isso, precisamos passar ponteiros. Em C, chamamos de ponteiro uma variável que, ao invés de armazenar um conteúdo per se, armazena o endereço da memória onde esse conteúdo se encontra (na realidade, o conceito é mais complexo, mas não vamos aprofundar nele agora). Como primeiro e segundo são variáveis int comuns (ou seja, armazenam conteúdos, e não o endereço), precisamos obter o endereço de memória onde esse conteúdo está., ou seja, o endereço de memória das variáveis Para isso, usamos o operador & antes do nome da varíavel. O operador & é chamado de operador de derreferenciamento, e sua função é indicar que, naquele momento, utilizaremos o endereço da variável em questão, e não o seu conteúdo.
No caso de palavra, porém, não é necessário o operador &, pois toda matriz em C também pode ser usada como ponteiro. Na verdade, no memcpy e no fgets utilizamos os nomes das matrizes como ponteiros. Portanto, uma regrinha de C que acabamos de aprender:
EM C, TODA MATRIZ PODE SER USADA COMO UM PONTEIRO.
Iremos aprofundar essa regrinha quando falarmos de ponteiros mais profundamente. Agora, porém, deve ter ficado claro a utilidade do e-comercial (&). Se não ficou, tudo bem (por agora): ainda veremos muitas vezes o & e logo tudo isso ficará claro.
O scanf, assim como o printf, possui uma grande gama de símbolos de formato. Abaixo deixamos uma tabela com os símbolos de formato do scanf (mais adiante ofereceremos uma para printf):
| Código | Formato |
| %c | Um único caracter (char) |
| %d | Um número decimal (int) |
| %i | Um número inteiro |
| %hi | Um short int |
| %li | Um long int |
| %e | Um ponto flutuante |
| %f | Um ponto flutuante |
| %lf | Um double |
| %h | Inteiro curto |
| %o | Número octal |
| %s | String |
| %x | Número hexadecimal |
Bem, vamos seguir em frente. Esse ponto ficará mais claro com o uso constante do comando scanf, que faremos no futuro.
Antes de avançar, falaremos sobre o comando getc(stdin). Basicamente ele lê um caracter de uma entra indicada (no caso stdin) e devolvê-lo para uma variável. Como não usamos nenhuma atribuição, o valor é simplesmente eliminado do stdin. Usamos esse comando para que qualquer caracter indesejado (em especial, ENTERs não lidos).
Antes de avançar, falaremos sobre o comando getc(stdin). Basicamente ele lê um caracter de uma entra indicada (no caso stdin) e devolvê-lo para uma variável. Como não usamos nenhuma atribuição, o valor é simplesmente eliminado do stdin. Usamos esse comando para que qualquer caracter indesejado (em especial, ENTERs não lidos).
Operações matemáticas, operandos matemáticos e typecasting:
OK… Já obtivemos as entradas de nosso usuário, então é hora de fazemos algo com tudo isso. No caso, faremos uma brincadeira boba que é fazer algumas contas com os dois números que o usuário passou, primeiro e segundo:
soma=primeiro+segundo;
divisaoInteira=primeiro/segundo;
resto=primeiro%segundo;
divisaoFlutuante=(float)primeiro/(float)segundo;
Aqui temos um exemplo mais claro de atribuição: as variáveis soma, divisaoInteira, resto e divisaoFlutuante recebem os resultados de cada uma das contas que mandamos o C fazer. No caso, toda operação matemática em C é composta por:
atributo1 operação atributo2
Por exemplo: a varíavel soma irá receber o resultado de primeiro + segundo. Vejamos quais são os principais operadores matemáticos em C:
- / , * e % = Divisão, multiplicação e resto da divisão inteira;
- + e - = Soma e subtração;
- = = atribuição;
A seqüência foi propositamente colocada na ordem acima pois o C, assim como a matemática, possui uma ordem de prioridade nos operandos: os operandos / , * e % (Divisão, multiplicação e resto da divisão inteira) possuem uma prioridade mais alta que os operandos + e - (Soma e subtração), portanto são executados primeiro em uma expressão complexa, com vários operandos executados ao mesmo tempo. É possível, com o uso de parênteses (), alterar a prioridade das expressões, gerando os valores corretos (de forma equivalente ao que acontece em equações matemáticas). Por exemplo: x * y + z é diferente de x * (y + z). Na primeira, o C (como na matemática) irá primeiro multiplicar x por y e depois somar o resultado a z. Na segunda expressão, primeiro é feita a soma de y e z e depois o resultado é multiplicado por x. Uma dica muito útil é: se você estiver em dúvida quanto à seqüência correta de operações, isole os termos com parênteses aos pares: embora afete um pouco a leitura do programa, é mais interessante que incorrer no risco de gerar resultados errados.
OK, vimos quais são os operandos matemáticos e como eles se comportam. Analisamos o código linha a linha, vemos que na primeira linha é executada uma soma entre os operandos primeiro e segundo e o resultado é atribuído a soma. Na segunda, é feita uma divisão entre os operandos primeiro e segundo. No caso, será feita uma divisão inteira, pois ambas são variáveis inteiras e a variável que que irá receber o resultado (divisaoInteira), também é um int. Em seguida, temos uma operação de resto entre primeiro e segundo que será armazenado em resto. Essa operação de resto (%) deve ser feito apenas com valores inteiros. Mas isso pode ser resolvido com um mecanismo que mostraremos abaixo.
A última linha apresenta uma estrutura importante que existe em C chamada typecast (mudança de tipo). Algumas vezes, precisamos fazer operações matemáticas (entre outras) com varíaveis cujo tipo originalmente não nos permite. Por exemplo, imagine que primeiro é 5 e segundo é 2. Embora indiquemos que divisaoFlutuante tem um tipo float, se não forçarmos o programa a enxergar ao menos um dos valores como float, o resultado armazenado em divisaoFlutuante será 2, ainda que armazenado em memória e com o mesmo comportamento de um número de ponto flutuante. Esse comportamento se deve ao fato de que o C pode converter operandos numéricos para outros tipos, mas apenas quando exista alguma diferença de armazenamento. Se deixarmos os dois como inteiros, a divisão será feita como inteira (ou seja, dando o resultado 2) e só depois, na hora da atribuição é que o valor será convertido para float, o tipo correto a ser armazenado em divisaoFlutuante.
Para solucionarmos esse tipo de problema, podemos informar ao C que determinado valor, ainda que expressado de um tipo, deve ser tratado como outro naquele momento específico. A isso chama-se em programação de typecast. No caso da última linha, estamos dando typecast (ou, para resumir, cast) nas variável primeiro e segundo. Para dar-se um cast em um valor ou variável, basta anteceder o mesmo com o tipo que o sistema irá adotar naquele momento para o mesmo entre parênteses. No caso, para converter primeiro em float, utilizamos (float)primeiro. Importante dizer que não era necessário dar o cast em segundo, pois o programa, ao perceber que estaria tentando dividir um número de ponto flutuante por um inteiro não dividiria “laranjas com bananas”, por assim dizer, dando ele próprio o cast em segundo (o que é chamado em programação de autocast). Porém, para melhorar a leitura do programa, achei interessante dar o cast manualmente em segundo também. Muitas vezes, fazendo as coisas da maneira correta, você não precisará tanto de casts quanto aparente, pois o compilador irá ele próprio fazer ajustes para provocar autocast dependendo do caso. De qualquer modo, casts podem ajudar a leitura do programa, o que é bem importante.
printf, caracteres de controle e símbolos de formato:
Bem, agora que já fizemos continhas bobas, tá na hora de nosso programa mostrar o que ele fez:
printf(“Olá, %s\n”,nome);
printf(“Você me pediu para exibir %s e os números %d e %d\n”,palavra,primeiro,segundo);
printf(“Algumas continhas!\n%d+%d=%d\n”,primeiro,segundo,soma);
printf(“%d:%d=%d(Resto %d)”,primeiro,segundo,divisaoInteira,resto);
printf(” ou %7.2f\n”,divisaoFlutuante);
printf(“Divertido, não? Aperte qualquer tecla para continuar…”);
getc(stdin);
return(0);
OK, você deve estar se perguntando, temos um monte de printf que vimos lá no Hello World, e que faz saída formatada. E daí?
Bem… E daí que agora temos saídas que o sistema processou e que devemos mostrar ao usuário. Para isso, temos que indicar ao C o que vai ser publicado e como.
O printf, além dos caracteres de controle, aceita símbolos de formato. Lembra quando falamos acima, ao comentarmos o scanf, que ele exigia símbolos de formato para saber o que ler? Pois bem, o nosso amigo printf também aceita símbolos de formato para dizer como os dados deverão ser apresentados pelo sistema. Abaixo copiamos uma tabela de símbolos de formatos (site original – Curso de C da UFMG):
| Código | Formato |
| %c | Um caracter (char) |
| %d | Um número inteiro decimal (int) |
| %i | O mesmo que %d |
| %e | Número em notação científica com o “e”minúsculo |
| %E | Número em notação científica com o “e”maiúsculo |
| %f | Ponto flutuante decimal |
| %g | Escolhe automaticamente o melhor entre %f e %e |
| %G | Escolhe automaticamente o melhor entre %f e %E |
| %o | Número octal |
| %s | String |
| %u | Decimal “unsigned” (sem sinal) |
| %x | Hexadecimal com letras minúsculas |
| %X | Hexadecimal com letras maiúsculas |
| %% | Imprime um % |
| %p | Ponteiro |
Na verdade, a formatação completa é um pouco mais complexa, pois após o % você pode colocar:
- -, indicando que o preenchimento deve alinhar-se à direta (e não à esquerda);
- +, indicando que, caso o valor tenha sinal, os símbolos de sinal são mantidos (normalmente sinais de positivo são ignorados);
- um número, indicando o tanto de caracteres a serem exibidos. No caso de numéricos, se esse número for precedido por 0, os caracteres que normalmente não seriam preenchidos serão preenchidos por 0;
- uma seqüência x.y indicando (para ponto flutuante) que deve-se exibir o número com um número de caracteres x, sendo que desses y serão casas decimais ou (para inteiros) deve-se exibir no mínimo x números e no máximo y. Vale a regra do 0 mostrada acima;
Existem muito mais complexidades envolvendo a saída formatada. Caso queira saber mais, esse artigo da Wikipedia traz muito mais informações que, na pior nas hipóteses, serão interessantes a título de curiosidade.
A primeira linha, printf(“Olá, %s\n”,nome);, irá imprimir na tela “Olá”, seguido pelo conteúdo da variável nome, e irá pular uma linha. Porém, na execução, você irá perceber que irão ser puladas duas linhas. A segunda linha deve-se ao fato de na leitura de dados por fgets o caracter \n (ENTER) será lido e interpretado pelo printf como parte da varíavel nome. Em outros tópicos ensinaremos uma técnica simples para remover esse \n e deixar a saída mais elegante. Por enquanto, somos obrigados a tratar essa segunda nova linha como um bug do programa.
A segunda linha do trecho que estamos estudando mostra uma característica do printf. Veja a linha em questão:
printf(“Você me pediu para exibir %s e os números %d e %d\n”,palavra,primeiro,segundo);
Essa linha irá exibir a palavra e os números que você digitou anteriormente. Como isso é feito?
Perceba que a linha em questão possui três símbolos de formato, %s, %d e %d. Esses símbolos indicam que o programa espera uma string e dois inteiros para exibí-los na tela. Logo após a nossa string formatada (“Você me pediu para exibir %s e os números %d e %d\n”), colocamos as variáveis que armazenam esses valores na seqüência pedida pela string (no caso, primeiro palavra – a string, depois primeiro e segundo – os dois inteiros), separados por vírgulas entre si e da string a ser formatada. Essa é a construção padrão de um comando printf: uma string a ser formatada, contendo tantos caracteres de controles e símbolos de formato quanto necessário, seguido pelas variáveis a terem seus conteúdos apresentadas em cada posição, na seqüência das mesmas e com um tipo adequado ao símbolo de formato. Colocar menos ou mais variáveis e/ou variáveis de tipo inadequado irá ocasionar erros no momento da compilação (porém, no caso dos numéricos, é permitido fazer o cast do conteúdo da variável para um tipo de dados adequado antes de apresentar o valor em questão).
Em seguida a outra linha possui uma construção propositalmente confusa na string a ser formatada. Vamos vê-la:
Em seguida a outra linha possui uma construção propositalmente confusa na string a ser formatada. Vamos vê-la:
“Algumas continhas!\n%d+%d=%d\n“
Lembrando que os valores que irão substituir os três símbolos %d são os das variáveis primeiro, segundo e soma. Qual será a saída dessa string:
- A primeira coisa será imprimir Algumas continhas!, seguido por uma nova linha(\n);
- Em seguida, irá exibir o conteúdo de primeiro (%d - imaginemos que seja um 5)…
- … seguido por um sinal de maior (+)…
- e pelo valor de segundo (%d – imaginemos que seja um 2) …
- … seguido por um sinal de igual (=)…
- que precede o valor de soma (%d – que, como vimos anteriormente, é primeiro+segundo – nesse caso 5+2, dando um 7)…
- Terminando por um outro nova linha (\n);
- O que nos leva à conclusão que, na tela, irá aparecer (considerando os valores acima):
Algumas continhas!
5+2=7
Esse tipo de construção é permitida? Sim! Desde que se siga-se a regra de que tem que haver tantas variáveis quanto símbolos de formato e nos tipos adequados, nada impede que uma mesma string formatada gere 2, 3, até 1000 linhas (na verdade, existe outra regra que falaremos ao mencionar mais claramente strings).
Bem, a linha seguinte, printf(“%d:%d=%d(Resto %d)”,primeiro,segundo,divisaoInteira,resto);, lembra a anterior, à exceção que não terminamos essa linha com um nova-linha (\n). Da mesma forma que uma string a ser formatada pelo printf não precisa ter nenhum símbolo de formato (lembra do printf(“Hello World!\n”);?), o printf pode ter uma linha sem caracteres de controle. Na realidade, nenhum dos dois é obrigatório no comando printf. No nosso caso, ele irá formatar a string e exibir o seu conteúdo, mas sem pular linha. Isso irá gerar uma linha cujo conteúdo será contatenado na saída em tela com o conteúdo da próxima instrução printf que tiver, ou então com uma linha de comando do sistema ou similar caso o programa se encerre antes. Isso é importante de ser entendido, pois o printf não pula automaticamente linhas! Parece bobagem dizer isso, mas caso não seja indicado explicitamente que o comando deve pular uma linha (com o uso de \n), ele não irá o fazer.
OK, a linha seguinte tem um exemplo que é interessante e importante:
printf(” ou %7.2f\n”,divisaoFlutuante);
Parece muito com os demais printf que vimos nesse longo exemplo. Porém, a diferença tá no símbolo de formato: %7.2f. O que isso quer dizer? Esse símbolo indica que, na posição em questão, serão exibidos no máximo 7 caracteres, com no mínimo 2 deles sendo casas decimais (somando o ponto decimal, sobrariam portanto 4 casas para a parte inteira) e que o número será exibido como um flutuante decimal (f). Esse é um ponto importante que podemos resumir criando uma espécie de “modelo” de símbolos de formatação:
%[-+0][tamanho.[casas-decimais]]tipo
Desses, apenas tipo é obrigatório, sendo que podem ser usados quaisquer um dos tipos anteriormente mostrados na tabela de símbolos. O tamanho pode ser usado em qualquer condição, e casas-decimais pode ser usado em qualquer numérico, assim como os caracteres especiais -, + e 0 antes do tamanho. Alguns exemplos:
- %30s – apresenta apenas os primeiro trinta caracteres de uma string;
-
%10.2f – apresenta um ponto flutante escrito com 10 caracteres, sendo dois deles casas decimais: no caso dos pontos flutuantes, uma vez que se defina um número de casas decimais a serem exibidas ele é respeitado SEMPRE – valores com mais casas decimais tem seus valores decimais arredondados até o número de casas adequado e valores com menos casas têm as casas restantes preenchidas com 0;
-
%4h – esse é um interessante, pois mostra o conteúdo da variável inteira associada convertido para hexadecimal. A base hexadecimal (ou base-16) é uma base numérica muito usada em eletrônica e programação avançada, e por isso C prevê o uso dessa base como forma de facilitar a entrada e saída de valores;
-
%-30s – como o anterior, mas irá alinhar o texto à direita, preenchendo os caracteres que sobrem (caso aplicável), com espaços;
-
%+020.2f – “COMO ASSIM BIAL?”, você deve estar pensando… Bem, esse é nosso exemplo mais complexo: ele vai (1) imprimir um ponto flutuante com (2) 20 caracteres sendo (3) duas casas decimais e (4) preenchendo os caracteres que sobrem (caso aplicável) com 0 e (5) mostrando sempre um símbolo de sinal, independente de o resultado ser positivo ou negativo. Esse pode ser um exemplo estranho, mas existem aplicações científicas onde a leitura do sinal na saída dos dados é importante (por exemplo, coordenadas geográficas e ou indicadores de sinais em astrofísica);
Bem creio que com essa última linha acabamos de explicar o importante do programa. Salve ele, compile-o (já vimos como compilar um programa no Hello World) e brinque um pouco, executando-o várias vezes e procurando pensar em como o programa se comporta com os diversos valores.
Como fizemos com o Hello World, aqui também vou sugerir algumas “brincadeiras” com o programa:
-
Pra começar, tente modificar os tipos de variáveis no momento da declaração para ver o comportamento do programa. Aqui muitas coisas poderão simplesmente não funcionar, mas o objetivo por incrível que pareça é esse mesmo: procurar entender o que funciona e o que não;
-
Para entender as mecânicas de typecasting e autocasting, remova um dos casts para float na divisaoFlutuante, e depois remova o outro. Veja o comportamento em ambas as situações, e procure reparar como o programa irá reagir em cada uma dessa situações. PS: para que o exemplo fique mais claro, escolha valores para primeiro e segundo cuja divisão não seja exata (por exemplo, 8 e 3 ou 5 e 2);
-
Tente modificar as formatações na saída do programa. Utilize tamanhos fixos e no caso dos números experimente acrescentar o 0 antes dos tamanhos do mesmo. Utilize - para alinhar valores à direita;
-
No momento em que for digitar o nome e a palavra a serem exibidas, tente utilizar valores com tamanhos muito maiores que os que as variáveis suportam. Verifique qual será a saída resultante. Lembrando sempre que a maior palavra da Língua Portuguesa é anticonstitucionalissimamente e que um bom nome gigante é o de Dom Pedro II (Pedro de Alcântara João Carlos Leopoldo Salvador Bibiano Francisco Xavier de Paula Leocádio Miguel Gabriel Rafael Gonzaga) , o que os tornam ótimos valores para esses testes;
-
Após fazer esses testes, modifique o programa para que ele use gets ao invés de fgets e repita os testes. Verifique o que pode acontecer ao entrar valores que “estourem” o tamanho da variável nome e o comportamento no sistema operacional quando isso ocorrer;
-
Tente adicionar ao programa um comando que determine a área de um triângulo de base primeiro e altura segundo. Declare e inicialize uma variável para guardar esse valor e um comando printf para exibir o resultado final;
Bem, esse foi um exemplo bem mais longo, pois tivemos que tratar muitos assuntos aqui. Semana que vem a idéia é entrar em comandos de controle de fluxo. Então, até lá!
O primeiro programa: HelloWorld.c
Publicado por em 05/11/2010
Olá todos!
Bem, agora vamos para algo de programação.
OK… Na realidade não é nada muito fantástico, mas a ideia é permitir que você tenha uma noção da estrutura de um programa C típico e de como ele é composto. Depois iremos explicar tudo de maneira mais detalhada.
Existe uma tradição em programação que o primeiro programa de computador para qualquer linguagem deve apresentar apenas uma mensagem na tela, normalmente “Hello World!“. Na realidade, se você usar o Google para pesquisar o termo “Hello World” em programação, você verá sites com coletâneas enormes de HelloWorlds nas mais diversas linguagens de programação, antigas ou modernas.
De qualquer modo, vamos ver nosso Hello World em C. Abra um editor de texto (como o Notepad do Windows ou quaisquer um dos editores de texto do Linux) e digite o que está abaixo as-is. (iremos explicar melhor logo) Se estiver usando uma IDE, abra-a e crie um arquivo com o conteúdo abaixo:
Existe uma tradição em programação que o primeiro programa de computador para qualquer linguagem deve apresentar apenas uma mensagem na tela, normalmente “Hello World!“. Na realidade, se você usar o Google para pesquisar o termo “Hello World” em programação, você verá sites com coletâneas enormes de HelloWorlds nas mais diversas linguagens de programação, antigas ou modernas.
De qualquer modo, vamos ver nosso Hello World em C. Abra um editor de texto (como o Notepad do Windows ou quaisquer um dos editores de texto do Linux) e digite o que está abaixo as-is. (iremos explicar melhor logo) Se estiver usando uma IDE, abra-a e crie um arquivo com o conteúdo abaixo:
#include <stdio.h>int main (int argc, char** argv)
/* Nosso Hello World! (c) 2010 GPL */
{
printf(“Hello World!\n”); // Trouxemos ele do stdio.h
return (0);
}
Não se preocupe em copiar a formatação do código: apenas digite-o como ele está. As cores são apenas para algumas explicações que serão dadas sobre o programa em questão.
Vamos começar então a destrinchar os que digitamos.
Repare na primeira linhas:
#include <stdio.h>
Ela, por incrível que pareça, ainda não é código C… Na verdade não exatamente. Todo “comando” que comece com o # (sharp, tralha, cerquilha, lasanha, entre outras formas de dizer que já ouvi por aí) é um comando para o pré-processador, que indica que o compilador deve tomar alguma atitude especial. Nesse caso, o #include adiciona ao arquivo em questão o conteúdo de um outro arquivo, no caso o arquivo stdio.h. O fato de ele estar entre os sinais de maior-menor tem uma função especial: ele faz o compilador buscar esse arquivo entre os arquivos da biblioteca-padrão do C. A biblioteca-padrão do C representa comandos que normalmente espera-se que façam parte do compilador independentemente da plataforma, versão ou tipo do compilador específico e, embora não sejam necessariamente obrigatórios, eles são quase sempre encontrados em qualquer bom compilador. É possível programar-se em C sem as bibliotecas-padrão (na realidade, em alguns casos é desejável, como no caso de programar-se C para microprocessadores), mas em geral um bom compilador irá incluir as bibliotecas padrão do C. Em alguns casos, o maior-menor irá representar a inclusão de arquivos de outras bibliotecas que fazem parte dos includes do compilador. Falaremos mais sobre isso quando entrarmos na questão de programação com múltiplos objetos e afins.
O stdio.h vêm de STandarD I/O Headers (Cabeçalhos de Entrada e Saída Padrão). Ele faz referências a funções de entrada e saída padronizadas pelo C. No caso, os cabeçalhos indicam ao compilador que tipo de funções o programa irá usar e como ele irá se comportar nesse caso. Veremos mais no futuro, mas o que é importante saber é que, sem essa linha, esse programa (e qualquer outro que exija funções de entrada e saída padrão) irá dar erro no momento da sua geração (ou compilação).
Chega de falar dessa linha. Vamos falar sobre uma coisa muito importante em C: comentários.
Comentários são basicamente isso: comentários. Em geral, comentários são apenas texto informativo que é inserido em um programa para documentá-lo, sendo sumariamente ignorado pelo compilador (veremos mais sobre o compilador ainda nesse post). Em alguns casos, com o uso de ferramentas certas, comentários podem ser muito úteis, ajudando a documentar um programa de maneiras muito inteligentes. Uma utilidade também dos comentários é que eles podem ser usados como método de depuração (correção de problemas): basta comentar-se o trecho de código onde existam problemas e verificar se os mesmos persistem uma vez que o programa seja re-executado.
No C, existem dois tipos de comentários:
- O padrão mais antigo, onde começa-se o comentário com /* e termina com */: nesse caso, é considerado comentário tudo que estiver entre esses dois símbolos. A vantagem desse tipo de comentário é que ele é multi-line, ou seja, você pode adicionar linhas e linhas de comentário, desde que todos os comentários estejam entre esses dois símbolos;
- Um padrão mais recente (parte do padrão chamado C99), que é usar-se duas barras (//): na verdade, esse padrão já usado a um bom tempo, em especial em compiladores que compilem código de C++ além de C (veremos C++ em tópicos mais avançados). Ele permite comentários in-line, ou seja, comentários a partir de um determinado ponto de uma linha de código. Para o compilador, tudo entre as duas barras e o final da linha onde elas estão será considerado comentário;
Bem, não precisamos falar mais dos comentários, então vamos voltar à nossa Repare nas linhas comentadas em azul:
int main (int argc, char** argv)
{
<…>
}
Aqui estamos utilizando uma função main para colocar o código principal do nosso programa. O C trabalha com o conceito de função para separar os trechos de códigos, sendo que uma função é basicamente um bloco de código (um trecho de código separado pelos colchetes { }) com um nome. Veremos mais sobre isso quando entramos em funções. O importante agora é saber que main é o nome que damos a essa função onde colocamos nosso código (o texto em preto no programa acima).
A função main, porém, é especial e exige um pouquinho de atenção: ela é considerada o ponto de entrada de um programa. Para ser exato, caso não exista uma função main dentro de um programa, o compilador irá dar erro ao compilar (existem situações em que você não usará main em um arquivo C. Veremos isso ao falarmos sobre a programação com múlltiplos fontes e bibliotecas). Ela também tem uma construção razoavelmente padronizada, que é int main (int argc, char** argv). Você pode criar seu main com outras definições (ou cabeçalhos… lembram lá de cima?), mas alguns compiladores poderão acusar um alerta (uma mensagem que não é de erro, mas indica detalhes que podem dar problema) de que o main em questão sai do padrão do C. Em geral, o mainmain será escrito dessa maneira como indicamos e, caso você use uma IDE, o arquivo principal do seu projeto quase sempre terá um como o acima (falaremos mais sobre esse conceito de projeto no futuro).
Toda função em C é composta de três fatores, que explicaremos por alto (voltaremos mais nesse assunto quando falarmos de variáveis e funções), e a main não escapa desse padrão:
- Retorno: diz qual o valor final que a função irá devolver ao sistema uma vez que termine de executar;
- Nome: como ela é identificada pelo programador (quando o programa for compilado, esse nome é substituído por informações que indicarão onde ela ficará na memória do computador no momento da execução);
- Parâmetros: O que ela espera de informação de quem quer que a chame. Normalmente são representados por um tipo, que indica qual o tipo de valor que é esperado, e por um nome de parâmetro, que indica como esse parâmetro será usado pelo programador;
Na realidade, é possível especificar-se funções que não retornem nada e não tenham parâmetros. Veremos isso em funções e quando falarmos dos tipos de dados em C.
No caso específico do main, ela é do tipo int (que representa valores inteiros – sem casas decimais – tanto positivos quanto negativos), chama-se main e possui como parâmetros um int chamado argc e um char** chamado argv. Esses parâmetros, no caso de main representam:
- argc: o número de argumentos passados pelo programa e;
- argv: uma lista dos mesmos (na verdade, o argv é mais complexo que isso, mas não iremos aprofundar mais nele. Por enquanto, o importante é saber como ele trabalha);
OK… Até agora vimos que precisamos dizer ao C que funções de biblioteca iremos usar e qual é nossa função main, além de dizer a ele o que ele deve retornar ao sistema operacional e como ele deve receber parâmetros do sistema operacional. Agora vamos aos comandos reais.
printf(“Hello World!\n”); // Trouxemos ele do stdio.h
return (0);
Bem, esses dois comandos basicamente imprimem na tela o texto “Hello World!” na tela e encerram o programa. Mas esses comandos possuem detalhes que os diferenciam e que são importantes para entender o C:
O primeiro comando se chama printf (de PRINT Formatted, “imprimir com formatação”). Esse comando é parte das bibliotecas padrão do C, na verdade da stdio que já mencionamos anteriormente. Embora seja parte da biblioteca padrão, ele não é, vamos dizer assim, obrigatório para um compilador C. Na verdade, ele não é uma palavra reservada, ou seja, um comando que é obrigatório da existência em C e que não pode possuir outro igual. De certa forma, um desenvolvedor pode criar seu próprio comando printf e colocá-lo em uma biblioteca à parte, o que pode ser útil para, por exemplo, quando vai programar-se microprocessadores (que não possuem saídas visuais, portanto havendo necessidade de um printf). No caso, ele recebe um texto para imprimir na tela. Na verdade, esse texto pode possuir determinados conjuntos de caracteres especiais que indicam como deverá ser formatado o código em questão, aos quais chamamos de formatos e caracteres de controles (veremos mais adiante sobre isso). No caso, temos um caracter de controle (símbolos que representam caracteres que não são visualizáveis normalmente), o \n, que indica que deve-se pular uma linha ao terminar-se de imprimir esse texto. Portanto, o que printf vai fazer aqui é (1) escrever na tela “Hello World!” e (2) pular uma linha.
Quem leu até aqui com calma vai perceber que a “mágica” já está feita. Então o programa não acabaria aqui? Para que o segundo comando, o tal return (0)?
O comando return é parte das palavras reservadas do C. Uma palavra reservada normalmente representa um comando ou informação interna da linguagem de programação C cujo nome não pode ser usado para MAIS NADA a não ser pelo que é indicado. O padrão C determina um conjunto de palavras reservadas, como return, int ou float. Importante ver a diferença entre os dois: um programador poderia criar sua própria versão de printf, mas não poderia criar uma versão de return.
O return é um comando que normalmente encerra qualquer função, devolvendo o controle do programa para quem quer que tenha chamado a função. No caso de main, pode-se dizer que quem chama a função main (o programa principal) é o ssitema operacional, portanto é ele que vai receber de volta o controle quando o comando return for executado nesse caso, o que indica o final do programa. O 0 entre parênteses é um valor inteiro que o sistema pode usar para fazer testes (no caso de programas automatizados e afins). No nosso caso, como não existe, digamos assim, um “dar errado”, o valor 0 foi adotado mais por convenção, mas esse valor pode ser mudado se for necessário, embora não aprofundaremos esse tópico aqui. Importante a saber aqui é que (1) return é uma palavra reservada e não pode ter outro no C, (2) ele devolve o controle ao sistema operacional nessa situação e (3) ele pode devolver um valor que pode ser usado pelo sistema operacional. No momento, basta saber essa informação: nos aprofundaremos no funcionamento de return quando estudarmos funções.
OK… O programa está pronto. O que fazer com ele?
Diferentemente de algumas linguagens de programação mais atuais, como Python, PERL, PHP ou Ruby, o C é uma linguagem compilada. Isso quer dizer que precisamos usar um programa, chamado compilador, para traduzir as instruções do nosso programa (chamado de código fonte) para instruções que o computador compreenda e seja capaz de executar (chamado de código objeto ou binário). No caso, vamos utilizar o GCC para compilar o nosso programa: salve o código digitado como HelloWorld.c (na realidade, você pode escolher qualquer nome, mas é bom usar nomes claros, que identifiquem facilmente seu código) e abra um terminal (no Linux) ou um Prompt de Comando (no DOS/Windows). Entre no mesmo diretório onde você gravou o seu HelloWorld.c e digite o seguinte comando:
gcc -o HelloWorld HelloWorld.c
O comando em questão irá compilar seu código e irá gravar o binário em um arquivo. No caso do Linux especificamente, o padrão do GCC é gravar o binário em um arquivo de saída a.out. Utilizamos então a opção -o (output) pada gravar o código em um arquivo de saída chamado HelloWorld. Imaginando que tudo esteja correto, usamos o comando ./HelloWorld para executarmos nosso Hello World!
OK, você deve ter visto o Hello World! e se perguntado em algum momento “Não entendi!”. Algumas “brincadeiras” que você pode fazer para entender alguns conceitos que colocamos aqui:
- Comente ou remova a linha #include e veja o resultado ao compilar o programa;
- Modifique o nome main para alguma outra coisa e tente compilar o programa. Substitua o retorno int ou os parâmetros entre parênteses dele por void (sem retorno/parâmetro);
- Adicione mais linhas printf com o texto que você quiser e coloque ou não o caracter de controle \n e veja como o programa irá se comportar;
Essas “brincadeiras” irão permitir que você pegue alguns dos conceitos sobre os quais falamos até agora e irá divertir você. Caso tenha alguma dúvida sobre esse post, por favor, adicione nos comentários sua dúvida. Em especial, se a dúvida envolver erros no programa, copie a saída que deu na compilação e informe seu sistema operacional e compilador.
Semana que vem estarei postando mais coisas. A jornada de programação C apenas começou.
Começando as atividades
Publicado por em 05/11/2010
Olá todos!
A idéia desse blog é ser uma espécie de “super-curso” de programação em linguagem C. Inicialmente serão englobados tópicos básicos com a programação mais simples, mas no futuro a ideia é englobar os tópicos mais avançados, como orientação a objetos em C++, bancos de dados, GUI, bibliotecas dinâmicas, etc.
Algumas propostas desse blog:
Algumas propostas desse blog:
- Sempre trabalharemos em cima do ANSI C. Caso contrário, o post indicará se precisará ser usado um ambiente ou compilador específicos;
- Sempre que possível, serão utilizadas ferramentas livres. Em especial, o GCC (GNU C Compiler), que possui versões para Windows, Linux e outras plataformas;
- Embora nosso foco não seja ensinar a parte de Lógica de Programação, o que for necessário será explicado. Porém, se você nunca programou antes, talvez seja melhor procurar na Internet por informações sobre Lógica de Programação;
- Eu não sou um professor profissional! Isso ficando claro, vou dar todo apoio que estiver ao meu alcance;
- Eu sou um ser humano, portanto posso cometer erros. Comentários serão bem-vindos;
- Serei agnóstico quanto a IDEs (Integrated Development Environment, Ambientes de Programação). Embora possa fazer recomendações e, em alguns tópicos utilizar uma ou outra específica, cada um deverá usar a que lhe aprouver;
- Em especial quanto ao Windows: sou um usuário de Linux. Embora possa dar ajuda em tópicos específicos e recomendar ferramentas, não sou mais tão proficiente no uso de ferramentas no Windows como já fui. Para quem puder, o conselho é utilizar um SO livre, como o Linux ou o FreeBSD. Caso contrário, existem muitas informações para IDEs C em Windows. Particularmente recomendo o Dev-C++ da Bloodshed como IDE para C em Windows. Outra boa IDE é a Turbo C da Borland;
- Guerras Santas (tipo VI e EMACS) não serão apoiadas aqui. Como disse anteriormente: poderei recomendar ferramentas, mas acredito que a boa ferramenta é aquela que funciona bem com cada um;
Quanto a mim, sou formado em Desenvolvimento de Software pelas faculdades ASMEC (Ouro Fino – MG). Trabalho com computadores a pelo menos uns 6 anos e aprendi programação C com o antigo curso online livre de programação C mantido pela UFMG. Embora ele não desse diploma, ele dava uma coisa ainda mias importante: conhecimento. Apesar de desenvolver atualmente em outras linguagens, tenho uma paixão pela programação em C, onde fiz alguns dos meus melhores trabalhos na época da faculdade.
O objetivo é que você que está lendo aprenda mais sobre C e melhore seu entendimento de como um computador funciona.
De qualquer modo, esse é apenas um post inicial. Logo veremos programação de verdade.