Sunteți pe pagina 1din 44

Linguagem de Programação

C++
Básico

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 1


Linguagem de Programação C++ – Sumário

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

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 2


Linguagem de Programação C++ – Linguagens de Programação – História de C

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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 3


Linguagem de Programação C++ – Características da Linguagem C

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:

1. É uma linguagem pequena;


2. Pode ser de alto ou baixo nível, dependendo do ponto de vista;
3. Produz um código muito eficiente, comparável ao código Assembly;
4. Fracamente figurada, possuindo alta flexibilidade para manipulação de dados;
5. É estruturada, antecipando o surgimento formal desse conceito;
6. Suporta programação modular;
7. Possibilita interfaces com as linguagens Assembly e Pascal;
8. Apresenta operadores para manipulação de bits;
9. Permite notáveis implementações de aritmética de ponteiros;
10. Contém estruturas flexíveis de dados, limitados apenas pela necessidade;
11. Portabilidade para funcionar em máquinas e sistemas operacionais diferentes;

Como nenhuma linguagem de programação é perfeita, as principais desvantagens de C são:

1. Fracamente figurada, podendo produzir efeitos colaterais inesperados e bizarros;


2. 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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 4


Linguagem de Programação C++ – A Linguagem C++

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 alcance absoluto
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++:

1. Estruturas passam a ser de tipo nome, não exigindo o uso da palavra reservada na declaração;
2. Declarações de variáveis em qualquer lugar do bloco, desde que antes da utilização;
3. Operador resolução de escopo, permitindo variáveis locais de globais de mesmo nome;
4. Especificador const, bloqueando o valor de variáveis;
5. Uniões anônimas, recurso que economiza tempo e memória;
6. Conversões explícitas, que diminuem os efeitos colaterais de uma linguagem fracamente figurada;
7. Modelagem de função, especificando no cabeçalho da função os tipos de cada argumento;
8. 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;
9. Funções com número de argumentos indefinido;
10. Tipo referência, facilitando o entendimento e a sintaxe;
11. 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;
12. Operadores new e delete, melhorando a alocação dinâmida de memória;
13. Ponteiros void e funções tipo void, aumentando o poder dos ponteiros e formalizando funções
void;
14. Programação orientada ao objeto;
15. Biblioteca stream, melhorando sensivelmente as operações de I/O.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 5


Linguagem de Programação C++ – Fundamentos de C++

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

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 6


Linguagem de Programação C++ – Fundamentos de C++

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:

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 7


Linguagem de Programação C++ – Fundamentos de C++

// 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"

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 8


Linguagem de Programação C++ – Fundamentos de C++

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++.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 9


Linguagem de Programação C++ – Tipos definidos e estruturas de dados

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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 10


Linguagem de Programação C++ – Tipos definidos e estruturas de dados

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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 11


Linguagem de Programação C++ – Tipos definidos e estruturas de dados

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 esquema abaixo:

char
int float double
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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 12


Linguagem de Programação C++ – Modificadores de dados

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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 13


Linguagem de Programação C++ – Conversões de dados

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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 14


Linguagem de Programação C++ – Classes de Armazenamento

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;
}

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 15


Linguagem de Programação C++ – Operadores

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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 16


Linguagem de Programação C++ – Operadores

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){

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 17


Linguagem de Programação C++ – Operadores

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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 18


Linguagem de Programação C++ – Operadores

 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 valor que 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);

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 19


Linguagem de Programação C++ – Operadores

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;

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 20


Linguagem de Programação C++ – Operadores

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 ,

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 21


Linguagem de Programação C++ – Controle de fluxo

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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 22


Linguagem de Programação C++ – Controle de fluxo

 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:

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 23


Linguagem de Programação C++ – Controle de fluxo

//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;

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 24


Linguagem de Programação C++ – Controle de fluxo

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(...){

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 25


Linguagem de Programação C++ – Controle de fluxo

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";
}
}
}

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 26


Linguagem de Programação C++ – Ponteiros

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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 27


Linguagem de Programação C++ – Ponteiros

 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);

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 28


Linguagem de Programação C++ – Ponteiros

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 ->*.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 29


Linguagem de Programação C++ – Funções

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 (...):

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 30


