Você está na página 1de 14

O C++ é uma linguagem construída sobre os fundamentos do C e comporta toda a

estrutura dele, ou seja, um programa escrito em C pode ser compilado ou editado


por um compilador de C++ com completa compatibilidade.

Tipos Básicos de Dados em C:

Os cinco tipos básicos de dados que o C suporta são:


- char;
- int;
- float;
- double;
- void.
Todos os outros tipos de dados são baseados ou variações desses cinco. Os
tamanhos e bytes de cada tipo pode variar de compilador para compilador, mas
pode-se ter uma média geral de tamanho, por exemplo o int possui 8 bits e o double
64 bits.
Esses tipos, com exceção do void, os dados básicos podem possuir modificadores
que alteram a estrutura básica de leitura e escrita dos mesmos:
- signed;
- unsigned
- long;
- short.
Note que o modificador signed reserva o primeiro bit da variável para sinalizar se o
número é negativo ou positivo e por isso faz com que tal implementação comporte
menos números. Utilizar o unsigned faz com que a variável comporte mais números,
porém apenas positivos. como exemplo um int unsigned comporta de 0 a 2^16
números.
Em geral, os números primitivos sem implementações costumam ser signed, mas
algumas implementações como o char, por padrão não possuem sinal.
Nomes de variáveis e funções em C são chamadas de identificadores e não podem
começar com números ou caracteres especiais, com exceção do “_”.
Os identificadores possuem um limite de caracteres que o compilador leva em
consideração na hora de identificá-los. Se utilizado como link externo, o compilador
só irá considerar as 6 primeiras letras que compõem o nome, já para uso interno é
possível utilizar até 32 caracteres.
As variáveis são ​locais ​na memória onde o programa poderá modificar esse valor.
As variáveis declarada dentro de uma função é denominada “Variável Local”. Em
algumas literaturas essas variáveis são referidas como “automáticas” pois podem ser
declaradas com a palavra-chave ​“auto”​. Variáveis locais são reconhecidas apenas
dentro do bloco de código onde são declaradas, ou seja entre as chaves “{}” da
função.
Variáveis locais são destruídas assim que o programa sai do bloco de código em
que ela foi criada.
variáveis locais devem ser declaradas no início do bloco e antes de qualquer
instrução. Em C++ essa restrição foi retirada e as variáveis podem ser declaradas
em qualquer parte do código.
Pode-se declarar variáveis locais como argumentos de uma função. Essas variáveis
serão usadas normalmente durante a função e serão destruídas depois.
Variáveis locais podem ser acessadas em qualquer bloco de função ou em qualquer
parte do programa.
Qualquer variável declarada fora dos blocos de função é uma ​variável global.
Se uma variável local for declarada com o mesmo nome de uma variável global, o
sistema utilizará a variável local quando tal nome for citado no código.
Variáveis globais ocupam espaço permanente na memória durante a execução do
programa, mesmo quando não estão sendo utilizadas, então seu uso deve ser
minimizado apenas para o indispensável.
O C possui dois modificadores de tipo de acesso:
const;
volatile.
Variáveis const, após receberem o valor inicial, não pode ter seu valor alterado. Ela
costuma ser declarada em funções onde os parâmetros passados não serão ou não
devem ser alterados. Uma observação interessante é que essa constante pode ser
alterada por “eventos externos”, como um periférico ou outro programa que esteja
compartilhando a mesma área de memória. usar o const é como usar permissões de
usuário para modificação, só que você define apenas quem não pode usar.
O comando volatile define ao compilador que a variável em questão pode sofrer
alterações a qualquer momento por eventos externos e sempre que ele for usá-la,
precisará conferir o seu valor. Por exemplo ao usar uma variável que possui a hora
do relógio, em tempo real, a cada segundo ela terá um valor diferente, valor esse
que é alterado pela rotina do relógio e não do programa que possui tal variável. O
volatile nesse momento deixa o programa ciente de que tal variável não possui valor
estável e deve ser conferido a cada utilização.
Pode-se utilizar o const e o volatile juntos em uma mesma instrução.

const volatile int numero = 1;

Classes de Armazenamento

O C possui quatro tipos de especificadores de armazenamento:


