# Curso de C++/Tipos de dados
## Tipos primitivos e compostos

C++ tem basicamente 6 tipos de dados primitivos, a saber: char, int, float, double, wchar_t e bool. São, respectivamente, os tipos: caractere (ASCII), inteiro, ponto flutuante de precisão simples, ponto flutuante de dupla precisão, caractere (UTF-16) e lógico ou booleano.
A partir desses tipos de dados, podemos "formar" outros tipos que serão denominados compostos. O tipo char, por exemplo, pode ser utilizado para criar strings de caracteres e mais adiante nesta seção analizaresmos também os tipos, vetores, matrizes, strings e structs.

## Tipos primitivos
### Caractere (ASCII)

O tipo de dados caractere é utilizado para armazenar letras, números e caracteres especiais. A declaração desse tipo dá-se através da palavra reservada char.
Ao total, são 256 caracteres (se unsigned char) que podem ser armazenados, dos quais os 128 primeiros fazem parte do conjunto ASC II. Você pode atribuir um caractere de duas formas, ao declarar um caracter sem as aspas simples, você deverá saber qual é o numero decimal correspondente. Por exemplo, se você digitar char caracter = 97, o console imprimirá a letra 'a'. Logicamente poderia ter declarado também dessa forma char caracter = 'a'.
É possível armazenar números inteiros pertencentes ao intervalo de -128 até 127. Se o contexto demandar pode realizar operações matemáticas entre esses números mas tendo em mente que se você for imprimir na tela do console, o resultado será o caracter correspondente. Por exemplo:
A saída deste trecho de código é:
Se um extrair o número do caractere, proceda assim:
A saída é:
Você poderá somar caracteres. Por exemplo: somar '2' com '/' equivale a letra 'a', pois 50 + 47 = 97.

### Caracter UTF-16

Existe o tipo wchar_t, que também é uma palavra reservada da linguagem C++. A declaração e o uso seguem as mesmas regras do tipo caracter, porém, o conjunto de caracteres que esse tipo suporta é muito maior (65.536 caracteres ao total). O conjunto de caracteres desse tipo é o Unicode codificado em UTF-16. Assim sendo, caracteres especiais como letras com acentuação, cedilha, e outros podem ser lidos e impressos.
Importante: Se você tentar imprimir um wchar_t na janela de console, você talvez não conseguirá (poderá aparecer um número de 0 até 65.535). Isso dependerá do conjunto de caracteres suportados pelo console. Entretanto, se você estiver realizando a leitura de dados digitados pelo usuário, esse tipo é mais adequado que char, pois o usuário poderá digitar alguns caracteres do teclado não suportados pelo tipo char.

### Inteiros

O tipo inteiro é um tipo bastante comum. Sua declaração dá-se através da palavra reservada int.
O tipo inteiro pode armazenar números que vão da faixa de -2.147.483.648 até 2.147.483.647 (um total de 2$^{32}$ números, ou 4.294.967.296). Você pode modificar esta faixa de valores usando as palavras reservadas signed, unsigned, short e long. Veremos estas palavras reservadas (chamadas de modificadores de intervalo) logo abaixo.
Importante: se você quiser utilizar um número que esteja além dessa faixa de valores, você deve utilizar o tipo double.

### Ponto flutuante (precisão simples)

Representa números fracionários e números reais (o que inclui os números inteiros). A faixa de valores varia de 1,2e-38 até 3,4e+38.
A declaração é feita através da palavra reservada float:

### Ponto flutuante (dupla precisão)

Igualmente ao tipo float, utilizado para números fracionários e reais, porém com precisão ainda maior. A faixa de valores varia de de 2,2e-308 até 1,8e+308.
A declaração é com a palavra reservada double:

### Lógico (booleano)

É o tipo mais simples, e pode armazenar apenas dois valores: verdadeiro ou falso. Para definir esses valores você deve proceder da seguinte forma:

## Sequências de escape