Linguagem de Programação C++ – Funções

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 utilizar cdecl.

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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 31


Linguagem de Programação C++ – Funções

 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;

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 32


Linguagem de Programação C++ – Funções

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

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 33


Linguagem de Programação C++ – Funções

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");

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 34


Linguagem de Programação C++ – Funções

// 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 o ponteiro
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.

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 35


Linguagem de Programação C++ – Diretivas do pré-processador

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++;

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 36


Linguagem de Programação C++ – Diretivas do pré-processador

#undef: cancela uma definição de macro anteriormente feita com #define;

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 37


Linguagem de Programação C++ – Arquivos

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

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 38


Linguagem de Programação C++ – Arquivos

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

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 39


Linguagem de Programação C++ – Arquivos

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);
cout <<"\n";
rewind(arq);

//pesquisando o arquivo e exibindo os dados que satisfazem à consulta


while(teste_fluxo(temp,arq))if(
(opcao=='N'&&!strcmp(cons.nome,temp.nome))||
(opcao=='C'&&!strcmp(cons.CPF,temp.CPF))||
(opcao=='R'&&cons.reg==temp.reg)){

exibir(temp);
}

//deixando o usuário decidir quando voltar ao menu


cout <<"\nPressione qualquer tecla para voltar ao menu";
getch();
}

//alterando, excluindo ou listando os dados gravados


void modifica(int z=ALTERA){
int reg,opcao;
colaborador temp;

//como o registro é único para cada colaborador, as operações de


//alteração e exclusão são direcionadas por esse campo
if(z!=LISTA){
cout <<"\nInforme o no. do registro: ";
cin >>reg;
}
else cout <<"\n\n";

//criando um arquivo temporário para auxiliar as operações de


// alteração e exclusão
FILE *tmp=tmpfile();

// pesquisando o arquivo e efetuando a operação desejada


while(teste_fluxo(temp,arq)){

// se foi pedida a listagem, entÆo todos os dados são exibidos


if(z==LISTA)exibir(temp);

//senão, é executada a ação somente no colaborador informado

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 40


Linguagem de Programação C++ – Arquivos

else if(temp.reg==reg){
if(z==ALTERA){
do{
gotoxy(1,11);
cout <<"\n\nAlterar nome ou CPF (N/C)?";
opcao=toupper(getch());
}while(opcao!='N'&&opcao!='C');

// novamente o uso extensivo do operador ternário ?:


cout <<"\n"<<"Novo "<<(opcao=='N'?"nome: ":"CPF: ");
cin.get(temp.CPF[11]);
cin.getline(opcao=='N'?temp.nome:temp.CPF,opcao=='N'?40:11);
}
cout <<"Registro "<<(z==ALTERA?"alterado. ":"excluído. ");
}
if(temp.reg!=reg||z==ALTERA)fwrite(&temp,tamanho,1,tmp);
}

//reescrevendo os dados reorganizados no arquivo de origem


if(z!=LISTA){
fclose(arq);
arq=fopen("C:\\Exemplo.txt","wb+");
rewind(tmp);
while(teste_fluxo(temp,tmp))fwrite(&temp,tamanho,1,arq);
}
// se foi pedida a lista, então somente é impresso o caractere nova linha
else cout <<"\n";
fclose(tmp);
cout <<"Pressione qualquer tecla p/ voltar.";
getch();
}
// programa principal
void main(void){

// obtendo o tamanho da estrutura colaborador


// isto é útil porque economiza código e chamadas de função
tamanho=sizeof(colaborador);

// o programa fica esperando o usuário escolher a ação


// e direciona a ação conforme e sua opção
for(;;)switch(menu()){
case '1': insere();
break;
case '2': consulta();
break;
case '3': modifica();
break;
case '4': modifica(EXCLUI);
break;
case '5': modifica(LISTA);
case -1: break;
case '6': return;
}
}
// fim do programa

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 41


Linguagem de Programação C++ – Introdução ao modo gráfico

Introdução ao modo gráfico

Acessar o modo gráfico significa mudar o modo de acesso ao vídeo. Em modo texto padrão, a tela é
dividida em 80 colunas e 25 linhas e no modo gráfico existem vários tipos possíveis dependendo do
hardware. No programa abaixo, o usuário informa os coeficientes de uma função do 2o grau (f(x) = ax2 +
bx + c) e o programa desenha o gráfico da função.