extern.
static.
register.
auto;
Esses especificadores informam ao compilador de que modo a variável deve ser
armazenada. Essa declaração vem antes de qualquer especificação do nome da
variável.
Extern - Serve para especificar que a variável criada é uma referência a uma variável
global de mesmo nome. Quando se utiliza vários arquivos para programar, pode-se
declarar todas as variáveis em um arquivo e usar o extern para fazer referências a
elas nos outros. Ele resolve o erro caso você declare duas variáveis globais com o
mesmo nome, seja em arquivos diferentes ou no mesmo arquivo.
Static - Normalmente, ao executar uma função, ela cria as variáveis locais e as
destrói logo que a função termina. Utilizar static em uma variável local, a torna
permanente, de modo que após encerrada a função ela mantém o seu valor, o qual
poderá ser utilizado novamente por essa função quando ela for chamada
novamente. Esse conceito é semelhante ao de variáveis globais, mas diferente
delas, variáveis com static são visíveis apenas dentro da função ou do arquivo que
foram declaradas.
Observe que uma variável static pode ter valor inicial atribuído a ela. esse valor só é
dado uma vez e na próxima execução da função a variável permanecerá com o valor
atual.
Declarar uma variável global como static faz com que ela seja vista apenas no
arquivo em que foi declarada, impedindo que esta seja vista e alterada por funções
em outros arquivos. Em outras palavras, o static encapsula as variáveis ao mesmo
tempo que mantém seu valor permanentemente na memória.
Register - Inicialmente o tipo register era usado para int e char, pedindo para que
essas variáveis fossem colocadas no registrador da cpu. Atualmente register
significa “acesse essa variável o mais rápido possível” e não te dá mais a certeza de
que tal variável será colocada no registrador. Esse tipo é apenas um otimizador e
funciona principalmente em variáveis que são muito requisitadas, como a variável
que controla um loop. Tenha em mente que em geral pelo menos duas variáveis
(use apenas int e char) irão ao registrador da cpu, por isso não declare qualquer
uma desse modo.
variáveis register não possuem endereço a memória, justamente por estarem no
registrador, então não aceita ponteiros.
Também são vetadas a criação de variáveis globais com o modificador register.

Inicialização de variáveis

Em geral as variáveis seguem o mesmo padrão do java:


Modificador Tipo nome = valor;
Variáveis não iniciadas possuem valores relativos. Variáveis Globais e variaveis
locais com modificado static, quando não iniciadas possuem valor 0. Variáveis locais
e variáveis register não iniciada possuem valor desconhecido (lixo da memória).
Constantes

As constantes são valores fixo colocados em uma variável e em C elas são bem
definidas:
Constantes que possuem um caractere (char) são definidas dentro de aspa simples
(‘ ‘).
Constantes do tipo int podem ter os modificadores short, long e unsigned.
unsigned int - valores de 0 a 65.535 (16 bits).
unsigned short int - O mesmo que unsigned int.
int - Valores de -32.767 a 32.767 (16 bits).
signed int - O mesmo que int.
short int - O mesmo que int.
signed short int - O mesmo que int.
long int - -2.147.483.647 a 2.147.483.647 (32 bits)
signed long int - O mesmo que long int.
unsigned long int - 0 a 4.294.967.295.

Constantes Char permitem signed e unsigned:


char - -127 a 127 (8 bits).
signed char - O mesmo que char.
unsigned char - 0 a 255 (8 bits).

Para variáveis com ponto flutuante, podemos utilizar float e double


float - usa 32 bits e usa até 6 dígitos depois da vírgula.
double - usa 64 bits e pode ter até 10 dígitos depois da vírgula;
long double - usa 80 bits e pode ter até 10 dígitos depois da vírgula.
Note que os pontos flutuante guardam números positivos, negativos e o bit onde
está a vírgula. Também não existe long float porque ele seria um double.

Em uma constante, se digitar um número qualquer, o compilador irá “deduzir” que


tipo de dado é aquele, ex: 4 é inteiro, 3,11 é float e ‘c’ é char. É possível especificar
o tipo de dado utilizando algumas notações ao fim da constante:
Se você colocar um “U” logo após um inteiro ele será tratado como unsigned;
Se colocar um “L” após um inteiro, será tratado como long int
Se usar um “F” após um número com vírgula ou inteiro, ele será tratado como float.
Se usar um “L” em um número com vírgula, ele será tratado como long double

Hexadecimais e Octais

É possível utilizar números em sistema hexadecimal e octal:


Antes do número deve-se colocar “0x” para hexadecimal e “0” para octal:
0x10 - é o número 16 representado em hexadecimal;
010 - é o número 9 representado em octal.

Strings

