Buscar

Linguagem de Programação C++

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 43 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 43 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 43 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Linguagem de Programação	C++
Básico�
Sumário
	Linguagens de programação – História de C	____________
	3
	Características da linguagem C	______________________
	4
	A linguagem C++	________________________________
	5
	Fundamentos de C++	___________________________
	6
	Dados Padrões	________________________________
	10
	Tipos definidos e estruturas de dados	_________________
	11
	Modificadores de dados	___________________________
	13
	Conversões de dados	___________________________
	14
	Classes de armazenamento	______________________
	15
	Matrizes	_____________________________________
	16
	Operadores	_____________________________________
	17
	Controle de fluxo	________________________________
	22
	Ponteiros	_____________________________________
	27
	Funções	_____________________________________
	30
	Diretivas do pré-processador	______________________
	36
	Arquivos	_____________________________________
	37
	Introdução ao modo gráfico	______________________
	41
	Palavras reservadas	___________________________
	43
�
Linguagens de programação – História de C
O computador é uma ferramenta poderosa que possui as mais variadas aplicações no mundo moderno. Encontramos sistemas controlados por computadores em quase todas as áreas do conhecimento humano, como telecomunicações, indústrias, internet, medicina, etc. Entretanto, por mais potentes e flexíveis que sejam os computadores, eles nada fariam sem que fossem orientados por listas de instruções detalhadas, interpretadas e executadas pelo processador: os programas.
Tudo que é físido em um computador é chamado hardware, e tudo que ele entende são dois estados de tensão que chamaremos, simbolicamente, de 0 e 1 (esses valores foram adotados somente para facilitar o entendimento). Todos os processadores possuem a sua linguagem de máquina (ou código binário), um conjunto de sequências de “zeros” e “uns” que produzem determinadas ações. É possível escrever programas em linguagem de máquina, mas seria uma tarefa improdutiva porque para que o processador execute tarefas comuns é necessário escrever muito código. Com o aumento da necessidade de programas, criaram-se as linguagens de programação, códigos intermediários entre a linguagem humana e a da máquina. Assim surgiram as linguagens Assembly, ADA, PL/I, CPL, BCPL, B, C, C++, Pascal, e muitas outras. As linguagens de programação podem estar mais próximas da linguagem de máquina ou da humana. Quanto mais próxima da linguagem humana, maior o nível de uma linguagem de programação. A linguagens sofisticadas para ambientes visuais como Visual Basic e Delphi são de altíssimo nível por estarem muito longe do código binário. Os programas de computador também podem ser chamados de softwares.
Para que o computador interprete os programas escritos em uma linguagem de programação, eles devem ser traduzidos em linguagem de máquina. Isso pode ser feito por compilação ou interpretação. A linguagem é compilada quando o programa é traduzido inteiramente para a linguagem de máquina antes da execução, e interpretada quando a tradução é feita linha por linha durante a execução. Linguagens interpretadas tendem a ser mais lentas porque a tradução durante a execução representa um trabalho extra.
A linguagem C foi desenvolvida nos Laboratórios Bell por Dennis Ritchie em 1972. Sua origem está muito ligada ao sistema operacional UNIX, escrito inicialmente em 1969 em linguagem montadora. 
Para entendermos como a linguagem C surgiu, devemos retroceder para o Algol 60, projetado em 1960 por um Comitê Internacional. Essa linguagem possuía objetivos elevados para os computadores da época e por isso nunca foi muito utilizada. Para trazer o Algol 60 mais próxmo da realidade, surgiu tanto em Londres quanto em Cambridge em 1963 a linguagem CPL, que também fracassou por ser muito difícil. Por isso Martim Richards criou em 1967 a linguagem BCPL, uma versão mais simples do CPL. Logo depois, Ken Tompson desenvolveu linguagem B, ainda mais simples que a BCPL, para reescrever o sofisticado sistema UNIX. Ainda havia uma problema: B e BCPL tornaram-se linguagens limitadas, úteis apenas para alguns tipos de problemas.
Devido a esses e outros contratempos, como imcompatibilidade com alguns tipos de hardware, Dennis Ritchie desenvolveu a sucessora de B, chamada de C.
Com a nova linguagem, um mundo rico em possibilidades foi aberto aos novos programadores de sistemas. C permitia o contato íntimo com a máquina enquanto possibilitava implementar instruções de alto nível nos mesmos programas, ou seja: uma linguagem de baixo e alto nível simultaneamente.
�
Características da linguagem C
C pode ser considerada a principal linguagem orientada para máquinas. Diversamente de linguagens criadas para aplicações específicas, como FORTRAN, que são orientadas para problemas, C possui flexibilidade suficiente para implementar soluções para os mais variados tipos de problemas nos mais diversos hardwares.
As linguagens de alto nível permitiram que o programador se concentrasse no problema que tinha que resolver, deixando a manipulação da máquina para o compilador ou interpretador. Para a engenharia ou administração, são excelentes. No entanto, os programadores que desenvolviam sistemas ainda dependiam das indigestas linguagens montadoras de suas máquinas. Para essa classe, C foi a solução definitiva em termos de produtividade e eficiência: está distante o suficiente da máquina para implementar rotinas de alto nível, e próxima o suficiente para especificar detalhes necessários para o sistema operacional. Talvez por isso a popularidade de C seja tão grande.
Dentre as vantagens de C, podemos citar: 
É uma linguagem pequena;
Pode ser de alto ou baixo nível, dependendo do ponto de vista;
Produz um código muito eficiente, comparável ao código Assembly;
Fracamente figurada, possuindo alta flexibilidade para manipulação de dados;
É estruturada, antecipando o surgimento formal desse conceito;
Suporta programação modular;
Possibilita interfaces com as linguagens Assembly e Pascal;
Apresenta operadores para manipulação de bits;
Permite notáveis implementações de aritmética de ponteiros;
Contém estruturas flexíveis de dados, limitados apenas pela necessidade;
Portabilidade para funcionar em máquinas e sistemas operacionais diferentes;
Como nenhuma linguagem de programação é perfeita, as principais desvantagens de C são:
Fracamente figurada, podendo produzir efeitos colaterais inesperados e bizarros;
Ausência de verificação de tempo de processamento.
Como surgiram muitos compiladores para a linguagem C e as variações da linguagem começaram a ameaçar a grande portabilidade de flexibilidade de C, em 1983 o ANSI padronizou a linguagem para que todos os compiladores fossem implementados segundo as mesmas regras. O ANSI manteve alguns conceitos que são conhecidos como “espírito de C”, como:
Confie no programador.
Não impeça que o programador faça o que precisa ser feito.
Mantenha a linguagem pequena e simples.
�
A Linguagem C++
Em 1980, o Dr. Bjarne Stroustrup desenvolveu a sucessora de C, a linguagem C++, que possui a base na linguagem C com idéias do Algol 68 e Simula67: operadores podem ser sobrecarregados e variáveis podem ser declaradas em qualquer ponto dentro do bloco de instruções como no Algol 68; objetos podem ser criados com funções virtuais e classes derivadas como no Simula67.
Quando foi necessário realizar algumas simulações orientadas a eventos, muito rigorosas e com conceitos inexistentes nas linguagens de programação da época como objetos e eventos, e exigindo eficiência que nenhuma linguagem existente era capaz de fornecer, nem mesmo C, um grupo liderado pelo Dr. Stroustrup começou a trabalhar na implementação de uma nova linguagem, versátil e poderosa, mas que deveria manter a compatibilidade com programas e bibliotecas escritos em C. Devido ao alcanceabsoluto desse objetivo, a linguagem que nascia foi considerada sucessora de C e chamada C++.
Dentre as melhorias, a mais significativa é a orientação ao objeto, mudando radicalmente os conceitos avançados de programação estruturada orientada para procedimentos, que era o caso de C. No entanto, para manter o “espírito de C”, o programador ainda é responsável por muitas verificações que são dispensáveis em outras linguagens mais rigorosas e também mais limitadas, como tamanho de vetores e matrizes, endereçamento de ponteiros, etc.
Para que possamos ter idéia do que foi modificado em relação à linguagem C, citamos as principais melhorias de C++:
Estruturas passam a ser de tipo nome, não exigindo o uso da palavra reservada na declaração;
Declarações de variáveis em qualquer lugar do bloco, desde que antes da utilização;
Operador resolução de escopo, permitindo variáveis locais de globais de mesmo nome;
Especificador const, bloqueando o valor de variáveis;
Uniões anônimas, recurso que economiza tempo e memória;
Conversões explícitas, que diminuem os efeitos colaterais de uma linguagem fracamente figurada;
Modelagem de função, especificando no cabeçalho da função os tipos de cada argumento;
Sobrecarga de função, permitindo que mais de uma função com o mesmo nome, desde que tenham tipo de retorno e/ou argumentos de tipos diferentes;
Funções com número de argumentos indefinido;
Tipo referência, facilitando o entendimento e a sintaxe;
Especificador inline, deixando que o compilador decida se pode inserir o código de um função no código em linha, economizando o tempo de chamada e armazenamento na pilha;
Operadores new e delete, melhorando a alocação dinâmida de memória;
Ponteiros void e funções tipo void, aumentando o poder dos ponteiros e formalizando funções void;
Programação orientada ao objeto;
Biblioteca stream, melhorando sensivelmente as operações de I/O.
�
Fundamentos de C++
Os programadores frequentemente relatam a dificuldade no aprendizado da linguagem C++ (bem como C), provavelmente devido à sintaxe simbólica e intimidativa. Essa queixa dificilmente acontece com Pascal, que possui uma sintaxe didática. O fato é que C e C++ foram projetadas para programadores de sistemas, ou seja, pessoas que já possuem um amplo conhecimento de lógica de programação, arquitetura e funcionamento do hardware. Mesmo assim, nada disso impede que a primeira linguagem de um programador seja C ou C++.
Todos os programas devem receber dados de alguma fonte de entrada; processar as informações recebidas por meio de instruções que podem ser divididas genericamente em: simples, condicionais, laços e funções; expressar os resultados da manipulação dos dados de entrada; possuir uma estrutura modular e nomes autodocumentados (com significado) para facilitar a manutenção e a leitura posterior feita por outros programadores.
Um programa C++ é constituído de funções, que são blocos de código cujas instruções executam ações de rotina. Também existem variáveis que são locais da memória RAM onde são armazenadas informações. Outros itens estarão presentes em um programa C++ e serão introduzidos oportunamente na compreensão da linguagem. Vamos escrever nosso primeiro programa C++, que imprime uma mensagem na tela:
// Primeiro programa C++
// Curso de Linguagem de Programação C++ PROG001.CPP - Silvio Sabino
#include<iostream.h>
void main(void){
	cout << "\nMeu primeiro programa!";
	return;
}
// Fim do programa
Vamos analisar linha a linha o conteúdo desse programa:
// Primeiro programa C++
// Curso de Linguagem de Programação C++ PROG001.CPP – Silvio Sabino
Todo programa deve possuir comentários significativos para facilitar o acompanhamento de outros programadores ou para manutenção posterior, que pode ocorrer muitos anos depois da criação do programa. Esse comentário explica o que é o programa.
#include<iostream.h>
Essa instrução é uma diretiva do pré-processador que inclui o arquivo IOSTREAM.H no código do programa. Esse arquivo é um dos vários arquivos de cabeçalho da linguagem C++, que são bibliotecas com rotinas implementadas pelos programadores da linguagem.
void main (void){
...
}
Esse bloco de código é uma função C++. O símbolo { abre o código e } fecha o mesmo. Esses símbolos também são utilizados para laços e estruturas de controle, que veremos mais adiante. A palavra void no início da linha representa o tipo de retorno da função. Nesse caso a função não retorna nenhum valor, fato evidenciado pela palavra void. A palavra main é o identificador (nome) da função. Todos os programas C++ possuem uma única função main e a execução do programa começa sempre a partir dessa função. A palavra entra parênteses void representa os argumentos da função. Nesse caso, a função não tem nenhum argumento, o que é indicado pela mesma palavra void. Entre os delimitadores { e } do bloco, podem existir instruções que são chamadas corpo da função:
cout << "\nMeu primeiro programa!";
Essa linha invoca a stream cout (console out) definida em IOSTREAM.H, que imprime o argumento “Meu primeiro programa!” na tela. Merece atenção a presença da sequência \n que significa nova linha. C e C++ possuem uma série de caracteres especiais que são formados por barra invertida (\) seguido de uma letra ou símbolo. Eis os mais comuns:
	\a
	Beep
	\n
	nova linha
	\t
	tabulação horizontal
	\v
	tabulação vertical
	\r
	retorno de carro
	\b
	retrocesso (backspace)
	\’
	aspas simples
	\”
	aspas duplas
	\\
	barra invertida
	\f
	salta uma página
	\0
	nulo (NULL)