// Introdução ao modo gráfico - Função do 2o. grau


// Curso de Linguagem de Programação C++ PROG023.CPP - Silvio Sabino
#include<graphics.h>
#include<iostream.h>
#include<conio.h>

// parâmetros e variável da função


float *p, x;

// retornando o valor da funçãoo do segundo grau


float bhaskara(void){
return(p[0]*x*x+p[1]*x+p[2]);
}

// desenhando o gráfico na tela em escala 10:1


// observar o uso de continue
void plot(float (*funcao)(void)){
float y;
for(x=-32;x<32;x+=0.0001){
if((y=funcao())>24||y<-24)continue;
putpixel(x*10+320,y*10+240,15);
}
}

void main(void){

//declarando um int register para uso nos laços


register int i;

float (*funcao)(void)=bhaskara; // para a funçãoo específica


p=new float[3]; // alocando espaço para 3 parâmetros da funçãoo
clrscr();// limpando a tela

//solicitando os dados para o usuário


for(i=0;i<3;i++){
cout << "Digite o parâmetro \""<<(!i?"A":i==1?"B":"C")<<"\": ";
cin >> p[i];
}

//iniciando o modo gráfico


int d=DETECT,m;
initgraph(&d,&m,"C:\\ARQUIV~1\\TC\\BGI");

// especificando azul como cor de fundo azul e


// cinza claro como cor da linha
setbkcolor(1);
setcolor(7);

// desenhando os eixos na tela


line(0,240,639,240);
line(320,0,320,479);
for(i=0;i<640;i+=10){

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 42


Linguagem de Programação C++ – Introdução ao modo gráfico

line(i,238,i,242);
if(i<480)line(318,i,322,i);
}

plot(funcao); // chamando a função que desenha o grafico


getch(); // esperando o usuario pressionar um tecla
closegraph(); // fechando o modo grafico
}

No segundo exemplo, o programa desenho um botão e espera até que o usuário pressione uma tecla para
então sair do programa.

// Introdução ao modo gráfico - Desenhando um botão


// Curso de Linguagem de Programação C++ PROG024.CPP - Silvio Sabino
#include<graphics.h>
#include<conio.h>
#include<dos.h>

// função que desenha o botão na tela


void botao(int flag){

moveto(100,100); // movendo o cursor gráfico para (100,100)

setcolor(flag?15:8);
linerel(80,0);
linerel(0,-32);
setcolor(flag?8:15);
linerel(-80,0);
linerel(0,32);

// escrevendo um texto no botão


for(register i=0;i<=flag;i++){
setcolor(!i&&flag?7:8);
outtextxy(120+i,80+i,"teste");
}
}

// programa principal
void main(void){

//iniciando o modo gráfico


int d=DETECT,m;
initgraph(&d,&m,"C:\\ARQUIV~1\\TC\\BGI");

// especificando cinza claro como cor de fundo e chamando


// a funcao que desenha o botão
setbkcolor(7);
botao(0);

getch();
botao(1);

// esperando 0,2 segundo para que seja percebido


// o movimento do botao
delay(200);

closegraph();// fechando o modo grafico


}

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 43


Linguagem de Programação C++ – Palavras reservadas

Palavras reservadas

Todas as linguagens de programação possuem um conjunto de palavras reservadas que apenas devem ser
utilizadas de acordo com a especificação original da linguagem, não podendo ser usadas como nome de
funções ou variáveis e podem, embora seja altamente desaconselhável, ser definidas para outras
atribuições com a diretiva #define. O resultado dessa acrobacia certamente será um cataclisma.

As palavras reservadas C++ são:

Asm auto break case cdecl char


Class const continue _cs default delete
Do double _ds else enum _es
Extern _export far _fastcall float for
Friend goto huge if inline int
Interrupt _loadds long near new operator
Pascal private protected public register return
_saveregs _seg short signed sizeof _ss
Static struct switch template this typedef
Union unsigned virtual void volatile while

Silvio Sabino de Souza Junior – sabino@cefetjunior.com.br 44

S-ar putea să vă placă și