Strings são conjuntos de caracteres dentro de aspas duplas. por exemplo “oi eu sou
goku”.
Se você escrever “a”, está escrevendo uma string de um caractere, agora se
escrever com aspas simples ‘a’, está escrevendo uma constante de um único
caractere

Operadores

Em C temos mais operadores que em java: aritméticos, relacionais, lógicos e


bit-a-bit, além de operadores especiais para tarefas específicas.
A atribuição de valores em c funciona como em java, onde temos a variável no lado
esquerdo, o sinal = e a expressão ou constante no lado direito. A variável esquerda
costuma ser chamada de “lvalue” (left value ou só variável). A expressão ou
constante do lado direito é chamada de “rvalue” (right value) ou só expressão.
O C automaticamente tenta converter a expressão rvalue para o tipo da variável
lvalue, mesmo que implique em perder bits. Ex;

int x;
char ch;
ch = x;

No exemplo, o x possui 16 bits, mas o ch possui 8, então os 8 bits mais significativos


serão removidos e o ch terá o valor apenas dos 8 bits menos significativos.
É muito importante saber que a conversão varia de compilador para compilador, pois
alguns tratam char apenas como números positivos, outros tratam char maiores de
127 como números negativos. Por isso definir bem os tipos de cada variável e
reduzir ou controlar ao máximo a conversão do compilador EVITARÁ ERROS DE
PORTABILIDADE.

O C também permite atribuir um valor a várias variáveis de uma só vez. Ex:

x = y = z = 0;

Operadores Aritméticos:

São os mesmos de todas as linguagens:


+ - soma;
- - Subtração;
/ - divisão;
% - resto da divisão;
++ - incremento;
-- - decremento.

Usar incremento e decremento sozinhos não apresenta problemas se usar o


operador no lado esquerdo ou direito da variável:

x++;
ou
++x;

Porém usar incremento e decremento em uma expressão de atribuição pode gerar


valores diferentes pela posição do sinal:

x = 10;
y = ++x; // o Y recebe o valor 11, enquanto X recebe o valor 11.
x=10;
y = x++; // o Y recebe o valor 10, enquanto x recebe o valor 11.

Operadores Relacionais e Lógicos

Os operadores lógicos e relacionais são os seguintes:

>;
<;
>=;
<=;
==;
!=;
&&
||;
!.

O C não dispõe de um XOR (Ou exclusivo), mas é possível cria-lo com a seguinte
função:

(x || y) && !(x && y);


Operador bit a Bit

Operadores bit a bit utilizam cada bit da variável. Pelo meu entendimento, essa
funcionalidade é muito utilizada em assembly, desse modo como substituto o C
precisa suportar todas as operações deste.
Operações bit a bit podem ser utilizadas para calcular bits de paridade, receber bits
de um dispositivo externo, como modem ou teclado, criptografar arquivos e até
compactá-los com algum algoritmo.
Ele possui operadores lógicos e de deslocamento, mas como vejo pouca utilidade
para isso agora, não vou explanar sobre o assunto.

Operador “?”

Esse operador pode substituir um if-else de maneira bem simples. Ele segue a
estrutura:

Exp1 ? Exp2 : Exp3;

A Exp1 é executada e se a sentença for verdadeira, entã o Exp2 é rodado e o


resultado dela será o valor de retorno, agora, se Exp1 for falso, Exp3 que será
executada e retornará o seu valor. Exemplo:

int x = 1;
intx y;

y = x>9 ? 100 : 200;

Se X for maior que 9, então retornará 100, se X for menor que 9, retornará 200.
Nesse caso, y receberá o valor 200 porque 1 é menor do que 9.

Operadores de Ponteiros & e *

Ponteiro é o endereço de memória onde uma variável está localizada. Uma variável
que guarda o endereço desse uma certa variável na memória. Ponteiros tem 3
funções principais em c:
- Fornecer uma maneira rápida de referenciar elementos em uma matrix;
- Permitir que funções modifiquem as variáveis passadas como parâmetro;
- Suportar listas encadeadas e estruturas dinâmicas de dados;
o & é um operador unário que retorna o endereço de memória de uma variável.
unário significa que ele suporta retornar o valor de uma variável por operação:

int x=0;
int y;

y = &x;

Coloca o endereço de memória de x na variável y. note que y não receberá 0 e sim o