return;
Retorna da função para o processo anterior, no caso o sistema operacional. Essa instrução pode ser dispensada nesse caso sem nenhum aviso do compilador.
// Fim do programa
Comentário para evidenciar que o programa terminou nesse ponto.
O compilador C++ ignorará espaços repetidos, tabulações ou linhas em branco em quase todos os pontos do programa. Portanto, o mesmo programa anterior pode ser escrito de várias formas, como por exemplo:
// Primeiro programa C++
// Curso de Linguagem de Programação C++ PROG0011.CPP - Silvio Sabino
#include <IOSTREAM.H>
void main (void) {cout << "\nMeu primeiro programa!";return;}// Fim do programa
Esse programa é igualmente válido. Devemos observar que na diretiva do pré-processador não podem haver espaços entre os símbolos < > e o nome do arquivo de cabeçalho IOSTREAM.H pode ser escrito em maiúsculas. Todas as instruções C++ são terminadas em ponto-e-vírgula. Outra característica marcante na sintaxe C e C++ é a diferença entre letras minúculas e maiúsculas. Em muitas linguagens, como Pascal, não existe nenhuma diferença, mas em C++ isso é sentido pelo compilador.
Vamos agora analisar um segundo programa C++. O código apresenta declarações de variáveis e a função adicao, cuja tarefa é calcular o valor da soma de dois números passados como parâmetros. As explicações estão inseridas em forma de comentário:
// Segundo programa C++
// Curso de Linguagem de Programação C++ PROG002.CPP - Silvio Sabino
#include<iostream.h> // incluindo iostream.h para utilizar a classe cout
// função que retorna a soma de 2 números cujos valores
// são passados como parâmetros
int adicao (int a, int b){
	// declarando a variável que conterá o valor da soma
	// dos dois parâmetros "a" e "b"
	int resultado;
	// atribuindo o valor da adicao de "a" e "b" à variável resultado
	resultado = a + b;
	// retornando o valor contido na variável "resultado" para
	// o processo anterior, que nesse caso é a função main()
	return resultado;
}
// função principal do programa onde é iniciada a execução
void main(void){
	// declarando duas variáveis do tipo inteiro
	int n , m, soma;
	// atribuindo o valor 2 à variável "n" e 4 à variável "m"
	n = 2;
	m = 4;
	// passando "n"e "m" como parâmetros para que a função soma(int, int)
	// calcule a soma dos dois valores e retorne o resultado que é atribuído
	// à variável soma
	soma = adicao (n, m);
	// imprimindo o valor de "soma" na tela
	cout << soma;
	// retornando o processo anterior, no caso o sistema operacional
	return;
}
// Fim do programa
O próximo programa melhora a interface com o usuário solicitando os valores das variáveis n e m para que a função adicao calcule a soma dos dois valores:
// Terceiro programa C++
// Curso de Linguagem de Programação C++ PROG003.CPP - Silvio Sabino
#include<iostream.h> // incluindo iostream.h para utilizar as classes cout e cin
// função que retorna a soma de 2 números cujos valores
// são passados como parâmetros
int adicao (int a, int b){
	// declarando a variável que conterá o valor da soma
	// dos dois parâmetros "a" e "b"
	int resultado;
	// atribuindo o valor da adicao de "a" e "b" à variável resultado
	resultado = a + b;
	// retornando o valor contido na variável "resultado" para
	// o processo anterior, que nesse caso é a função main()
	return resultado;
}
// função principal do programa onde é iniciada a execução
void main(void){
	// declarando duas variáveis do tipo inteiro
	int n, m, soma;
	// pedindo para o usuário o valor de "n"
	cout << "\nDigite o 1o. no.: ";
	cin >> n;
	// pedindo para o usuário o valor de "m"
	cout << "Digite o 2o. no.: ";
	cin >> m;
	// passando "n" e "m" como parâmetros para que a função soma(int, int)
	// calcule a soma dos dois valores e retorne o resultado que é atribuído
	// à variável soma
	soma = adicao (n, m);
	// imprimindo o valor de "soma" na tela
	cout << "A soma é: " << soma;
	// retornando o processo anterior, no caso o sistema operacional
	return;
}
// Fim do programa
Nos programas acima, vimos como é a sintaxe de declaração de funções e variáveis, como passar parâmetros para uma função e como retornar valores para o processo anterior que chamou a função.
Depois disso, provavelmente será possível reconhecer um programa C++ se alguém nos apresentar um. Passaremos agora a detalhar os aspectos específicos da linguagem C++.
�
Dados padrões
Todo programa C++ deve ter pelo menos a função main( ), e podem também conter dados que podem ser variáveis ou constantes.
	
