Introdução às Linguagens C e C++
Embora C e C++ compartilhem uma herança comum, elas possuem distinções importantes. Em C, a declaração de variáveis geralmente precisa preceder seu uso dentro de um bloco de código. C não inclui a biblioteca <iostream> e, consequentemente, não utiliza cin ou cout para operações de entrada/saída, nem requer using namespace std;.
C++, por outro lado, é uma linguagem orientada a objetos que oferece maior flexibilidade na declaração de variáveis e um conjunto rico de bibliotecas padrão, como <iostream> para I/O e <algorithm> para operações comuns em coleções de dados.
Tamanhos de Tipos de Dados Básicos
A representação de dados na memória é fundamental. Um byte consiste em 8 bits. Os tamanhos de tipos de dados comuns podem variar ligeiramente entre sistemas, mas tipicamente:
- Um
intocupa 4 bytes. - Um
doubleocupa 8 bytes.
Representação Binária de Números
Números inteiros são frequentemente representados usando o complemento de dois. Por exemplo, em um sistema de 16 bits:
- O valor 32767 é representado como
0111 1111 1111 1111. - O valor -32768 é representado como
1000 0000 0000 0000.
O bit mais significativo (o primeiro bit à esquerda) atua como um indicador de sinal: 0 para positivo e 1 para negativo.
Fundamentos da Sintaxe
Comentários no Código
Comentários são essenciais para documentar o código. Em C e C++, existem duas formas principais:
- Comentário de linha única: Começa com
//e se estende até o final da linha. - Comentário de múltiplas linhas: Delimitado por
/*no início e*/no final.
Operações de Entrada e Saída
As linguagens C e C++ oferecem diferentes mecanismos para lidar com a entrada e saída de dados:
- C++ (
<iostream>): Usastd::cinpara entrada estd::coutpara saída, com operadores>>e<<, respectivamente. - C (
<cstdio>): Utilizascanfpara entrada formatada eprintfpara saída formatada. Estes são geralmente mais rápidos para I/O em massa.
Para caracteres individuais, as funções getchar() e putchar() (da biblioteca <cstdio>) são usadas. Por exemplo, putchar(66); exibirá o caractere 'B' (ASCII 66).
Especificadores de Formato (printf / scanf)
Ao usar scanf e printf, especificadores de formato são cruciais:
%s: Para strings de caracteres (scanfpara strings para ao encontrar espaço ou Enter).gets(): Lê uma linha inteira, incluindo espaços, até encontrar um Enter (Nota:gets()é perigoso e desaconselhado devido a vulnerabilidades de estouro de buffer; prefirafgets()oustd::getlineem C++).%c: Para caracteres (char). Caracteres literais são definidos com aspas simples, e.g.,'A'.%f: Para números de ponto flutuante (float).%lf: Para números de ponto flutuante de precisão dupla (double).%lld: Para inteiros longos (long long).
Formatação de saída:
%Nd: Alinha um inteiro à direita em um campo deNcaracteres. Ex:%5dpara15resulta em15.%-Nd: Alinha um inteiro à esquerda em um campo deNcaracteres. Ex:%-5dpara15resulta em15.
float valorDecimal = 45.6789f;
printf("Valor formatado: %12.3f\n", valorDecimal);
// Saída: Valor formatado: 45.679
// O número é impresso com 3 casas decimais e ocupa um campo total de 12 caracteres.
O caractere de tabulação \t avança a saída para a próxima parada de tabulação, alinhando o texto em colunas.
Precedência de Operadores
A ordem em que as operações são avaliadas é definida pela precedência dos operadores. Alguns grupos de operadores comuns incluem:
- Aritméticos:
+,-,*,/,%,++,--. - Lógicos:
&&(E),||(OU),!(NÃO). - Atribuição:
=,+=,-=,*=, etc.
Macros com #define
Diretivas de pré-processador como #define realizam substituição de texto antes da compilação. Elas podem ser usadas para definir constantes ou "macros com parâmetros".
#define SOMA_VALORES(a, b) ((a) + (b))
#define DOBRO(val) ((val) * 2)
Embora úteis, macros podem introduzir problemas de depuração e segurança de tipo. Em C++, funções inline ou const são geralmente preferíveis. Uma macro pode ser desdefinida com #undef para limitar seu escopo.
Tipos de Dados Fundamentais
C e C++ oferecem uma variedade de tipos de dados para armazenar diferentes tipos de informações:
void
O tipo void indica a ausência de tipo. É usado em funções que não retornam valor ou para ponteiros genéricos (void*).
bool
Representa valores lógicos: true ou false. Geralmente ocupa 1 byte.
char
Armazena um único caractere. Caracteres literais são delimitados por aspas simples, como 'X'. As sequências de escape são caracteres especiais:
\n: Nova linha.\\: Barra invertida literal.\': Apóstrofo literal.\0: Caractere nulo (frequentemente usado como terminador de string em C).
A aritmética com caracteres é possível devido à sua representação ASCII (ou equivalente). Por exemplo, para converter uma letra maiúscula para minúscula, pode-se adicionar 32 ao seu valor ASCII.
float e double
Usados para números de ponto flutuante (com casas decimais):
float: Precisão simples, geralmente 6-7 dígitos significativos. Literaisfloatpodem ser sufixados comf, e.g.,1.27f.double: Precisão dupla, geralmente 15-16 dígitos significativos. É o tipo padrão para literais de ponto flutuante sem sufixo.
Números podem ser expressos em notação científica, como 1.23E3 (equivalente a 1.23 * 10^3 ou 1230).
Tipos Inteiros com e sem Sinal
Tipos inteiros podem ser signed (com sinal, permitindo números positivos e negativos) ou unsigned (sem sinal, apenas não negativos).
short: Geralmente de -32768 a 32767.unsigned short: Geralmente de 0 a 65535.int: Geralmente de -2.147.483.648 a 2.147.483.647.
Operador Condicional (Ternário)
Uma forma concisa de expressar uma condição:
condição ? expressão_se_verdadeira : expressão_se_falsa;
Se a condição for verdadeira, o resultado é expressão_se_verdadeira; caso contrário, é expressão_se_falsa.
int a = 10, b = 20;
int maior = (a > b) ? a : b; // 'maior' será 20
Estruturas de Controle
Estruturas de Repetição (Loops)
Utilizadas para executar blocos de código repetidamente. Podem ser combinadas com break (para sair do loop) e continue (para pular para a próxima iteração).
for: Ideal para um número fixo de iterações.while: Repete enquanto uma condição é verdadeira (pode não executar se a condição for falsa desde o início).do...while: Garante que o bloco de código seja executado pelo menos uma vez, e depois repete enquanto a condição for verdadeira.
Estrutura Condicional switch
Usada para selecionar um de muitos blocos de código a serem executados, com base no valor de uma expressão inteira.
int opcao = 2; // Exemplo de variável de controle
switch (opcao) {
case 1:
// Bloco de código para a opção 1
printf("Opcao selecionada: Um\n");
break; // Importante para evitar "fall-through"
case 2:
// Bloco de código para a opção 2
printf("Opcao selecionada: Dois\n");
break;
default:
// Bloco padrão, executado se nenhum dos casos anteriores corresponder
printf("Opcao desconhecida\n");
}
É crucial incluir break; após cada case para evitar que a execução "caia" para os case seguintes.
Arrays (Vetores)
Arrays são coleções de elementos do mesmo tipo, armazenados em posições contíguas de memória. A indexação em C e C++ é baseada em zero (o primeiro elemento tem índice 0). É importante estar atento aos limites do array para evitar erros de acesso à memória.
Estruturas (struct)
Estruturas permitem agrupar diferentes tipos de dados sob um único nome, criando um tipo de dado composto.
struct Estudante {
int matricula;
float media;
char nome[50]; // Um array de char para o nome
};
// Criação de uma variável do tipo Estudante
Estudante alunoPrincipal;
alunoPrincipal.matricula = 1001;
alunoPrincipal.media = 8.5f;
strcpy(alunoPrincipal.nome, "Carlos"); // Usando strcpy para atribuir uma string
// Criação de um vetor de estruturas
Estudante turma[30];
turma[0].matricula = 2001;
turma[0].media = 7.8f;
strcpy(turma[0].nome, "Ana");
Conversão de Tipos
A conversão de tipos pode ocorrer implicitamente (coerção) ou explicitamente (casting). Ao converter um número de ponto flutuante para um inteiro, a parte fracionária é truncada (descartada). Em expressões com tipos mistos, um tipo de "menor" precisão pode ser promovido ao tipo de "maior" precisão para evitar perda de dados.
Strings Estilo C
Strings em C são arrays de caracteres terminados por um caractere nulo ('\0').
scanf("%s", nomeArray);: Lê uma string para um array de caracteres.gets(nomeArray);: Lê uma linha inteira (desaconselhado).puts("Mensagem");: Escreve uma string seguida de uma nova linha.
Funções
Funções de Manipulação de Strings (C-style)
A biblioteca <string.h> (C) ou <cstring> (C++) oferece funções para manipular strings de caracteres:
strlen(s): Retorna o comprimento da strings(sem contar o'\0').strcat(destino, fonte): Concatena a stringfonteao final dedestino.strcpy(destino, fonte): Copia a stringfonteparadestino.strcmp(s1, s2): Compara lexicograficamentes1es2. Retorna um valor negativo ses1 < s2, zero ses1 == s2, e positivo ses1 > s2.
Passagem de Parâmetros por Referência
Por padrão, parâmetros são passados por valor para funções, significando que uma cópia do valor é usada e o argumento original não é modificado. Para modificar o argumento original, pode-se usar passagem por referência (em C++ com &) ou ponteiros (em C e C++).
void trocarValores(int &val1, int &val2) {
int temp = val1;
val1 = val2;
val2 = temp;
}
Quando um array é passado para uma função, o que é realmente passado é o endereço de seu primeiro elemento. Isso significa que modificações dentro da função afetam o array original.
Recursão e Iteração
- Iteração (Abordagem Bottom-Up): Resolve um problema construindo a solução a partir de casos base conhecidos, geralmente com loops.
- Recursão (Abordagem Top-Down): Resolve um problema dividindo-o em subproblemas menores da mesma natureza. É crucial ter um caso base para parar a recursão. Técnicas como "memoização" (caching de resultados de subproblemas) podem otimizar funções recursivas.
Standard Template Library (STL)
A STL em C++ é uma coleção de classes e funções de template que fornecem estruturas de dados e algoritmos comuns.
std::vector
Um vector é um array dinâmico que pode redimensionar-se automaticamente. Ele armazena elementos de um tipo específico (T) e oferece acesso aleatório.
std::vector<T> meuVetor;: Declara um vetor.Tpode serint,std::string, ou até mesmo outrostd::vectorpara arrays multidimensionais.meuVetor.empty(): Retornatruese o vetor estiver vazio.meuVetor.size(): Retorna o número de elementos no vetor.meuVetor.push_back(elemento): Adiciona um elemento ao final.meuVetor.pop_back(): Remove o último elemento.meuVetor[n]: Acesso direto ao elemento na posiçãon.meuVetor.begin()emeuVetor.end(): Retornam iteradores para o início e logo após o final do vetor, respectivamente.- Algoritmos como
std::sort(meuVetor.begin(), meuVetor.end())podem ser usados para ordenar o vetor. std::unique(meuVetor.begin(), meuVetor.end()): Remove elementos adjacentes duplicados (o vetor deve estar ordenado para que funcione corretamente).
Outros Componentes da STL
A STL inclui uma vasta gama de contêineres e algoritmos:
- Contêineres Sequenciais:
std::deque(fila de duas extremidades),std::list(lista duplamente encadeada),std::stack(pilha),std::queue(fila),std::priority_queue(fila de prioridade). - Contêineres Associativos:
std::set(conjunto ordenado de valores únicos),std::multiset(conjunto ordenado com valores duplicados),std::map(mapa/dicionário chave-valor único),std::multimap(mapa chave-valor com chaves duplicadas). - Utilitários:
std::string(para strings modernas em C++),std::pair(para agrupar dois valores),std::bitset(para manipular sequências de bits).
Muitos contêineres compartilham funções comuns como begin(), end(), size(), empty(), clear() (para remover todos os elementos), e swap() (para trocar o conteúdo com outro contêiner do mesmo tipo).
Além disso, o cabeçalho <algorithm> oferece funções genéricas como std::find, std::reverse, std::lower_bound (retorna um iterador para o primeiro elemento não menor que um valor) e std::upper_bound (retorna um iterador para o primeiro elemento maior que um valor).