endereço da memória RAM que foi alocado naquela determinada instância do
programa.
O operador “*” seguindo as mesmas regras do & faz exatamente o contrário. Ele
pega o valor da variável, procura o endereço de memória correspondente àquele
valor e retorna o conteúdo daquele endereço:

int x = 0;

int *y = &x;

int z = *y;

X terá valor 0, Y terá o valor do endereço de memória da variável x e z receberá 0, já


que na o endereço de memória que y referencia possui o conteúdo “0”. Um ponto a
se observar é que o *y já deve ser colocado na declaração, para que o compilador
saiba que y se trata de um ponteiro.
Outro detalhe é que cada ponteiro precisa que seu tipo seja declarado, isso porque
cada tipo primitivo ocupa uma quantidade de bytes diferente na memória e ao
declarar esse tipo, o compilador automaticamente irá alocar espaço suficiente para
que esse ponteiro guarde o endereçamento de tamanho correto.

Operador em tempo de compilação sizeof

O sizeof retorna o espaço que a variável ocupa em bytes. O tamanho das variáveis
pode mudar de acordo com o sistema em que o programa está rodando e isso pode
gerar problemas em aplicações que exijam tamanhos definidos, como um banco de
dados que só aceita inteiros de 2 bytes. Se aparece um computador que registra
inteiros com 3 bytes, o programa irá apresentar erro. Desse modo, usar o sizeof para
testar os tamanhos das variáveis poderá gerar testes que impeçam ou solucionem
erros:

int x=0;
float f=1.2f;
char c='s';
double d = 1.2;

printf ("x = %d, f = %d, c = %d e d = %d... int = %d...",sizeof x, sizeof f, sizeof c,


sizeof d, sizeof (int));

Retorna os valores de uma variável do tipo inteiro, float, char, double e int
novamente. observe que não é necessário parênteses para usar o sizeof em uma
variável, mas é obrigatório em um tipo primitivo, como mostrado na última linha
“sizeof (int)”. Curiosamente os valores testados no meu computador foram:
x-4
f-4
c-1
d-8
int - 4

Operador vírgula “,”

O operador vírgula “,” serve para desencadear várias atribuições de valor em uma só
linha, é como dizer: “faça isso, agora isso, então isso, isso aqui agora …”. com no
exemplo

int x,y;
x = (y=3, y+1);

Nesse caso, y recebe o valor de 3 e X recebe o valor 4. Perceba que o valor que X
recebe sempre será o resultado da sentença mais à direita. Abaixo vou reescrever o
código de outra maneira, mas que vai dar o mesmo resultado:

int x,y;
y = 3;
x = y+1;

Perceba que “y+1” está gerando o resultado 4, mas esse valor é atribuído apenas
para X, y continua com o seu valor 3 inalterado. O operador vírgula pode ser usado
quantas vezes quiser:

int x,y, z;
x = (y=3, z=1, y+100, y+1);
printf ("x = %d, Y = %d e z= %d", x, y, z);
No código acima, veja que x só receberá o valor da última operação (y+1). enquanto
y+100 serve para nada. Ao fim, x=4, y=3 e z=1.
Um detalhe importante é que o operador de atribuição “=” tem maior prioridade que o
operador vírgula “,”, então, se os parênteses forem removidos da operação, X iria ser
igual a 3, pois o compilador iria atribuir o valor da operação mais próxima dele.

Operadores Ponto “.” e seta “>”

Operadores ponto e seta servem para referenciar um elemento dentro de um grupo


definido. o ponto é usado para referenciar o valor a partir de uma variável, já a seta
usado a partir de um ponteiro, por exemplo:

struct empregado {
char nome[80];
int idade;
float salario;
} emp;

struct empregado *p = &emp;

emp.salario = 1000.0f;
p->salario = 500.0f;

printf ("Salario = %f", emp.salario);

Criei uma estrutura chamada “empregado” e uma variável representante chamada


“emp”. Em seguida criei um ponteiro chamado “*p” que aponta para “emp”. Quando
eu quero usar a variável “salario” que está dentro de emp, pela variável emp eu uso
o ponto “emp.salario”, já quando eu quero usar o ponteiro *p para chegar à variável
salario, eu uso seta “p->salario”. O resultado do printf nesse caso será “salario =
500.000000”.

Ordens de avaliação das operações

Em geral, as expressões em C seguem da esquerda para a direita, mas se há uma


ou mais funções nessa expressão, a execução dessas funções não segue nenhuma
ordem definida, apenas os resultados:

x = F1() + F2();
Na função acima, x receberá o resultado de F1 somado ao resultado de F2, mas isso
não significa que a função F1 será executada antes da função F2, por isso é
importante evitar que uma função necessite da execução da outra em uma operação
dessas.

Conversão de Tipos em Expressões

Em uma expressão onde variáveis de tipos diferentes são misturadas, o compilador


realiza a conversão delas para o menor tipo de variável possível que comporte
ambas. Tome cuidado ao misturar tipos diferentes para que seu programa não
retorne resultados ou bugs inesperados.

Casts

Casts são operadores que forçam a conversão de um resultado de expressão para o


tipo definido. Ele pode ser declarado colocando o tipo desejado entre parênteses
antes da expressão:

(float) x/2;

A expressão acima força “x/2” a apresentar um resultado em formato float.

Espaçamentos e parênteses

Em C, espaçamentos e parênteses podem ser usados para tornar uma expressão


mais legível. Espaços adicionais não alteram o programa e parênteses servem para
definir a ordem das operações e organizar o código para ficar mais legível.

C reduzido

Todos os operadores binários em C possuem uma notação mais simples:

x = x+1;
x += 1;

As duas operações são iguais, mas o C reduzido é bastante utilizado em programas


profissionais. Outros operadores como - / e * também podem ser utilzados em forma
reduzida.

int x, y, z, a;
x = 10;
y = 5;
z = 100;
a = -1;

x += -9;
y -= 4;
z /= 100;
a *= -1;

printf ("X = %d, Y = %d, Z = %d e A = %d", x, y, z, a);

No exemplo acima, após a operação, o printF imprimirá todas as variáveis com o


valor 1. a intenção era que todos os cálculos de soma, subtração, divisão e
multiplicação retornassem 1.

Comandos de Controle do Programa

Verdadeiro ou Falso em C

Muitas funções realizam o teste de verdadeiro ou falso. Para C, um resultado


verdadeiro retorna qualquer valor diferente de zero, incluindo números negativos.
Para C, falso é apenas o valor 0.

Comandos de Seleção

Existem 2 comandos de seleção: if e Switch. Algumas vezes o ? pode substituir um


if.
A forma geral da expressão if é:]

if (condição) comandos;
else comandos;

onde comandos pode ser um ou mais comandos. o else é opcional. É importante


perceber que o if é uma condição que testa verdadeiro ou falso, como exemplo:

if (0) x++;
else x--;
O comando acima sempre executará o else, pois 0 representa falso. Essa premissa
pode ser utilizada para economizar código caso os operadores da condição possam
assumir valores numericos.
É comum a utilização de ifs e elses aninhados e em casos onde existem muitos
deles, a estrutura pode ficar bem feia esteticamente, por isso, gerlamente os
programadores aninham esses if-else-if da seguinte maneira:

if (condição)
comando;
else if (condição)
comando;
else if (condição)
comando;
else if (condição)
comando;
else comando;

Ainda falando de estilos, a expressão seguinte pode ser reescrita sem a condicional:

int b = -1;
if (b != 0) printf (“b não é zero”);

O codigo acima não é um código considerado bom, pois é redundante e pode ser
reescrito assim:

int b = -1;
if (b) printf (“b não é zero”);

o condicional if precisa de um valor zero para falso e diferente de zero para positivo,
desta forma, qualquer número de b que não for zero vai acionar a mensagem “b não
é zero”, caso b assuma o valor zero, essa mensagem não é executada e caso exista
um else aninhado a esse if, ele será executado.

O comando switch, diferente do if não trabalha com verdadeiro e falso, mas testa se
o valor base corresponde aos mesmos valores do case. Um detalhe interessante é
que se não usar o break dentro de um case, o programa continua testando os
próximos cases até o switch terminar.
Outra característica interessante é que você pode deixar cases sem comandos.
nesse caso ele executará o comando do primeiro case que possuir algum comando:

int i=1;
switch (i){
case 1:
case 2:
case 3:
i++;
break;
case 4:
i--;
break;
}

No código acima, se o i possui valor igual a 1 ou 2, ele executará o código “i++”, já


que o case mais próximos deles com algum comando é o case 3.
Outro detalhe é que variáveis locais só podem ser declaradas no início de um bloco
de código. Como você sabe, um bloco de código é delimitado por {}, então, a menos
que seja adicionado dois colchetes dentro de um case, variáveis locais só podem ser
declaradas no início do switch, antes do primeiro case.

Comandos de Interação

vamos ao laço For