Todos os dados e funções C++ são referenciados por identificadores (nomes). Os identificadores não podem começar com dígitos numéricos porque assim o compilador não poderia separar tais identificadores de constantes.Eis a descrição suscinta dos tipos de dados padronizados C++:
char: utilizado para armazenar caractares alfanuméricos, o tipo char ocupa um byte na memória. Devido ao fato de C++ ser fracamente figurada, um dado char pode ser visto como número ou caractere, dependendo do desejo do programador na aplicação específica. Seu valor padrão pode variar de –128 a 127.
int: ocupa no modelo padrão uma palavra (nas máquinas da plataforma PC, isso corresponde a dois bytes) na memória e seu valor padrão pode variar entre –32768 a 32767. Pode armazenar números inteiros ou pode ser visto como caractere, dependendo da aplicação, mas o valor do segundo byte não é considerado nesse caso.
float: pode armazenar valores em ponto flutuante e correspondem aos números reais. Ocupam duas palavras na memória e seu valor padrão pode variar entre 3,4x10-38 até 3,4x10+38.
double: armazena valores em ponto flutuante de precisão dupla. Ocupam quatro palavras na memória e seu valor padrão pode variar entre 1,7x10-308 e 1,7x+308.
enum: tipo de dado associado a um conjunto de constantes inteiras chamadas de conjunto de enumeração (enumeration set), que possuem valor presumido mas que podem ser especificados pelo programador. A sintaxe é:
enum semana {domingo, segunda, terça, quarta, quinta, sexta, sábado} dias;
A declaração acima cria o tipo enum semana e a variável dias, do tipo semana. A constante domingo tem valor 0 e as seguintes têm o valor da anterior mais um.
void: tipo vazio para retorno e argumentos de funções. Seu uso é importante para ponteiros, definindo ponteiros genéricos. Isso será visto quando tratarmos de dados dinâmicos.
Dados padrão podem ser iniciados com algum valor quando são declarados, como na declaração:
int inteiro = 7;
Se o programador esquecer de iniciar a variável na declaração ou fora dela, seu valor será desconhecido até que lhe seja atribuído algum valor.
Os dados variáveis, em suma, são os que podem estar no lado esquerdo de uma instrução de atribuição, ou em outros termos, são lvalues. Quaisquer outras expressões não são lvalues (localizador de objeto)
Pode-se conhecer o tamanho de qualquer tipo de dado C++ utilizando-se o operador sizeof que retorna o tamanho em bytes do operando. Por exemplo: sizeof(int) retorna 2, que é o tamanho em bytes do tipo int.�
Tipos definidos e estruturas de dados
typedef
Além dos dados padronizados, podem ser definidos outros tipos de dados com a palavra reservada typedef:
typedef int inteiro;
Com essa definição, poderemos declarar um dado inteiro a como int a ou inteiro. Já que inteiro foi definido como sendo equivalente ao tipo int. Na maioria dos casos, typedef é utilizado para conferir significado aos tipos criados pelo usuário e facilitar a sintaxe, nos poucos casos restantes é uma necessidade para que a linguagem suporte certas declarações ou passagem de argumentos para funções.
Estruturas de dados
Podem ser definidos tipos de dados heterogêneos, ou estruturas de dados, formados por combinações de tipos válidos, padrões ou não. Existem três tipos de estruturas de dados em C++:
struct: a estrutura segue o conceito de registro: dados relacionados logicamente referenciados por um único nome, e cada dado representa um campo. Considere um número complexo com a parte real e imaginária. As duas partes podem ser referenciadas por um só nome, desde que declarada uma estrutura, como por exemplo:
struct complexo {
	double real;
	double imag;
};
class: tipo de dado concebido para a criação de objetos e pode ser entendida com a uma evolução de struct. As funções de uma classe são conhecidas como métodos. A classe abaixo possui dados (campos ou instâncias) e métodos:
class exemplo{
	int n,u;
	float t;
	public:
	char letra;
};
int exemplo::metodo1(void){
	return(0);
}
As instâncias e métodos de uma classe somente podem ser acessadas pelo programa diretamente se especificadas com o modificador public. No exemplo, somente letra pode ser acessada fora da classe. Em C++, tipos de dados struct também podem ter métodos, e suas instâncias são sempre presumidas públicas. Para impedir o acesso de alguma instânca pelo programa, utilizamos o modificador private. A palavra reservada this representa um ponteiro que aponta para o objeto atual.
Quando criamos uma class, não criamos um objeto, mas apenas um tipo de dado. Quando em algum lugar do programa declaramos um dado do tipo de uma class definida, então criamos um objeto na memória.
Para que o objeto seja construído na memória, existe sempre uma função especial denominada construtor do objeto e para dealocar o espaço reservado, o programa chama uma outra função, chamada destrutor. O programador pode criar seus próprios construtores de destrutores, como veremos mais adiante.
union: um tipo interessante de estrutura de dados. Em uma union, todos os dados ocupam a mesma área de memória, sendo que a memória ocupada pela union é igual ao tamanho do maior tipo de dado. Consideremos a union abaixo:
union teste {
	char caractere;
int inteiro;
float flutuante
	double flutuante_duplo;
};
O maior tipo de dado é o campo flutuante_duplo, que ocupa 8 bytes. Na memória, esses campos estariam de forma parecida com o esquemaabaixo:
	C45D:0780
	C45D:0781
	C45D:0782
	C45D:0783
	C45D:0784
	C45D:0785
	C45D:0786
	C45D:0787
Em uma união, os campos estão no mesmo endereço, portanto se um deles tiver seu valor alterado, todos podem sofrer a alteração.
Para acessar bits em um local de memória, C e C++ possuem uma forma de acessá-los com um tipo especial de estrutura denominada campo de bits:
struct campo{
	unsigned c1:1; // 1 bit
	unsigned c2:1; // 1 bit
	unsigned c3:4; // 4 bits 
	unsigned c4:2; // 2 bits
};
Os campos de bits em uma estrutura pode ocupar no máximo 16 bits. A configuração na memória seria algo parecido com o esquema abaixo:
		c4					c3				 c2		c1
	Bit 8
	Bit 7
	Bit 6
	Bit 5
	Bit 4
	Bit 3
	Bit 2
	Bit 1
Se o número total de bits ocupado pelos campos de bits da estrutura for diferente de um múltiplo de 8, os bits restantes até completar um múltiplo de 8 são “desperdiçados”, pois não será possível acessar os bits restantes porque o processador só poderá endereçar bytes e não bits.
�
Modificadores de dados
Os tipos padrões char e int podem ter seus intervalos de valores alterados pelos modificadores signed e unsigned. O modificador signed (sinalizado) é o estado padrão e não é necessário expressá-lo na declaração. Já unsigned (sem sinal) deve ser explicitado para que o compilador saiba que o dado será considerado sempre positivo. Nos dados signed o bit mais significativo representa o sinal, e quando declaramos um dado unsigned o compilador utiliza todos os bits disponíveis para guardar a informação. O efeito é a alteração dos intervalos de valores: unsigned int pode variar de 0 a 65535 e unsigned char de 0 a 255.
O modificador long dobra o tamanho em bytes ocupado pelos tipos int e double. E short pode modificar o tipo int, mas nenhum efeito ocorre na plataforma PC.
O resumo abaixo mostra o efeito nos intervalos e no tamanho em bytes dos modificadores de sinal e tamanho nos tipos padrões C++:
	Tipo
	Tamanho
	Intervalo
	
	unsigned char
	8 bits
	0 a
	 255
	Char
	8 bits
	-128 a
	 127
	Enum
	16 bits
	-32768 a
	 32767
	unsigned int
	16 bits
	0 a
	 65535
	short int
	16 bits
	-32768 a
	 32767
	Int
	16 bits
	-32768 a
	 32767
	unsigned long
	32 bits
	0 a
	 4294967295
	Long
	32 bits
	-2147483648 a
	 2147483647
	Float
	32 bits
	3,4x10-38 a
	 3,4x10+38
	Double
	64 bits
	1,7 x10-308 a
	 1,7 x10+308
	long double
	80 bits
	3,4 x104932 a
	 1,1 x104932
