Introdução à sintaxe do C
Hello mundo em C
Hello_mundo.c
#include <stdio.h> // importação de biblioteca externa
int main () { // declaração da função main
printf("Hello mundo!!\n"); // função que escreve coisas na tela
return 0; // retorno da função
} // fim da função
Compilando o arquivo
linux/BSD/Mac OSX
gcc Hello_mundo.c -o hello
Windows
gcc Hello_mundo.c -o hello.exe
Todos os exemplos e desafios são compilados da mesma forma: gcc <arquivo.c> -o <nome do binário>
Caso o arquivo não compile com o
gcc
use og++
Executando o arquivo (lembre-se de estar no mesmo diretório do arquivo compilado)
linux/BSD/Mac OS X
./hello
Windows
hello.exe
Saída
Hello mundo!!
Todos os exemplos e desafios são executados da mesma forma mostrada acima, apenas troque o
hello
pelo nome do binário gerado.
No programa apresentado, nós vimos a estrutura básica de todo programa em C, no qual temos a importação do módulo stdio.h
(conjunto de funções para saída e entrada de dados), a função main
(função que é chamada na execução do programa), e os comandos da função que serão executados (tudo o que está entre {
e }
), que no nosso caso é o printf
(função de saída de dados que escreve texto na tela), e por fim o return
que diz para o sistema operacional se ocorreu tudo como o planejado na execução da função main
.
Notem que todos os comandos dentro do bloco (tudo o que está entre
{
e}
) da funçãomain
estão separados por;
, caso você se esqueça desse caractere, o seu programa não será compilado.
A função main
é essencial para o funcionamento de programas escritos em C, pois ela é a função que é chamada na execução do programa.
Mas, caso você ainda não tenha entendido, eu vou explicar de uma maneira mais simples.
Imagine que Terezinha, uma cozinheira muito habilidosa, vai preparar um ovo frito.
A primeira coisa que ela faz é pegar uma frigideira com óleo e colocar no fogo. Depois, ela vai quebrar o ovo dentro da frigideira e jogar sal. Depois de todos os passos feitos ela dá uma olhada para saber se o ovo queimou, ou se tudo ocorreu como desejado.
Terezinha simboliza o sistema operacional executando um programa feito em C. a frigideira é a função main
, a fritura do ovo é executada pela frigideira.
Terezinha sabe se o ovo está queimado ou não porque a frigideira dá um retorno (quando o ovo está mais escuro, ela sabe que queimou): esse é o papel do comando return
da função main
.
A partir daqui, você vai se deparar com diversos códigos soltos (para economizar espaço), mas quando for testá-los na sua máquina, coloque-os dentro da função
main
:
#include <stdio.h>
int main(){
<comandos apresentados>
return 0;
}
O ;
é o que delimita o fim de um comando no C e ele ignora os espaços ou quebras de linha em excesso antes do ;
, logo, isso:
printf
(
"Hello mundo!!\n"
)
;
É o mesmo que isso:
printf("Hello mundo!!\n");
Então as regras para o uso do
;
são:
- Devem estar no final das linhas com comandos.
- Não devem estar em linhas que começarem com
#
.- Não devem estar em linhas que terminam com chaves se essas chaves pertencem a blocos de código (pois existem outras estruturas que usam chaves).
Mas mesmo sabendo disso tome cuidado com os espaços, pois em alguns casos muito específicos a falta deles pode confundir o compilador, por exemplo:
int i = -2 - -3;
não se preocupe com o
int i =
, saiba apenas quei
é uma variável, isso será explicado mais tarde...
O -3
é um número negativo, mas o -
entre -2
e -3
é o sinal de subtração, se não houvesse espaço entre o -
solto e os outros números, o programa acima não seria compilado pois o C não saberia o que você quer que ele faça.
Comentários
Comentários são “anotações ou esclarecimentos” escritas(os) no código para descrever a função de algo e geralmente são úteis quando se quer analisar algum código antigo seu, ou o código de outra pessoa. Os comentários sempre são ignorados pelo compilador, eles são apenas para auxiliar o programador.
// comentários de uma única linha
/*
comentários
de
multiplas
linhas
*/
É sempre aconselhável o uso de comentários, principalmente se você pretende fazer um projeto open source (como já dito, projetos de código aberto).
Variáveis
Imagine um armário com diversos espaços com um nome para identificar, alguns só cabem esferas e outros só cabem cubos. Toda vez que alguém quer um espaço no armário deve pedir para o dono, mas o dono só reserva o espaço se pedir da maneira correta, que é:
<tipo do espaço> <nome do espaço> com <coisa> dentro
Exemplos:
esfera bola_de_futebol com ⚽ dentro
cubo dado com 🎲 dentro
O armário é a memória do seu computador, os espaços são as variáveis e o nome em cada espaço é o nome da variável, que só consegue armazenar tipos específicos de dados, no exemplo são esfera
, cubo
ou boneca
, e a situação descrita para a reserva de um espaço é a declaração:
// <tipo do espaço> <nome do espaço> <dado>
int numero = 80;
No exemplo acima, reservei um espaço que só guarda números inteiros (int
) com o nome numero
e com o valor 80
dentro. E no C, existem 3 tipos primitivos, ou seja, 3 tipos de dados básicos, o int
, o float
e o char
.
int numero = 80;
char caractere = 'A';
float numero_real = 99.9;
Variáveis do tipo int
recebem números sem ponto, como 2
, 8
ou 234
enquanto as do tipo float
recebem números com ponto como 2.5
, 8.3
ou 23.0
, já variáveis do tipo char
recebem um caractere, apenas um , logo, se tentar colocar um "hello"
ou até mesmo um "h"
, ele vai retornar um erro, pois todo e qualquer caractere entre "
é uma string enquanto um char
é um único caractere entre '
, não se preocupe com as strings, por enquanto...
E se você deseja alterar o valor da variável, só precisa colocar o nome da variável recebendo o valor:
int i = 5; // declaração da variável "i" valendo "5"
i = 92; // agora a variável vale 92
Esse exemplo acima serve para todos os tipos primitivos, mas lembre-se de colocar valores do tipo certo na variável. Se você declarou uma variável inteira, na hora de alterar o valor, tem que trocar por um inteiro.
Além disso, também existe o tipo double
que é descendente do tipo float
, mas com mais capacidade de espaço... “Mas como assim espaço? Números não são infinitos?” ... Os números são infinitos sim, mas a memória ram do computador não é, e mesmo que fosse, seria um desperdício liberar um espaço infinito para uma única variável, então todas as variáveis dentro do C tem um espaço limitado.
Cada variável ocupa uma certa quantidade de bytes na memória ram:
/*
um byte tem 8 bites e um bite só pode ser 0 ou 1, isso quer dizer que
sempre que o computador reserva 1 byte ele está reservando 8 espacinhos
com zeros e ums.
*/
int inteiro = 0; /* -> 4 bytes -> você só consegue colocar
números de -2147483648 a 2147483647,
pois se o número estiver fora desse
intervalo ele teria mais de 4 bytes.
*/
char caractere = 'A'; /* 1 byte -> só aceita um caractere,
porque um caractere ocupa um
byte.
*/
float real = 3.14; /* 4 bytes -> só suporta valores entre
10E-38 e 10E38 (isso significa 10
vezes 10 elevado a -38 a 38, o "E"
substitui o "vezes 10 elevado a"
para simplificar para o computador).
*/
double real_2 = 10E49; /* 6 bytes -> o double tem mais
espaço que um float
e por isso pode suportar
números entre 10E-4932 e
10E4932
*/
Essas quantidades demonstradas acima não são iguais em todas as arquiteturas (tipo de processador), isto quer dizer que se o seu computador é de 32 bits o tamanho das variáveis pode ser diferente de um de 64 bits, logo, para que você tenha certeza do tamanho delas (em bytes) é só usar o
sizeof
:
int inteiro;
int tmh_inteiro = sizeof inteiro; // tamanho da variável inteiro
Caso você não queira criar uma variável unicamente para pegar o seu tamanho é possível usar o
sizeof
para pegar o tamanho do tipo diretamente:
int tmh_inteiro = sizeof (int); // tamanho da variável inteiro
Note que o tipo está entre parênteses, isso é obrigatório ou o C vai achar que você está se referindo a uma variável.
E a galera que já conhece um pouco de programação deve estar se perguntando “Mas e os booleanos? No C não existe verdadeiro e falso?” sim, mas no C o int
faz esse papel, sendo que o 0 equivale a falso e o 1 equivale a verdadeiro.
As variáveis em C (e acho que em todas as linguagens) têm algumas regras quanto à escolha do seu nome, estas regras são:
- Variáveis não podem iniciar com números;
- Variáveis não podem ter espaços (substitua os espaços por
_
); - Variáveis só podem conter letras, números e travessões (evite usar letras com acento também);
- Variáveis não podem ser iguais à palavras reservadas.
Palavras reservadas do C:
auto break case char if const continue default do double else enum
extern float for goto if int long register return short signed void
sizeof static struct switch typedef union unsigned volatile while
Sendo assim, variáveis com nomes como 2letras
, char
, jo%ao
ou peso da pedra
estão erradas, mas variáveis como _2letras
, Char
, joao
ou peso_da_pedra
estão certas, e tome muito cuidado com o uso de maiúsculas e minúsculas, pois o C as diferencia, portanto, char
é uma palavra reservada, mas Char
não é.
Uma forma de atribuição do C que pode ser meio confuso pode ser dado pelo seguinte código:
int c = 80;
int i = (c = 30); // i vai valer 30
c = c + (i = 20); // c vai valer 50
Isso ocorre, porque o C atribui o
30
a variávelc
e retorna o valor parai
.
Conflito entre tipos
Um problema (na minha opinião) do C é a forte tipagem, que significa que os tipos têm que ser respeitados a todo o custo, logo, se queremos que um dado seja transformado em outro, precisamos fazer conversões de tipos.
int Um = (int) 1.5; // apenas o 1 será atribuído
Quando você atribui a uma variável um valor que pertence a outro tipo, o C vai converter isso para o tipo da variável:
int i = 1.5; // i vai valer 1
float f = i / 3; /*
o resultado dessa divisão seria 0.3333...
Mas como os dois números são inteiros o
resultado é 0, e por isso é atribuído
o valor 0.0 à variável f
*/
Portanto, sempre use variáveis do mesmo tipo para operações matemáticas, caso sejam de tipos diferentes use a conversão de tipos.
Para que o resultado seja atribuído da forma correta, você deve fazer a conversão de tipos ou usar o tipo certo no calculo:
float f = 1.0 / 2.0; // usando o tipo certo (float)
f = (float) 1 / (float) 2; /* usando a conversão de tipos
também conhecida como
"type cast"
*/
int n = 5, n1 = 2;
f = n / n1; // f = 2.0
f = (float) n / (float) n1; // f = 2.5