Especialmente no caso de uma variável tipo caracter ou string, você pode querer declarar, por exemplo, a própria aspa simples (utilizando \'), ou um caracter de nova linha (\n). Para isso você deve utilizar seqüências de escape. Todas elas vêm precedidas de uma barra invertida (\).
| Sequência | Equivale a |
| \n | Nova linha |
| \t | Tabulação |
| \b | Backspace |
| \" | Aspa dupla |
| \' | Aspa simples |
| \? | Ponto de interrogação |
| \\ | Barra invertida |
Exemplo:
A saída no console se pareceria com:

## Modificadores de faixa (ou intervalo)

Em C++ existem alguns modificadores de faixa (ou intervalo). Isso altera a faixa de valores suportada pela variável (mas a capacidade de armazenamento continua a mesma). São eles: short, long, unsigned e signed.

### Short

O modificador short, que é uma palavra reservada da linguagem, fixa a faixa dos valores inteiros (int) para -32.768 até 32.767. Quando você declara um inteiro, ele inicialmente é da faixa de um long int. Se você quer reduzir a faixa, use short int.

### Long

No subtópico "inteiros", dissemos que a faixa de um número inteiro é de -2.147.483.648 até 2.147.483.647. Na verdade, quando você declara um int, ele já é um long int. Ao declarar um long int, estamos apenas assegurando essa faixa de valores para int.
Long também pode ser utilizado com float. Nesse caso, a faixa de valores de float será a mesma de um double.

### Unsigned e signed

Estes modificadores alteram a faixa dos números inteiros (int) e caracteres (char) para valores somente positivos (unsigned) ou fixa a faixa deles em valores com sinal (signed). Por padrão, se você não declarar esses modificadores, as variáveis tipo inteiro e caracter ASCII serão signed.
Quando definimos que um inteiro terá valores sem sinal (unsigned), na verdade estamos dizendo que só estamos admitindo valores positivos. Isso altera a faixa de um inteiro para 0 até 4.294.967.295 - uma capacidade maior para números positivos). Se você declarar um valor negativo, ocorrerá um estouro de faixa.
Com signed, fixamos a faixa normal para um número inteiro.

## Estouro de faixa (range overflow)

Se você declarar um valor maior do que o tipo suporta, ocorrerá um estouro de faixa, também chamado range overflow.
Ao chegar no fim da faixa de valores para números inteiros e caracteres (incluindo wchar_t), você volta para o início ou para o fim da faixa. Exemplo:
A saída no console se parecerá com:
Para o tipo double, se você estourar a faixa de valores, ocorrerá um erro de compilação (indicando constant too big ou token overflowed internal buffer). Isso ocorrerá porque para double o número deve "caber" em 64 bits. Tente o seguinte e ocorrerá erro de compilação:

## Espaço ocupado na memória

As variáveis e constantes são armazenadas na memória e, dependendo do tipo, ocupam um espaço diferente nela. Abaixo segue o tamanho em bytes ocupado por cada tipo e a faixa:
| Sequência | Bytes ocupados | Faixa (ou intervalo) |
| short int signed int signed short int wchat_t signed wchar_t | 2 | -32.768 a 32.767 |
| unsigned short int unsigned wchar_t | 2 | 0 a 65.535 |
| int long int signed long int | 4 | -2.147.483.648 até 2.147.483.647 |
| unsigned int unsigned long int | 4 | 0 a 4.294.967.295 |
| char signed char | 1 | -128 a 127 |
| unsigned char | 1 | 0 a 255 |
| bool | 1 | true ou false |
| float | 4 | 1,2e-38 a 3,4e+38 |
| double long float | 8 | 2,2e-308 a 1,8e+308 |

## Sizeof

Sizeof é um operador unário de C++ que é utilizado semelhantemente a uma chamada de função. Sizeof será muito importante em tópicos posteriores, porque retorna o tamanho de memória que um tipo de dados ocupa. Para utilizá-la, a sintaxe é sizeof([tipo/variável/constante/objeto]). Exemplo:
A saída no console se parecerá com:
Sizeof é uma palavra reservada da linguagem C++.

## Typedef

Se você quiser abreviar a declaração de um tipo de dados, você pode usar typedef. Esta função também server para criar uma estrutura de dados, que veremos logo abaixo. Typedef é uma palavra reservada da linguagem.
Para abreviar a declaração de um tipo de dados, faça o seguinte:

## Conversões

Você pode realizar conversões entre os tipos de dados. Existem dois tipos de conversão: as implícitas e as explícitas. Vejamos cada uma.

### Conversões implícitas

Conversão implícita é aquela realizada pela linguagem sem que o programador tenha explicitamente solicitado que ela a fizesse (entretanto, fica subentendido que você deseja fazer a conversão, por isso ela é chamada de implícita). C++ converte implicitamente a maioria dos tipos de dados. Os principais são:
* De inteiros para caracteres e ponto flutuante.
* De ponto flutuante para inteiro e caracter.
* De caracter para inteiro e ponto flutuante.
Exemplo (de caracter para inteiro e ponto flutuante):
Importante: Quando convertemos ponto flutuante para inteiros e caracteres, a parte fracionária é desprezada. Ao realizar a conversão poderá ocorrer um estouro de faixa, alterando o valor.