Os dados podem ter seus valores inalteráveis pelo programa se modificados pela palavra reservada const, e podem ter seu valor modificado por algum evento externo através do modificador volatile. Se um dado variável é declarado normalmente como:
int a=0;
O valor contido na variável pode ser alterado pelo programa em uma instrução de atribuição qualquer, mas se ele a variável for declarada com o modificador const:
const int a=0;
O programador não poderá alterar o valor dessa variável, entretanto um processo externo pode se ela for declarada como volatile, mesmo sendo especificado o modificador const:
const volatile a=0;
Nesse caso, o compilador não presumirá qualquer valor para a constante, que pode estar sendo atualizada por algum processo externo.
�
Conversões de dados
Quando escrevemos instruções que envolvem mais de um tipo de dado, eles são convertidos automaticamente seguindo uma ordem hierárquica para que o compilador possa executar a instrução. Essas operações são chamadas de modo misto. Essa necessidade de conversão existe porque tipos de dados diferentes são armazenados de modos diferentes na memória. Os dados originais não são alterados, pois é somente durante o cálculo da instrução que os tipos são alterados influenciando no resultado. Consideremos a instrução abaixo:
float termo1=2.0, resultado;
int termo2=3;
resultado = termo1*termo2;
Para executar a instrução de atribuição, o valor de termo2 é temporariamente convertido para float e o valor de termo2 não é alterado. A hierarquia de conversão segue a sequência: double, float, long, int, short.
Se um float é convertido para int a parte fracionária é perdida sem arredondamento, vejamos o exemplo:
float termo1=2.9, termo2=7.8;
int resultado;
resultado = termo1*termo2;
Esse operação teria como resultado 22,62 se resultado fosse do tipo float ou double, mas como é uma variável do tipo int a parte fracionária é perdida e resultado receberá o valor 22 após a instrução.
Em algumas instruções o resultado normal é indesejável e nesse caso os dados devem ser convertidos com o operador cast, que modela o tipo de dado da melhor maneira para a aplicação:
float termo1=5.7, resultado;
int termo2=3, termo3=4;
resultado = termo1 + termo2/termo3;
Depois dessa instução, o valor de resultado é 5,7. Isso é estranho, já que os dados inteiros não exerceram nenhuma influência. Isso ocorreu porque após a divisão termo2/termo3 o resultado deveria ser 0,75 mas como os dois operandos são inteiros a parte fracionária é desprezada e o resultado da divisão é 0.
Para corrigir esse problema, C++ possui o operador de modelamento de dados (cast). Usando o operador cast em um dos operandos inteiros, o resultado seria 4,275:
resultado = termo1 + termo2/(float)termo3;
Quando o operador cast é aplicado em termo3, a divisão passa a considerar todos os dados como float, conforme a hierarquia de conversão, por isso não é necessário modelar os dois operandos da operação.�
Classes de armazenamento
Os dados em C++ podem ter seu armazenamento padrão modificado, e isso terá efeitos na visibilidade (escopo) da variável dentro do arquivo e dentro do programa (se o programa conter mais de um arquivo). Um dado declarado fora de qualquer função é um dado de escopo global, porém se ele for declarado dentro de um bloco de código ele terá escopo local. As declarações de dados pode ser de nível interno ou externo.
As classes possíveis em declarações de nível interno são auto (padrão) static e register. Um dado auto ou static existe enquanto o programa estiver dentro do bloco onde está declarado, mas se for static a cada chamada à função ele retém o último valor e deve ser iniciado com algum valor, ou o compilador presumirá o valor zero. Se um dado é declarado com classe register o compilador tentará armazenar esse dado em um registrador da CPU ou otimizá-lo. Devemos ter cuidado: register é uma solicitação e não uma ordem, pois nem sempre será possível armazenar dado em um registrador.
Em declarações de nível externo, as classes podem ser somente extern ou static: extern refere-se a um dado declarado em outro arquivo, e pode ser declarado apenas uma vez em um dos arquivos; dados static podem ser declarados em mais de um arquivo, já que static limita o escopo no arquivo onde está declarado. Uma função também pode ter classe de armazenamento modificada: funções static são visíveis apenas dentro do arquivo onde está declarada e funções extern são visíveis em todos os arquivos que formam o programa. Funções sem classe de armazenamento são extern por padrão Abaixo um exemplo de declaração de de um dado com declarações de nível externo (para rodar, abra o projeto proj01.prj no Turbo C++):
// Ilustrando o uso de classes de armazenamento static e extern
// Arquivo PROG004.CPP
// Curso de Linguagem de Programação C++ PROG004.CPP - Silvio Sabino
#include<iostream.h>
int a=0;
static int b;
extern void modifica(void); // declaração de função para acessá-la em outro arquivo
void main(void){
	cout << "\nO valor de a é: " << a;
	modifica();
	cout << "\n\nE o de B em PROG004.CPP é: " << b;
}
// Ilustrando o uso de classes de armazenamento static e extern
// Arquivo PROG005.CPP
// Curso de Linguagem de Programação C++ PROG005.CPP - Silvio Sabino
#include<iostream.h>
extern int a;
static int b=2;
void modifica(void){a=a+1;
	cout << "\n\nO valor de a mudou para: " << a;
	cout << "\nE o de B em PROG005.CPP é: " << b;
}
�
Matrizes
Qualquer tipo de dado em C e C++ pode ser organizados em arranjos (array) contíguos na memória RAM. Esses arranjos são chamados matrizes e têm grande importância na programação. As matrizes podem ter uma ou mais dimensôes, e quando possuem uma dimensão podem ser denominadas de vetores.
A declaração de uma matriz de 5 inteiros de nome matriz seria:
int matriz[5];
Para uma matriz bidimensional em que cada dimensão possui 5 elementos:
int matriz[5][5];
O nº de elementos de uma matriz pode ser omitido na declaração, mas se a matriz não for iniciada o seu tamanho será presumido como 0 pelo compilador. Para declarar uma matriz iniciando-a a sintaxe é:
int matriz[]={0,1,2,3,4,5,6};
No caso de matrizes de mais de uma dimensão, somente a dimensão mais à direita pode ficar sem o nº de itens:
int matriz[5][]={{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15},{16,17,18,19}};
No caso de matrizes de caracteres (em Pascal, o tipo string é padrão, o que não ocorre com C e C++),a inicialização pode ser feita como mostrada acima ou de forma mais direta:
char matriz[]= "essa é uma matriz de caracteres";
No caso de mais de uma dimensão:
char matriz[3][]={"primeiro item","segundo item","terceiro item";};
Nesse caso, o compilador criará todos os itens com o tamanho do maior item.
Poderemos usar as matrizes com todas as possibilidades que elas oferecem quando estudarmos os ponteiros, um assunto de extrema importância em C e C++ que é um dos motivos da escolha delas para implementar sistemas operacionais.
�
Operadores
C++ possui alguns operadores que não são encontrados em outras linguagens de programação, como operadores bit a bit, de atribuição composta, incremento e decremento e operador vírgula. Os tipos de operadores C++ são:
Operadores bit a bit
Tratam os dados como sequências de bit individuais. São & (AND), | (OR), ^ (XOR), ~ (complemento de um). O programa a seguir ilustra os efeitos dos operadores bit a bit:
// Ilustrando os efeitos dos operadores bit a bit
// Curso de Linguagem de Programação C++ PROG006.CPP - Silvio Sabino
#include<iostream.h>
unsigned int zeros=0;
unsigned int uns=255;
unsigned int medio=127;
void main(void){
	cout << "\n\n 0 em binário é 0000000000000000";
	cout << "\n127 em binário é 0000000001111111";
	cout << "\n255 em binário é 0000000011111111\n";
	cout << "\n0 & 255 = " << (zeros & uns) << " 0000000000000000";
	cout << "\n0 | 255 = " << (zeros | uns) << " 0000000011111111";
	cout << "\n0 ^ 255 = " << (zeros ^ uns) << " 0000000011111111";
	cout << "\n~0 = " << (~zeros) << " 1111111111111111";
	cout << "\n0 & 127 = " << (zeros & medio) << " 0000000000000000";
	cout << "\n0 | 127 = " << (zeros | medio) << " 0000000001111111";
	cout << "\n0 ^ 127 = " << (zeros ^ medio) << " 0000000001111111";
	cout << "\n~127 = " << (~medio) << " 1111111110000000";
	cout << "\n255 & 127 = " << (uns & medio) << " 0000000001111111";
	cout << "\n255 | 127 = " << (uns | medio) << " 0000000011111111";
	cout << "\n255 ^ 127 = " << (uns ^ medio) << " 0000000010000000";
	cout << "\n~255 = " << (~uns) << " 1111111100000000";
}
Deslocamento
Também conhecidos como rotação de bits. Esses operadores, bem como os operadores bit a bit, são bastante utilizados em programação de sistemas, por manipularem diretamente os bits dos dados. O operador deslocamento à esquerda << move todos os bits uma posição para a esquerda, e o deslocamento à direita >>, move todos os bits para a direita. Nos dois casos, os bits de um extremo é perdido e o do outro extremo torna-se zero. O programa a seguir mostra como funcionam os operadores de deslocamento de bits:
// Ilustrando os efeitos dos operadores bit a bit
// Curso de Linguagem de Programação C++ PROG007.CPP - Silvio Sabino
#include<iostream.h>
unsigned int valor1=7;
unsigned int valor2=64512;
void main (void){
	cout << "\n\n 7 em binário ‚ 0000000000000111";
	cout << "\n64512 em binário ‚ 1111110000000000\n";
	cout << "\n 7<<1 = " << (valor1<<1) << " 0000000000001110";
	cout << "\n 7<<2 = " << (valor1<<2) << " 0000000000011100";
	cout << "\n64512>>1 = " << (valor2>>1) << " 0111111000000000";
	cout << "\n64512>>2 = " << (valor2>>2) << " 0011111100000000";
}
Incremento e decremento
Somar ou subtrair 1 de um número é tão comum em programação que C++ possui operadores especiais para essas ações: ++ (incremento) e – (decremento). Eles só podem ser utilizados por dados variáveis e a sua sintaxe pode ser observada no programa abaixo:
// Ilustrando os efeitos dos operadores bit a bit
// Curso de Linguagem de Programação C++ PROG008.CPP - Silvio Sabino
#include<iostream.h>
#include<conio.h>
int numero=10;
void main(void){
	clrscr();
	cout << "\nnumero incrementado: " << ++numero;
	cout << "\nnumero novamente incrementado: " << numero++;
	cout << "\nnumero decrementado: " << --numero;
	cout << "\nnumero novamente decrementado: " << numero--;
}
Já que numero foi iniciado com valor 10 e foi incrementado 2 vezes e depois decrementado 2 vezes, então a princípio a saída deve ser:
numero incrementado:			11
numero novamente incrementado:	12
numero decrementado:			11
numero novamente decrementado:	10
Mas a saída que ele apresenta é outra. Execute o programa para verificar e veja que o resultado é diferente. Isso acontece porque a posição dos operadores ++ e – influi no resultado, pois altera a ordem de execução da instrução. Quando escrevemos:
cout << "\nnumero incrementado: " << ++numero;
A ordem de execução é: primeiro a variável numero é incrementada e depois a sentença é impressa por cout.
Enquanto que na linha seguinte:
cout << "\nnumero novamente incrementado: " << numero++;
A ordem é: primeiro a sentença é impressa por cout e depois a variável numero é incrementada
O mesmo ocorre com decremento.
Aritméticos
Os operadores para operações aritméticas em C++ são: + (adição), - (subtração), * (multiplicação), / (divisão) e % (módulo). O operador módulo retorna o resto de uma divisão entre dois inteiros.
Atribuição simples e compostos
Diferente de outras linguagens, C++ possui um operador de atribuição ao invés de uma instrução de atribuição. Isso torna-se claro na instrução abaixo, que não seria possível em outras linguagens:
valor1 = valor2 = valor3 = 2;
Ou seja: valor3 recebe o valor 2 e a operação retorna o valor contido em valor3, que é atribuído à variável valor2, e a peração retorna o valor contido em valor2 e finalmente valor1 recebe 2.
C++ possui ainda um conjunto de operadores de atribuição compostos que permitem que o código seja escrito de forma mais concisa sem perder a clareza. As instruções abaixo são equivalentes:
valor = valor + 5;
valor + = 5;
Outras operações que podem utilizar esses operadores são as demais perações aritméticas, deslocamento de bits e bit a bit, gerando os seguintes operadores: +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |=.
Relacionais e lógicos
Os operadores relacionais C++ sempre estabelecem uma relação entre os valores dos operandos. Eles retornam 0 se o teste for falso e 1 se for verdadeiro. Os operadores relacionais C e C++ são: == (igual, note que ele é diferente do operador = de atribuição), != (diferente), > (maior), < (menor), >= (maior ou igual), <= (menor ou igual).
Os operadores lógicos C e C++ retornam resultados de acordo com a relação lógica de seus argumentos: && (AND), || (OR), ! (NOT). O operador && retornará 1 quando os dois argumentos forem verdadeiros, || retornará 1 quando pelo menos 1 argumento for verdadeiro e ! inverte o valorque seria retornado. O programa a seguir mostra os resultados de teste relacionais e lógicos de acordo com a entrada do usuário:
// Ilustrando os resultados dos operadores relacionais e lógicos
// Curso de Linguagem de Programação C++ PROG009.CPP - Silvio Sabino
#include<iostream.h>
void main(void){
	float num1, num2;
	cout << "\nInforme o primeiro valor real: ";
	cin >> num1;
	cout << "\nInforme o segundo valor real: ";
	cin >> num2;
	cout << "\n\nResultado de "<<num1<<" == "<<num2<<" -> " <<(num1==num2);
	cout << "\nResultado de "<<num1<<" != "<<num2<<" -> " <<(num1!=num2);
	cout << "\nResultado de "<<num1<<" > "<<num2<<" -> " <<(num1>num2);
	cout << "\nResultado de "<<num1<<" < "<<num2<<" -> " <<(num1<num2);
	cout << "\nResultado de "<<num1<<" >= "<<num2<<" -> " <<(num1>=num2);
	cout << "\nResultado de "<<num1<<" <= "<<num2<<" -> " <<(num1<=num2);
	cout << "\nResultado de "<<num1<<" && "<<num2<<" -> " <<(num1&&num2);
	cout << "\nResultado de "<<num1<<" || "<<num2<<" -> " <<(num1||num2);
}
Operador condicional ternário
Esse operador torna o código compacto por envolver um decisão com pouco código. Sua sintaxe é:
condição ? expressão_verdadeira : expressão_falsa ;
A condição genérica na instrução acima é um teste, que pode envolver operadores condicionais e lógicos:
// Ilustrando os resultados dos operadores relacionais e lógicos
// Curso de Linguagem de Programação C++ PROG010.CPP - Silvio Sabino
#include<iostream.h>
int a, b, c;
void main(void){
cout << "\n\nInforme o primeiro valor: ";
cin >>a;
cout << "Informe o segundo valor: ";
cin >>b;
cout << "Informe o terceiro valor: ";
cin >>c;
cout << "o "<<((a>=b && a>=c)?"1o.":(b>=c)?"2o.":"3o.")<<"no. ‚ maior";
}
Operador vírgula
O operador vírgula permite que duas expressões coexistam na mesma linha onde normalmente somente uma seria premitida. Seu uso será evidenciado quando tratarmos de estruturas de controle de fluxo.
Resolução de escopo
C++ permite que uma variável local possua o mesmo nome de uma global, bastando que seja utilizado o operador resolução de escopo ::. No trecho abaixo as há duas variáveis teste:
int teste;
...
void funcao(int teste){
	::teste=teste;
}
Dentro da função funcao, a variável global recebeu o valor da variável local por meio do operador ::.
Assim como nas outras linguagens, os operadores C++ obedecem a níveis de precedência que determinam a ordem que o compilador avaliará os operadores. Efeitos colaterais pode surgir quando os operadores são colocados de forma confusa. As instruções abaixo podem causar efeitos colaterais:
valor = 2; resultado = (valor = 4) + valor;
Existem duas formas de avaliar a expressão: valor recebe 4 e em seguida resultado recebe 8 (4+4); ou valor é usado como 2 e logo depois recebe 4, e resultado recebe 6.
A tabela abaixo relaciona os operadores C++ por ordem de precedência, sendo que alguns ainda não foram descritos. Operadores da mesma categoria tem a mesma precedência:
	Categoria
	Descrição
	Operador
	Precedência mais alta
	Chamada de função
	()
	
	Índice de matriz
	[]
	
	Referência indireta de estruturas
	->
	
	Resolução de escopo
	::
	
	Referência direta de estrutura
	.
	Unários
	NOT
	!
	
	Complemento de 1
	~
	
	Sinal positivo
	+
	
	Sinal Negativo
	-
	
	Incremento
	++
	
	Decremento
	--
	
	Endereço
	&
	
	Referência indireta
	*
	
	Modelamento (cast)
	(tipo)
	
	Tamanho do operando
	sizeof
	
	Alocação dinâmica
	new
	
	Dealocação dinâmica
	delete
	Multiplicativos
	Multiplicação
	*
	
	Divisão
	/
	
	Módulo
	%
	Acesso a membros
	Referência indireta membro de estrutura
	.*
	
	Referência indireta membro de estrutura
	->*
	Aditivos
	Adição
	+
	
	Subtração
	-
	Deslocamento
	Deslocamento à esquerda
	<<
	
	Menor que
	<<
	Relacionais
	Menor ou igual a
	<=
	
	Maior que
	>
	
	Menor ou igual a
	>=
	Igualdade
	Igual
	==
	
	Diferente (não igual)
	!=
	
	AND bit a bit
	&
	
	XOR bit a bit
	^
	
	OR bit a bit
	|
	
	AND lógico
	&&
	
	OR lógico
	||
	
	Condicional ternário
	?:
	Atribuição
	Atribuição
	=
	
	Atribuições compostas
	*=, /=, %=, +=, -=, &=, ^=, |=, <<=, >>=
	
	Vírgula
	,
�
Controle de fluxo
Para que possamos escrever programas C++ mais elaborados, é necessário dominar as estruturas de controle de execução de instruções, que são, basicamente, as instruções condicionais e laços.
Quase todos os programas que escrevemos até o momento seguiram sempre uma sequência definida e o programador não interferiu em nenhum momento para que o programa tomasse decisões. A exceção foi o uso do operador condicional ternário.
Quando é feito o controle de fluxo em um programa, algumas instruções podem não ser executadas em nenhum momento dependendo dos critérios adotados para a decisão.
if
Esse instrução executa condicionalmente um bloco de código. Um bloco de código com apenas uma instrução não precisa ser delimitado com chaves { }, mas deve ser delimitado se houver mais de uma. A sintaxe genérica da instrução if é:
if(expressão de teste)
	ação;
Caso exista mais de uma instrução devem ser usadas as chaves:
if(expressão de teste){
	instrução1;
	instrução2;
	...
}
O programa abaixo exemplifica o uso da instrução if:
//Ilustrando o uso da instrução if
// Curso de Linguagem de Programação C++ PROG011.CPP - Silvio Sabino
#include<iostream.h>
void main(void){
	int valor_teste;
	cout << "\nDigite um valor inteiro: ";
	cin >> valor_teste;
	if(valor_teste==2){
		cout << "\nFoi digitado o valor 2.";
		return;
	}
	cout << "\nFoi digitado um valor diferente de 2.";
}
Nesse exemplo, se o usuário digitar o valor 2, o teste valor_teste==2 retorna 1 e a instrução if direciona o fluxo para dentro do bloco, aparecendo a mensagem “Foi digitado o valor 2.” e o programa retorna para o processo anterior com a instrução return. Caso contrário o programa segue com a instrução após o bloco.
if-else
Com essa instrução o programa pode tomar duas direções baseado em um teste. A sintaxe geral seria:
if(expressão de teste){
	instrução1;
	instrução2;
	...
}
else{
	instrução1;
	instrução2;
	...
}
As instruções dentro do bloco else somente serão executadas quando o teste for falso (retornar 0).
switch
Quando é desejável testar uma variável em relação a vários valores, é improdutivo montarmos sequências de instruções if. Nesses casos é aconselhável utilizar a instrução switch. A sintaxe geral é:
switch (expressão){
	case constante_1:
		instruções;
		break;
	case constante_2:
		instruções;
		break;
	...
	case constante_n:
		instruções;
		break;
	default: instruções;
}
Devemos observar as peculiaridades da instrução switch. Quando o programa encontra a constante que corresponde ao valor da expressão, ele executa as instruções abaixo do case até que seja encontrada uma instrução break ou outra instrução de controle que provoque um devio na odem normal do programa.
for
É uma das estruturas de laço mais potentes em muitas linguagens de programação, mas em C e C++ o laço for ultrapassa os limites normais de flexibilidade. Sua sintaxe geral é:
for(inicialização;expressão de teste;incremento){
	instrução1;
	instrução2;
	...
}
O laço for deve ser usado preferencialmente quando o número de iterações é conhecido. O exemplo abaixo mostra o uso do laço for e da instrução switch:
//Ilustrando o uso do laço for e da instrução switch
// Curso de Linguagem de Programação C++ PROG012.CPP - Silvio Sabino
#include<iostream.h>
void main(void){
	// corpo do laço for, atenção às declarações// de variáveis dentro da inicialização.
	// O programa executará 5 vezes as instruções dentro do bloco
	for(register int i = 0; i < 5;i ++){
		int valor;
		cout << "\nDigite um valor inteiro: ";
		cin >> valor;
		// a instrução switch testará o valor de "valor" e
		// direcionará o programa para o case certo
		switch(valor){
			case 1: cout << "\n\nVocê digitou o valor 1";
							break;
			case 2: cout << "\n\nVocê digitou o valor 2";
							break;
			case 3: cout << "\n\nVocê digitou o valor 3";
							break;
			default: cout << "\n\nVocê digitou um valor diferente de 1,2 ou 3";
		}
	}
}
while
Quando não podemos prever o número de iterações necessárias é recomendado o uso do laço while:
while(expressão de teste){
	instrução1;
	instrução2;
	...
}
Vamos reescrever o exemplo anterior utilizando o laço while:
// Ilustrando o uso do laço while e da instrução switch
// Curso de Linguagem de Programação C++ PROG013.CPP - Silvio Sabino
#include<iostream.h>
void main(void){
	// iniciando a variável com um valor diferente de 0 para
	// evitar efeito colateral no laço while
	int valor=1;
	// se o valor de "valor" for 0, o teste retorna 0 e o laço termina
	while(valor){
		cout << "\nDigite um valor inteiro (0 para sair): ";
		cin >> valor;
		switch(valor){
			case 1: cout << "\nVocê digitou o valor 1";
							break;
			case 2: cout << "\nVocê digitou o valor 2";
							break;
			case 3: cout << "\nVocê digitou o valor 3";
							break;
			default: cout << "\nVocê digitou um valor diferente de 1,2 ou 3";
		}
	}
}
do-while
A principal direfença entre esse instruçõ e while é que as ações dentro do bloco sempre serão executadas pelo menos uma vez:
do{
	instrução1;
	instrução2;
	...
}while(expressão de teste);
break e continue
Dentro de laços, a instrução break provoca a saída imediata do laço, e a instrução continue faz o programa saltar imediatamente para a avaliação da expressão de teste. O uso comum de break é na instrução switch, e continue é raramente usado.
return
Provoca a saída imediata de uma função para o processo anterior. Se a mesma for de tipo diferente de void essa instrução deve vir acompanhada de um valor de retorno, caso contrário o compilador emitirá um aviso que não impede a execução do programa. Se a função for main() o programa terminará.
exit( ) e atexit( )
A função exit( ) provoca a saída imediata do programa e pede um argumento inteiro que será o código de erro para o sistema operacional, e atexit( ) faz com que uma função seja chamada imediatamente antes de terminar o programa. Essa função pede um ponteiro de função com argumento.
goto
É uma instrução que desvia incondicionalmente o programa para um rótulo. Sua sintaxe geral é:
goto rotulo;
...
rotulo:
instrução;
Seu uso é condenável por estar fora da filosofia da programação estruturada, mas foi mantido na transição de C para C++ porque em algumas situações seu uso é vantajoso. Exemplo genérico:
...
for(...){
	for(...){
		for(...){
			for(...){
				...
				if(...)goto sair;
			}
		}
	}
}
sair:
...
Nesse esquema de laços profundamente aninhados, não importam os testes dos laços externos ao for mais interno, porque goto desvia incondicionalmente o fluxo para o rótulo especificado. A única restrição é que o rótulo deve estar dentro da mesma função da instrução goto.
Laços infinitos
Se a expressão de teste de um laço for vazia ou se as variáveis envolvidas não sofrerem modificação dentro do laço, deve existir alguma instrução para que o programa saia do laço por meio de break, return, goto ou pelas função exit( ), caso contrário o laço nunca terminará.
Os laços infinitos podem ser usados quando o programa ou o laço termina mediante um evento produzido pelo usuário ou alguma entrada de valor específica. O exemplo anterior pode ser reescrito novamente utilizando-se um laço for(poderia ser while ou do-while, mas a expressão de teste não seria vazia) infinito:
// Ilustrando o uso do laço infinito
// Curso de Linguagem de Programação C++ PROG014.CPP - Silvio Sabino
#include<iostream.h>
void main(void){
	// utlizando um laço for infinito
	// nota-se que os sinais de ponto-e-vírgula são mantidos
	for(;;){
		int valor;
		cout << "\nDigite um valor inteiro (0 para sair): ";
		cin >> valor;
		switch(valor){
			case 0: return;
			case 1: cout << "\nVocê digitou o valor 1";
							break;
			case 2: cout << "\nVocê digitou o valor 2";
							break;
			case 3: cout << "\nVocê digitou o valor 3";
							break;
			default: cout << "\nVocê digitou um valor diferente de 1,2 ou 3";
		}
	}
}�
Ponteiros
Ponteiros são variáveis dinâmicas que guardam endereços de outra variáveis. A declaração de ponteiros é feita com o operador de referência indireta *:
tipo *identificador;
Onde tipo é o tipo apontado pelo ponteiro. Para atribuição, podemos utilizar o operador endereço &:
tipo nome;
tipo *apontador = &nome;
O ponteiro apontador armazenará o endereço da variável nome, ou em outras palavras, apontará para ela.
Ponteiros podem apontar para ponteiros, aumentando o nível de referência indireta, que é limitado apenas pela necessidade. Os ponteiros podem ser constantes ou variáveis. Ponteiros constantes são as matrizes ou ponteiros que tenham classe de armazenamento const. O nome da matriz representa o endereço do 1º item, ou seja, se array[50] é uma matriz, as expressões &array[0] ou array são equivalentes. Para declarar um ponteiro de nível(ordem) maior, basta aumentarmos o nº de operadores de referência indireta:
int **p, *****p1; //p é de segunda ordem e p1 é de quinta ordem
Se o operador referência indireta for utilizado em instruções durante o programa, ele permitirá o acesso à variável apontada pelo ponteiro. O programa a seguir mostra como isso ocorre:
// Funcionamento de ponteiros
// Curso de Linguagem de Programação C++ PROG015.CPP - Silvio Sabino
#include<iostream.h>
void main(void){
	int valor, *ponteiro = &valor;
	cout << "\nDigite um valor inteiro: ";
	cin >> valor;
	cout << "\nO valor digitado foi: "<< *ponteiro;
	*ponteiro=10;
	cout << "\nO valor foi modificado para: " << valor;
}
Aritmética
Ponteiros podem ser incrementados, decrementados, adicionados ou subtraídos de constantes, e a unidade válida é sempre o tamanho do tipo de dado apontado: depois e incrementar um ponteiro de nome pointer que aponta para o tipo float com a instrução pointer++, o seu valor será o endereço sizeof(float) acima do anterior. E depois de pointer = pointer+3, o novo valor será 3*sizeof(float) acima do anterior.
Para obter o endereço do elemento n de um ponteiro de nome array, que aponta para uma matriz, podemos utilizar notação de matriz ou de ponteiro se o ponteiro for variável: &array[n] ou array+n. E para acessar o valor desse elemento podemos escrever: array[n] ou *(array+n). Em qualquer caso, a notação de ponteiro executa mais rapidamente do que a de matriz.
Modificadores de ponteiros
A memória do processador 8088 é segmentada, e cada segmento tem 64 kbytes (65535 bytes). Todo endereçamento é feito com dois números denominados segmento e deslocamento (offset). Existem 4 segmentos em um programa “.EXE”: código, dados, pilha e extra. Se nada for informado ao compilador, ele tentará sempre alocar espaço dentro do segmento de dados, mas podemos modificar ponteiros para que sejam armazenados em outros locais com o uso de modificadores:
near: força o ponteiro a apontar somente para o deslocamento. Ocupam 2 bytes na memória;
far: força o ponteiro a contar sempre o valor do segmento e do deslocamento. Além e tornar o acesso mais lento, ponteiros far ocupam 4 bytes;huge: semelhante ao ponteiro far, mas quando é incrementado, o segmento pode ser alterado. Isso nunca ocorre com um ponteiro far.
Para apontar para qualquer tipo de dado, um ponteiro pode ser declarado como void * e ser moldado para qualquer tipo de acordo com a necessidade. Um ponteiro void simplesmente aponta para uma endereço de memória sem estar associado a qualquer tipo de dado. Abaixo um programa para exemplificar:
// Funcionamento de ponteiros void
// Curso de Linguagem de Programação C++ PROG016.CPP - Silvio Sabino
#include<iostream.h>
int inteiro;
float flutuante;
void *pointer=&inteiro;
void main(void){
	*(int *)pointer = 2;
	pointer = &flutuante;
	*(float *)pointer = 3.0;
	cout << "\nValor int: " << inteiro << "\nValor float: " << flutuante;
}
Strings
C++ não possui cadeias de caracteres como tipo de dado padrão. Todas as cadeias de caracteres são tratadas como ponteiros para o tipo char. O programador deve ter muito cuidado com strings, porque um acesso fora da área reservada ou alocada não será avisado pelo compilador e pode levar à catástrofe: a área invadida pode pertencer a outros dados, ao programa ou ao sistema operacional, no pior caso.
Strings em C++ são sempre terminadas com o caractere nulo (NULL), portanto sempre devemos alocar espaço para um elemento além do tamanho da string.
Alocação dinâmica de memória
Quando os programas tornam-se mais complexos, é comum que o programador não possa prever quanta memória será necessária para o programa, devendo alocar memória dinamicamente. Os operadores new e delete alocam e liberam memória, respectivamente. A sintaxe geral desses operadores é:
tipo *ponteiro = new tipo[num_itens];
delete(ponteiro);
Quando o operador new é invocado pelo programa, este solicita ao sistema operacional um bloco de tamanho igual a núm_itens*sizeof(tipo). Se não houver memória disponível o ponteiro recebe o valor 0(NULL). Devemos testar se a alocação foi feita com sucesso, porque se tentarmos usar um ponteiro que aponta para NULL ou com valor desconhecido podemos causar uma catástrofe: os outros dados, o código do programa ou de outros programas pode ser corrompido e o sistema pode cair, travando a máquina. O programa a seguir mostra o uso dos operadores new e delete:
// Operadores new e delete
// Curso de Linguagem de Programação C++ PROG017.CPP - Silvio Sabino
#include<iostream.h>
void main(void){
	int *valor, itens;
	cout << "\nDigite o n£mero de itens: ";
	cin >>itens;
	if(!(valor=new int[itens]))
		cout << "\nMemória insuficiente!";
	else{
		cout << "\nAlocação dinâmica efetuda com suceso!";
		delete(valor);
	}
}
Referência
É possível simplificar a notacão de ponteiros usando o tipo referência. Assim, nas chamadas de funções podemos utilizar os nomes das variáveis e passar o endereço para a função. O cabeçalho abaixo possui um argumento que é passado por referência:
int funcao(char *a, int &ref){...
Quando o programa chamar essa função, a variável referência ref equivalerá ao argumento passado para a função, porque terão o mesmo endereço. O uso do tipo referência C++ é indispensável quando não podem ser utilizados ponteiros e tampouco é possível o uso de variáveis comuns. Em C, a única forma de alterar o valor do parâmetro original era por meio de ponteiros.
Membros de ponteiros de estruturas
Para referenciarmos membros de ponteiros que apontam para estruturas de dados, a referência indireta é realizada com os operadores -> e ->*. Por exemplo: seja *pont um ponteiro para uma struct casa, que possui uma instância denominada sala que e um ponteiro do tipo comodo.
struct casa *pont = new casa;
pont->casa = new comodo;
pont->*casa = 20;
A instância casa é referenciada pelo operador-> porque a estrutura externa (pont) é um ponteiro, e o conteúdo apontado por casa é acessado com o operador ->*.
�
Funções
Conforme o conceitos da programação estruturada, todas as ações que são usadas rotineiramente devem ser modularizadas para economizar tempo e facilitar o entendimento. Cada módulo ou sub-rotina em C++ é um função, como também foi explicado no início. A sintaxe geral de uma função C++ é:
tipo_de_retorno identificador(tipo_1 argum_1, tipo_2 argum_2, ..., tipo_n argum_n){
	instrução1;
	instrução2;
	...
}
O tipo de retorno é o tipo da função, ou seja, se ela retorna um tipo int dizemos que ela é do tipo int. Para retornar um valor, basta que uma expressão constante ou variável seja argumento de return.
Argumentos
Uma função pode ter um n° de argumentos limitado apenas pela necessidade e capacidade da máquina. Quando um argumento é passado para uma função, ele pode ser passado de duas formas:
Passagem por valor: quando passamos o valor dos dados. Os valores das variáveis originais da função chamadora não são alterados porque apenas uma cópia de seus valores é armazenada na pilha para serem utilizadas na função chamada. Funções chamadas por valor só podem retornar um valor;
Passagem por referência: nesse caso, são utilizados tipos referência e os dados originais podem ser alterados pela função. Por isso podemos dizer que funções chamadas por referência podem retornar mais de um valor (o normal com return e os outros que foram modificados). Em qualquer caso, a chamada por referência é mais rápida, consumindo menos espaço na pilha e menos instruções.
Em C++ os argumentos podem possuir um valor padrão, definido no cabeçalho da função:
int minha_funcao(int a, char n, double d=0.0, int c=0){
	instrução1;
	instrução2;
	...
}
Argumentos com valores padrões só podem ser os últimos da função. Portanto o cabeçalho:
int minha_funcao(int a, char n, double d=0.0, int c...
É inválido porque após um argumento iniciado com valor padrão segiu-se um argumento normal.
A função main() pode aceitar dois argumentos:
void main(int argc, char argv[]){...}
O argumento argc é o n° de argumentos na linha de comando e argv[] é uma matriz de ponteiros para char contendo os argumentos da linha de comando (o primeiro é o nome completo do programa).
Podem existir funções com nº variável de argumentos utilizando as elipses (...):
void funcao(int arg1, int arg2, ...){...}
Ponteiros de função
Em alguns casos, para que o código torne-se funcional, é aconselhável referenciar uma função indiretamente por um ponteiro. Apontar para uma função é conter o endereço do início do seu código, representado pelo nome da função. O programa abaixo mostra como funciona a sintaxe de um ponteiro de função:
// Ponteiros de função
// Curso de Linguagem de Programação C++ PROG018.CPP - Silvio Sabino
#include<iostream.h>
// declarando um ponteiro que aponta para uma função do tipo void
// sem nenhum argumento
void (*ponteiro)(void);
void funcao_1(void){
	cout << "\nExecutando a função 1!";
	return;
}
void funcao_2(void){
	cout << "\nExecutando a função 2!";
	return;
}
void main(void){
	int resposta;
	do{
		cout << "\nVocê deseja executar qual função (1 ou 2)?";
		cin >>resposta;
	}while(resposta!=1&&resposta!=2);
	ponteiro = resposta==1?funcao_1:funcao_2;
	ponteiro();
	return;
}
O uso de ponteiros de função é uma das portas para a programação avançada orientada por eventos, onde estruturas de dados genéricas são criadas e os objetos são diferenciados pelas funções apontadas.
Modificadores de acesso
C++ pode interagir com as linguagens Pascal e Assembly. Para que uma função possa ser utilizada por um programa escrito em Pascal, ela deve ser modificada com a palavra reservada pascal. Assim a ordem de empilhamento dos argumentos seguirá o padrão da linguagem Pascal: do primeiro para o último (em C++ é o inverso). Diversamente, para garantir que a ordem de empilhamento dos argumento siga o padrão C++ deve-se utilizarcdecl.
Assim como os dados referenciados por ponteiros, as funções também podem estar localizadas em segmentos de código diferentes. Com o uso dos modificadores near e far o compilador pode forçar uma chamada somente utilizando deslocamento (near) ou segmento e deslocamento (far). Chamadas distantes (far) tornam todo o processo mais lento.
inline
Algumas vezes é vantajogo expandir em linha uma função pequena. Isso acontece porque existe um código mínimo para chamar a função envolvendo pilha, argumentos e endereçamento que pode ser de tamanho ou tempo de execução maior do que a colocação do código da função diretamente no local. Para que o programador possa sugerir a expansão em linha, usamos a palavra reservada inline. A limitação é que não podem haver laços na função “candidata” para a expansão.
Recursividade
Muitos problemas possuem solução recursiva ou recorrente, ou seja, a solução chama a si própria até que uma condição básica seja satisfeita e ela começa a retornar. O fatorial de um número é um exemplo clássico de aplicação de recursividade. Observe a função fatorial recursiva:
long fatorial(int n){
	return(n<2?1:n*fatorial(n-1));
}
Sem dúvida, a recursividade torna o código claro. No exemplo do fatorial, a função chamará a si mesma até que o argumento n seja menor do que 2. Nesse ponto ela começa a retornar as chamadas acumuladas na pilha até a primeira. Para comparação, abaixo segue uma função de forma iterativa para o mesmo fim:
long fatorial(int n){
	long resultado=1;
	if(n>1)for(register int i=n;i<2;i--)resultado=resultado*i;
	return(resultado);
}
Sobrecarga
C++ permite que mais de uma função possua o mesmo nome, desde que sejam de tipos diferentes ou tenham argumentos diferentes. Isso ajuda o programador porque só haverá um nome para a mesma tarefa, que poderá aceitar diferentes tipos de argumentos. Destrutores não podem ser sobrecarregados. O programa abaixo calcula o cubo de um número e aceita um argumento int ou float:
// Ilustrando a sobrecarga de função
// Curso de Linguagem de Programação C++ PROG019.CPP - Silvio Sabino
#include<iostream.h>
int cubo(int n){
	return (n*n*n);
}
float cubo(float n){
	return (n*n*n);
}
void main(void){
	int inteiro;
	float real;
	cout << "\nDigite um valor inteiro: ";
	cin >>inteiro;
	cout << "\nDigite um valor real: ";
	cin >>real;
	cout << "\nO cubo do valor inteiro ‚: " << cubo(inteiro);
	cout << "\nO cubo do valor real ‚ : " << cubo(real);
	return;
}
Com exceção de ., .*, ::, ?:, os operadores em C++ são sobrecarregáveis para desempenhar funções diferentes das originais. Uma sobrecarga que já conhecemos é a dos operadores de deslocamente de bits << e >> que são utilizados com os fluxos de entrada e saída cin e cout, que correspondem a stdin e stdout em C. A sobrecarga de operador é realizada pela palavra reservada operator, cuja sintaxe é:
operator <símbolo> (argumentos) {
	instruções
}
Operadores sobrecarregados podem ser membros de uma class:
nome_da_classe::operator <símbolo> (argumentos){
	instruções
}
A definição da sobrecarga deve ter parâmetros de um tipo de class ou deve ser membro de uma class e a precedência do operador não sofre alteração. O programa abaixo sobrecarrega o operador + para somar as partes real e imaginária de dois números complexos e para concatenar duas strings. Atenção nos detalhes.
// Sobrecarga de operador e outras aplicações 
// Curso de Linguagem de Programação C++ PROG020.CPP - Silvio Sabino
#include<string.h>
#include<iostream.h>
// criando uma struct para representar números complexos
struct complex{
	double real; // parte real
	double imag; // parte imaginária
	// construtor para a classe complex com argumento padrão
	complex(double real, double imag=0){
		this->real=real;
		this->imag=imag;
	}
	// construtor sobrecarregado sem argumentos
	complex(void){
		real=0;
		imag=0;
	}
};
// criando a classe string para ser utilizada como parâmetro
// de operator
class string {
	// ponteiro para char manipulado pelo objeto
	// nenhuma outra parte do programa pode acessar diretamente
	// o conteúdo desse ponteiro
	char *str;
	//comprimento máximo permitido
	int n;
	// tornando públicas as funções do objeto para que o programa
	// possa invocá-las
	public:
	// atribuindo uma cadeia à str
	// note como o argumento str é diferenciado do ponteiro str que
	// faz parte do objeto usando-se o ponteiro this, pois as instâncias
	// não são variáveis globais e por isso :: não funciona nesse caso
	int setstr(char *str){
		if(!this->str||n<strlen(str))return(1);
		strcpy(this->str,str);
		return(0);
	}
	//obtendo o conteúdo de str
// o uso do ponteiro temp evita que o processo externo
	// obtenha o endereço de str, podendo obter apenas o
	// conteúdo apontado por ele
	char *getstr(void){
		char *temp=new char[strlen(str)+1];
		return(strcpy(temp,str));
	}
	// sobrecarregando + para concatenar strings;
	char *string::operator+(string &str1){
		char *temp=new char[strlen(str)+1];
		strcpy(temp,str);
		return(strcat(temp,str1.getstr()));
	}
	// construtor da classe, que aloca memória
	// de acordo com o número de itens informado
	// pelo processo anterior
	string(int itens=0){
		n=itens;
		str=n?new char[n]:NULL;
	}
	// liberando o espaço alocado para o ponteiro str
	// e destruindo o objeto
	~string(void){ if(str)delete(str); 	}
};
// sobrecarregando o mesmo operador para somar as partes real
// e imaginária de dois números complexos
complex operator+(complex n1, complex n2){
	return(complex(n1.real+n2.real,n1.imag+n2.imag));
}
// programa principal
void main(void){
	// declarando objetos de classe string
	string string1(11),string2(11),string3(22);
	// declarando estruturas do tipo complex
	complex c1(5,8), c2(2.4), c3;
	string1.setstr("string1");
	string2.setstr(" + string2");
	// utilizando a sobrecarga do operador + para concatenar as strings
	string3.setstr(string1+string2);
	c3=c1+c2;
	cout << "\nresultado com *char : " << string3.getstr();
	cout << "\nresultado com complex: " << c3.real << " " << c3.imag;
}
Protótipos
Normalmente, uma função apenas poderá invocar outra se esta estiver escrita acima daquela:
int acima(void){ ... }
...
int abaixo(void){ ... }
No fragmento acima, a função abaixo pode chamar acima, mas não o contrário. Para que isso seja possível, deve ser declarado um protótipo da função abaixo antes do código de acima.
int abaixo(void);
Modelos
Muitas vezes uma função pode executar o mesmo trabalho com tipos de dados diferentes, sem que isso altere as instruções que fariam parte da função. Funções desse tipo devem ser modeladas. Para construir um modelo, usamos as palavras reservadas template e class:
template <class tipo> nome_da_funcao(argumentos){ ... }
A modelo do programa seguinte aloca espaço na memória para n elementos de qualquer tipo de dado conforme o argumento:
// Ilustrando o uso de modelos de função e ponteiros de 2a ordem
// Curso de Linguagem de Programação C++ PROG021.CPP - Silvio Sabino
#include<iostream.h>
// Implementando o modelo de função que aloca memória e retorna NULL
// se não existir espaço disponível
template <class tipo> tipo* aloca(tipo **ponteiro, int n){
	return(*ponteiro=new tipo[n]);
}
void main(void){
	float *flutuante=NULL;
	int n;
	cout << "\nEscolha o número de elementos: ";
	cin >>n;
	cout << (aloca(&flutuante,n)?"Alocação executada":"Espaço insuficiente!");
	if(flutuante)delete(flutuante);
	return;
}
O programa apresenta um detalhe interessante além do uso do modelo de função: para que oponteiro flutuante seja alterado pela função modelada aloca, é passado o seu endereço, ou seja, um ponteiro de ponteiro (ponteiro de 2a ordem), exemplificando o seu uso.
�
Diretivas do pré-processador
Em alguns casos, deve-se compilar condicionalmente um trecho de código, incluir um arquivo ou trocar um texto por outro segundo definições prévias. Para tal, C++ possui várias diretivas para modificar a compilação. As diretivas com suas sintaxes genéricas são:
#define <id1>[(id2,id3...)] <sentença>: define uma macro, que pode ser simplesmente uma expressão constante ou com argumentos:
#define maior(x,y) ((x)>(y)?(x):(y))
#define NULL 0L
Depois de uma diretiva #define o pré-processador substituirá a primeira sentença pela segunda, respeitando os argumentos. Por exemplo: maior(3,5) será substitído por ((3)>(5)?(3):(5)). O efeito de uma macro com argumento é semelhante ao modelo abaixo, mas sempre será expandida em linha:
template <class tipo> inline tipo maior (tipo x, tipo y){ return(x>y?x:y); }
#if <expressão>, #ifdef <nome>, #ifndef <nome>: instrui o compilador a considerar ou não um trecho do código-fonte de acordo com uma diretiva #define anterior. Isso é especialmente útil para manter a compatibilidade com C e outras linguagens com C++. #ifdef equivale e #if defined(expressão) e #ifndef significa #if !defined(expressão). A palavra defined só pode ser utilizada com estas diretivas.
#elif <expressão>:complemento de #if, #ifdef, #ifndef, instrui o compilador a compilar o código subseqüente se a condição destas diretivas for falsa e se a condição de #elif for verdadeira.
#else: semelhante à #elif, porém não inclui mais uma condição.
#endif: termina o bloco onde as diretivas #if, #ifdef, #ifndef, #elif e #else exercem sua influência.
#error <msg>: instrui o compilador e emitir uma mensagem de erro cujo texto é msg.
#include <arquivo>: inclui um arquivo no local de sua ocorrênia, é a diretiva mais usada.
#line <constante> <arquivo>: faz com que o compilador considere que o a próxima linha do arquivo-fonte atual seja constante e que seu nome seja nome.
#pragma: informa o compilador sobre características específicas da aplicação. Os tipos são:
#pragma inline: informa que o arquivo possui código assembly;
#pragma argused: impede a emissão do aviso “Parameter ‘parâmetro’ is never used”;
#pragma exit <funcao> <prioridade>, #pragma startup <funcao> <prioridade>: fazem com que funcao() seja invocada antes e depois de main(), respectivamente, seguindo uma ordem de prioridade: funções com maior prioridade são executadas antes com startup e depois com exit;
#pragma hdrfile: informa onde estão localizados os arquivos cabeçalho pré-compilados;
#pragma hdrstop: informe o término dos arquivos cabeçalho candidatos à pré-compilação;
#pragma option [opções...]: inclui opções de linha de comando para o compilador;
#pragma saveregs: garante que uma função são modificará os valores dos registradores da CPU;
#pragma warn [+xxx;-xxx;.xxx]:habilita/desabilita ou troca o estado de um aviso C++;
#undef: cancela uma definição de macro anteriormente feita com #define;
�
Arquivos
C++ oferece uma biblioteca para funções de leitura e escrita em arquivos, operações necessárias em muitas aplicações. A linguagem não oferece nenhum meio natural de entrada e saída, mas todas as necessidades foram embutidas na linguagem através das bibliotecas. As ações normais no trabalho com arquivos são: gravar, ler, testar o fim do arquivo, obter o tamanho do arquivo e percorrer o arquivo.
Um arquivo pode ser tratado em alto ou baixo nível. Em alto nível as operações são intermediadas por armazenamento na memória (buffer), que acelera bastante o processo. Os dados são gravados em blocos, para diminuir os acessos ao disco, muito mais lento do que a memória. Arquivos em alto nível são conhecidos como streams (fluxos), e são referenciados por um ponteiro para uma struct FILE. Essa estrutura de dados, bem como as funções que tratam streams, são definidas em STDIO.H. Em baixo nível, C++ trata diretamente com os arquivos e não utiliza buffers. Os arquivos são referenciados por números inteiros denominados manipuladores de arquivos, tratando diretamente com o sistema operacional.
No programa abaixo, há uma estrutura de dados representando um colaborador de uma empresa e o programa manipula os dados lendo e escrevendo os dados em um arquivo. Atenção ao menu apresentando opções ao usuário, implementado em uma função.
// Arquivos em C++
// Curso de Linguagem de Programação C++ PROG022.CPP - Silvio Sabino
// inserindo arquivos cabeçalho necessários
#include<iostream.h>
#include<stdio.h>
#include<conio.h>
#include<ctype.h>
#include<string.h>
// definindo constantes para facilitar o entendimento
#define ALTERA 0
#define EXCLUI 1
#define LISTA 2
FILE *arq; //arquivo onde serão armazenados os dados
size_t tamanho; //variável que guardar  o tamanho da estrutura "colaborador"
// estrutura para referenciar o registro
struct colaborador{
	int reg;		// registro na empresa
	char nome[41]; 	// nome do colaborador
	char CPF[12]; 	// cadastro de pessoa física(CPF)
};
// testa fim de arquivo e leitura
int teste_fluxo(colaborador &empr,FILE *str){
	return(!feof(str)&&fread(&empr,tamanho,1,str)==1);
}
// exibe os dados de um colaborador na tela
void exibir(colaborador c){
	cout <<c.reg<<" - "<<c.nome<<" - "<<c.CPF<<"\n";
}
// testa abertura do arquivo
int abrir(void){
	//tenta abrir o arquivo para atualização ou cria novo arquivo
	if(!(arq=fopen("C:\\exemplo.txt","a+"))){
		cout << "Erro não abrir arquivo. Pressione qualquer tecla p/ voltar";
		getch();
		return(1);
	}
	return(0);
}
// exibe um menu na tela para que o usuário realize a escolha
char menu(void){
	// variável estática para identificar a primeira chamada
	static char opcao=0;
	// testando se é a primeira chamada ou o usuário encerrou a sessão
	if(opcao&&opcao!=54)fclose(arq);
	// limpando a tela
	clrscr();
	// exibindo o menu
	cout << "\nPrograma exemplo de manipulação de arquivos\n\n";
	cout << "1) Inserir\n";
	cout << "2) Consultar\n";
	cout << "3) Alterar\n";
	cout << "4) Excluir\n";
	cout << "5) Listar\n";
	cout << "6) Sair";
	// esperando a opção do usuário.
	// o programa não irá adiante enquanto o usuário não efetuar
	// uma escolha válida
	do{
		gotoxy(1,10);
		cout << "Tecle a sua opção.";
		opcao=getch();
	}while(opcao<49||opcao>54);
	// se o usuário não deseja encerrar a sessão, abre-se o arquivo
	// e se houver erro o usuário será avisado, voltando para o menu
	if(opcao!=54&&abrir())return(-1);
	// retornando para main()
	return opcao;
}
// inserindo um colaborador
void insere(void){
	colaborador novo;
	// solicitando a entrada de dados para o usuário
	cout << "\nInforme o registro: ";
	cin >> novo.reg;
	cin.getline(novo.nome,40);
	cout << "\n\nInforme o nome: ";
	cin.getline(novo.nome,40);
	cout << "\nInforme o CPF: ";
	cin.getline(novo.CPF,11);
	// gravando os dados em arquivo
	fwrite((void*)&novo,tamanho,1,arq);
}
// consultando os dados armazenados
void consulta(void){
	char opcao;
	//perguntando ao usuário qual o chave de consulta desejada
	//a instrução do-while somente terminará quando a resposta for válida
	do{
		gotoxy(1,12);
		cout << "Deseja consultar por nome, CFP ou registro (N/C/R)?";
		opcao=toupper(getch());
	}while(opcao!='N'&&opcao!='C'&&opcao!='R');
	//solicitando agora a entrada do dado a ser consultado
	//observe o uso do operador ternário ?:
	cout <<"\n\n"<<(opcao=='N'?"Nome: ":opcao=='C'?"CPF: ":"Registro: ");
	colaborador cons,temp;
	if(opcao=='R')cin >> cons.reg;
	else cin.getline(opcao=='N'?cons.nome:cons.CPF,opcao=='N'?40:11);

Outros materiais