### Conversões explícitas

Na conversão implícita você solicita que a linguagem realize a conversão, de forma explícita. C++ converte implicitamente a maioria dos tipos de dados mas, para certificar-se de que fará a conversão correta, você pode fazer conversões explícitas (cast), conforme o exemplo que segue:

## Tipos de dados compostos

Os tipos de dados compostos derivam dos tipos primitivos e são úteis para resolver uma grande quantidade de problemas. Se quisermos, por exemplo, armazenar uma frase inteira? Ou, por exemplo, os tempos dos atletas que disputaram uma corrida?
Para resolver esses problemas podemos criar tipos compostos, que atendem a uma função específica no seu programa. Veremos a seguir 4 principais tipos compostos de dados que podemos criar em C++ e que lhe ajudará a solucionar a maioria dos problemas.

### Vetores

No código acima criamos um registro que armazena 10 números de ponto flutuante na memória. Para criar um vetor, declaramos o tipo de dados, o nome do registro e, entre colchetes, a quantidade de registros que queremos armazenar.
Para acessar, utilizamos o nome do registro com o índice do registro entre colchetes. É muito importante ter em mente que os índices começam em 0 (zero)! Sendo assim, um registro de, por exemplo, N coisas, tem índices de 0 até N-1.
A sintaxe para declarar um vetor é:
Ao declarar a quantidade de registros, você pode fazê-lo digitando um número inteiro ou colocando ali o nome de uma constante inteira. Por exemplo:
Isso é útil quando criamos vários vetores, todos com o mesmo tamanho. Se, porventura, for necessário modificar o tamanho do vetor, você pode fazê-lo simplesmente alterando o valor da constante.
Você pode utilizar o operador sizeof para obter o tamanho de um registro. A saída no console do código acima geraria a seguinte saída no console:

### Matrizes

Matrizes são, conceitualmente, um vetor de vetores. A declaração de uma matriz se dá semelhantemente a de um vetor. Ex:
Note que os índices, tanto das colunas quanto das linhas, começam em zero também. O primeiro colchete indica a coluna e o segundo a linha.
Podemos criar matrizes com mais dimensões. Exemplo:
Todas as regras válidas para vetores valem para matrizes.

### Strings

Strings são vetores de caracteres. Ainda que sejam vetores, as strings em C++ possuem algumas particularidades.
A saída no console se parecerá com:
Aprenderemos a utilizar strings e manipulá-las no tópico Entrada e saída, Biblioteca <string>.

### Structs

Structs, do inglês structure, são utilizadas para criar estruturas de dados: tipos compostos de dados que, em conjunto, formam uma única estrutura.
A declaração e o uso de structs é bastante simples.
A saída no console se parecerá com:
A declaração da struct não precisa estar, necessariamente, no início do código (antes da main). Poderá estar dentro de um bloco de chaves (), mas nesse caso seria como uma struct local: só poderia ser acessada dentro deste bloco. Pelo código podemos notar a sintaxe da declaração de uma struct:
Para acessar os atributos, a sintaxe é a seguinte:
Note que podem ser criados vetores e matrizes de structs. Isso é útil, quando, como no exemplo dado, queremos criar o registro de alunos (de uma turma), por exemplo.
Podemos ainda "formatar" as estruturas de acordo com necessidades especificas, vejamos os exemplos:

## Revisão

Neste tópico discutimos os tipos de dados possíveis em C++: os tipos primitivos e os compostos. Entretanto, podemos criar tipos e estruturas de dados através de classes, mas este assunto será abordado inteiramente em um tópico posterior.
Antes de passar para o próximo tópico, certifique-se de ter compreendido e memorizado o que segue:
* A sintaxe da declaração e acesso aos tipos primitivos de dados.
* Os modificadores de acesso: o que eles fazem e a faixa para qual alteram cada tipo de dados.
* O que é estouro de faixa (range overflow), e o que acontece quando isso ocorre.
* A função do operador unário sizeof.
* Os erros comuns que geram erro de compilação, citados nos comentários dos códigos.
* O que é conversão implícita e explícita e como fazê-las.
* O que são tipos compostos de dados, e a sintaxe da declaração e acesso a vetores, matrizes e strings.
* Structs: o que são, a declaração e o acesso aos atributos.
* Clique aqui para avançar para o próximo tópico: Operadores