Você está na página 1de 170

Universidade Federal de Santa Catarina UFSC

Centro Tecnolgico - CTC


Departamento de Automao e Sistemas - DAS
Sistemas Industriais Inteligentes S2i
http://s2i.das.ufsc.br/

Curso de Linguaguem
Computacional C/C++

Florianpolis, janeiro de 2002.

Curso de Linguagem Computacional C/C++

ndice
ndice .........................................................................................................................................2
1
Programao em C ...........................................................................................................7
2
Conceitos Bsicos da Programao C ..............................................................................9
2.1 Histrico de C...............................................................................................................9
2.2 Criando um Programa Executvel................................................................................9
2.3 A Estrutura Bsica de um Programa em C.................................................................10
2.4 Variveis.....................................................................................................................11
2.5 Tipos de Dados...........................................................................................................12
2.6 Constantes ..................................................................................................................14
2.7 Ponteiros.....................................................................................................................15
2.8 Exerccios ...................................................................................................................16
3
Entrada/Sada Console ...................................................................................................17
3.1 Printf() ........................................................................................................................17
3.2 Cprintf()......................................................................................................................19
3.3 Scanf() ........................................................................................................................19
3.4 Getch(), Getche() e Getchar().....................................................................................20
3.5 Putch() ou Putchar() ...................................................................................................21
3.6 Exerccios ...................................................................................................................21
4
Operadores......................................................................................................................23
4.1 Operadores Aritmticos..............................................................................................23
4.2 Operadores Relacionais..............................................................................................23
4.3 Operadores lgicos binrios .......................................................................................24
4.4 Operadores de Ponteiros.............................................................................................25
4.5 Operadores Incrementais e Decrementais ..................................................................25
4.6 Operadores de Atribuio...........................................................................................27
4.7 O Operador Lgico Ternrio......................................................................................28
4.8 Precedncia.................................................................................................................28
4.9 Exerccios: ..................................................................................................................28
5
Laos ..............................................................................................................................30
5.1 O Lao For..................................................................................................................30
5.2 O Lao While .............................................................................................................31
5.3 O Lao Do-While .......................................................................................................32
5.4 Break e Continue ........................................................................................................33
5.5 Goto ............................................................................................................................33
5.6 Exerccios ...................................................................................................................33
6
Comandos para Tomada de Deciso ..............................................................................34
6.1 If .................................................................................................................................34
6.2 If-Else .........................................................................................................................35
6.3 Switch.........................................................................................................................35
6.4 Exerccios ...................................................................................................................37
7
Funes...........................................................................................................................39
7.1 Sintaxe ........................................................................................................................39
7.2 Exemplos ....................................................................................................................40
7.3 Prototipagem ..............................................................................................................41
7.4 Classes de Armazenamento........................................................................................42
7.4.1 Auto ....................................................................................................................42
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
2

Curso de Linguagem Computacional C/C++

7.4.2 Extern .................................................................................................................42


7.4.3 Static...................................................................................................................43
7.4.4 Variveis Estticas Externas ..............................................................................44
7.4.5 Register...............................................................................................................44
7.5 Exerccios ...................................................................................................................44
8
Diretivas do Pr-Processador .........................................................................................46
8.1 Diretiva #define..........................................................................................................46
8.2 Macros ........................................................................................................................47
8.3 Diretiva #undef...........................................................................................................48
8.4 Diretiva #include ........................................................................................................48
8.5 Compilao Condicional ............................................................................................49
8.6 Operador defined........................................................................................................49
8.7 Diretiva #error ............................................................................................................50
8.8 diretiva #pragma ........................................................................................................50
8.9 Exerccios ...................................................................................................................50
9
Matrizes ..........................................................................................................................51
9.1 Sintaxe de Matrizes ....................................................................................................51
9.2 Inicializando Matrizes ................................................................................................52
9.3 Matrizes como Argumentos de Funes ....................................................................54
9.4 Chamada Por Valor e Chamada Por Referncia ........................................................55
9.5 Strings.........................................................................................................................57
9.5.1 Strings Constantes ..............................................................................................57
9.5.2 String Variveis..................................................................................................57
9.5.3 Funes para Manipulao de Strings................................................................58
9.6 Exerccios ...................................................................................................................60
10 Tipos Especiais de Dados...............................................................................................61
10.1
Typedef...................................................................................................................61
10.2
Enumerados (Enum)...............................................................................................61
10.3
Estruturas (Struct)...................................................................................................62
10.4
Unies.....................................................................................................................65
10.5
Bitfields ..................................................................................................................66
10.6
Exerccios ...............................................................................................................67
11 Ponteiros e a Alocao Dinmica de Memria ..............................................................68
11.1
Declarao de Ponteiros e o Acesso de Dados com Ponteiros...............................68
11.2
Operaes com Ponteiros .......................................................................................68
11.3
Funes & Ponteiros ..............................................................................................70
11.4
Ponteiros & Matrizes..............................................................................................71
11.5
Ponteiros & Strings ................................................................................................73
11.6
Ponteiros para Ponteiros.........................................................................................74
11.7
Argumentos da Linha de Comando........................................................................77
11.8
Ponteiros para Estruturas........................................................................................77
11.9
Alocao Dinmica de Memria............................................................................78
11.9.1 Malloc() .............................................................................................................79
11.9.2 Calloc() ..............................................................................................................81
11.9.3 Free() .................................................................................................................81
11.10 Exerccios ...............................................................................................................81
12 Manipulao de Arquivos em C.....................................................................................83
12.1
Tipos de Arquivos ..................................................................................................83
12.2
Declarao, abertura e fechamento ........................................................................83
Leitura e escrita de caracteres ...............................................................................84
12.3
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
3

Curso de Linguagem Computacional C/C++

12.4
Fim de Arquivo (EOF) ...........................................................................................84
12.5
Leitura e escrita de strings......................................................................................85
12.6
Arquivos Padres ...................................................................................................85
12.7
Gravando um Arquivo de Forma Formatada .........................................................86
Leitura e escrita de valores binrios ......................................................................87
12.8
12.9
Exerccios ...............................................................................................................87
13 Programao em C++.....................................................................................................89
13.1
Palavras-chave C++................................................................................................91
13.2
Sintaxe & Variveis................................................................................................91
13.3
Laos e Comandos de Deciso...............................................................................92
13.4
I/O em C++: Stream ...............................................................................................92
13.4.1 A stream de sada cout.......................................................................................92
13.4.2 A stream de entrada cin .....................................................................................94
13.5
Funes...................................................................................................................95
13.5.1 Valores Default Para Argumentos de uma Funo ...........................................95
13.5.2 Sobrecarga de Funes ......................................................................................96
13.5.3 Funes Inline ...................................................................................................96
13.5.4 Operador Unrio de Referncia: &....................................................................96
13.6
Alocao Dinmica de Memria em C++..............................................................97
13.7
Exerccios ...............................................................................................................98
14 Classes e Objetos em C++..............................................................................................99
14.1
Tipo Classe e o Encapsulamento de Dados..........................................................100
14.2
Definindo Classes.................................................................................................100
14.3
Membros Privados e Pblicos ..............................................................................101
14.4
Funes-Membro..................................................................................................102
14.5
Construtores & Destrutores ..................................................................................102
14.6
Criando Objetos....................................................................................................103
14.7
Atributos do Tipo: Static ......................................................................................104
14.8
Acessando Funes e Dados Pblicos..................................................................105
14.9
Objetos Const .......................................................................................................105
14.10 Tipo Objeto...........................................................................................................106
14.11 Exerccios .............................................................................................................106
15 Sobrecarga de Operadores............................................................................................108
15.1
A Sobrecarga como uma Funo Global..............................................................109
15.2
Limitaes e Caractersticas.................................................................................110
15.3
Sobrecarga de Operadores como Funo-Membro ..............................................111
15.4
Estudo de Casos....................................................................................................112
15.5
Exerccios .............................................................................................................119
16 Herana.........................................................................................................................120
16.1
Derivando uma Classe..........................................................................................121
16.2
Dados Protected....................................................................................................124
16.3
Construtores & Destrutores ..................................................................................124
16.4
Construtor de Cpia & Alocao Dinmica.........................................................125
16.5
Chamadas a Funes ............................................................................................126
16.6
Herana Pblica e Privada....................................................................................126
16.7
Converses de Tipos entre Classe-Base e Derivada ............................................127
16.8
Nveis de Herana ................................................................................................127
16.9
Herana Mltipla..................................................................................................128
16.10 Exerccios .............................................................................................................131
17 Funes Virtuais e Amigas...........................................................................................132
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
4

Curso de Linguagem Computacional C/C++

17.1
Funes Virtuais...................................................................................................132
17.2
Destrutores Virtuais..............................................................................................134
17.3
Classe-Base Virtual ..............................................................................................134
17.4
Funes Amigas ...................................................................................................135
17.5
Classes Amigas.....................................................................................................137
17.6
Exerccios .............................................................................................................137
18 Operaes com Arquivos Iostream ..............................................................................139
18.1
Estudo de Caso .....................................................................................................140
18.2
A funo Open()...................................................................................................143
18.3
Testando Erros......................................................................................................143
18.4
Escrevendo e Lendo em Buffers de Caracteres....................................................144
18.5
Imprimindo em Perifricos...................................................................................145
18.6
Exerccios .............................................................................................................145
19 Namespaces ..................................................................................................................146
19.1
Examplo e Sintaxe................................................................................................146
19.2
Qualified Names, Using Declarations and Directives..........................................147
19.3
Prevenindo Conflitos de Nomes...........................................................................148
19.4
Namespaces sem Nome........................................................................................148
19.5
Apelidos para Namespace ....................................................................................149
19.6
Declarando Nomes ...............................................................................................149
19.7
Atualizando Cdigos Antigos ..............................................................................149
19.8
Namespaces so Abertos ......................................................................................150
20 Templates .....................................................................................................................151
20.1
ClasseTemplates...................................................................................................151
20.1.1 Especificao...................................................................................................151
20.1.2 Membros da Classe Template .........................................................................151
20.1.3 ParmetrosTemplate ........................................................................................152
20.2
Funes Templates ...............................................................................................152
20.2.1 Function Template Arguments ........................................................................153
20.2.2 Sobreescrevendo Funes Templates..............................................................153
20.3
Especializao ......................................................................................................154
20.4
Derivao e Templates .........................................................................................154
20.5
Polimorfismo ........................................................................................................155
21 Conteiner ......................................................................................................................156
21.1
Iteradores ..............................................................................................................156
21.2
Tipos de Conteineres ............................................................................................156
21.2.1 Conteineres Seqenciais..................................................................................156
21.2.2 Contineres Associativos: ...............................................................................156
21.3
Exemplo de Conteiner ..........................................................................................156
22 Exceptions Handling ....................................................................................................158
22.1
Exceo ................................................................................................................158
22.2
Como as excees so usadas ..............................................................................158
22.3
Biblioteca Except <except.h> ..............................................................................160
22.3.1 Terminate() ......................................................................................................160
22.3.2 Set_terminate() ................................................................................................161
22.3.3 Unexpected() ...................................................................................................161
22.3.4 Set_unexpected() .............................................................................................161
Trabalho 1..............................................................................................................................162
Trabalho 2..............................................................................................................................162
Trabalho 3..............................................................................................................................162
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
5

Curso de Linguagem Computacional C/C++

Trabalho 4..............................................................................................................................162
Referncias Bibliogrficas.....................................................................................................166
Hot Sites ................................................................................................................................167
Anexo 1 Metodologia para o Desenvolvimento de Softwares ...........................................168
Anexo 2 Sumrio da Modelagem UML .............................................................................169

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
6

Curso de Linguagem Computacional C/C++

1 Programao em C

Sistemas Digitais

expandabilidade

Microprocessadores

complexidade

CLP

flexibilidade

Micro-Computador

custo

Redes de
Computadores

capacidade computacional

Atualmente, empregam-se cada vez mais sistemas computacionais na automatizao de


processos industriais. Os sistemas computacionais empregados (ver Figura 1) variam desde um
simples circuito lgico digital, passando por uma circuito composto por um microprocessador ou
um CLP, at sistemas complexos envolvendo um ou mais microcomputadores ou at estaes de
trabalho. Um engenheiro que atua nesta rea deve conhecer os sistemas computacionais disponveis
e ser capaz de selecionar o melhor equipamento para uma dada aplicao. Alm disto, este
profissional deve conseguir instalar este sistema, configur-lo e acima de tudo program-lo para que
este execute a tarefa de automatizao atendendo os requisitos industrias do sistema, como
imunidade a falhas ou comportamento determinstico com restries temporais (sistemas temporeal). Neste contexto, a programao destes sistemas se faz de suma importncia. Basicamente, a
inteligncia dos sistemas automatizados implementada atravs de programas computacionais,
comandando os componentes de hardware para executar a tarefa com o comportamento desejado.

Figura 1 : Comparao entre os diversos sistemas computacionais para aplicaes industriais.

Nas ltimas dcadas, o desenvolvimento em hardware permitiu que cada vez mais os
processos industrias sejam automatizados e interligados atravs de sistemas computacionais.
Entretanto, a evoluo em software no se deu em tamanha velocidade como a de hardware. Desta
forma, um dos grandes paradigmas tecnolgicos hoje o desenvolvimento de programas para a
realizao de tarefas complexas e que exigem um alto grau de inteligncia.
A maneira de se comunicar com um computador chama-se programa e a nica linguagem
que o computador entende chama-se linguagem de mquina. Portanto todos os programas que se
comunicam com a mquina devem estar em linguagem de mquina.
Para permitir uma maior flexibilidade e portabilidade no desenvolvimento de software, foram
implementados nos anos 50 os primeiros programas para a traduo de linguagens semelhantes
humana (linguagens de "alto nvel") em linguagem de mquina.
A forma como os programas so traduzidos para a linguagem de mquina classifica-se em
duas categorias:
Interpretadores: Um interpretador l a primeira instruo do programa, faz uma
consistncia de sua sintaxe e se no houver erro converte-a para a linguagem de mquina
para finalmente execut-la. Segue, ento, para a prxima instruo, repetindo o processo
at que a ltima instruo seja executada ou a consistncia aponte algum erro. So muito
bons para a funo de depurao ("debugging") de programas, mas so mais lentos. Ex.:
BASIC Interpretado, Java.
Compiladores: Traduzem o programa inteiro em linguagem de mquina antes de serem
executados. Se no houver erros, o compilador gera um programa em disco com o sufixo
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
7

Curso de Linguagem Computacional C/C++

.OBJ com as instrues j traduzidas. Este programa no pode ser executado at que
sejam agregadas a ele rotinas em linguagem de mquina que lhe permitiro a sua
execuo. Este trabalho feito por um programa chamado linkeditor que, alm de
juntar as rotinas necessrias ao programa .OBJ, cria um produto final em disco com
sufixo .EXE que pode ser executado diretamente do sistema operacional.
Compiladores bem otimizados produzem cdigo de mquina quase to eficiente quanto
aquele gerado por um programador que trabalhe direto em Assembly. Oferecem em geral menos
facilidades de depurao que interpretadores, mas os programas so mais rpidos (na ordem de 100
vezes ou mais). Ex.: BASIC Compilado, FORTRAN, PASCAL, MDULA - 2, C, C++.
Alm da velocidade, outras vantagens podem ser mencionadas:
desnecessria a presena do interpretador ou do compilador para executar o programa
j compilado e linkeditado;
programas .EXE no podem ser alterados, o que protege o cdigo-fonte.
Desta forma, os compiladores requerem o uso adicional de um editor de ligaes ("Linker"),
que combina mdulos-objetos ("Traduzidos") separados entre si e converte os mdulos assim
"linkados" no formato carregvel pelo sistema operacional (programa .EXE).
Estudaremos aqui uma das linguagens de alto-nvel mais utilizadas na indstria: a linguagem
"C" e, posteriormente, a sua sucessora a linguagem C++, resultado da introduo da programao
Orientada a Objetos linguagem C.
A programao uma atividade que requer pacincia, concentrao e organizao. O
aprendizado desta tcnica deve acontecer de forma gradual para que o programador entenda bem os
conceitos envolvidos e compreenda os diversos mecanismos disponveis. Por isso, o aluno deve
prosseguir neste aprendizado no seu ritmo, permitindo-se consolidar os conhecimentos atravs dos
exemplos e exerccios. O aluno deve buscar formar uma boa base antes de se preocupar com as
estruturas mais complexas. A caminhada feita passo a passo, com calma e segurana.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
8

Curso de Linguagem Computacional C/C++

2 Conceitos Bsicos da Programao C


2.1 Histrico de C
O compilador "C" vem se tornando o mais difundido em ambiente industrial. A linguagem
"C" se originou das linguagens BCPL e B desenvolvidas em 1970. A primeira verso de "C" foi
implementada para o sistema operacional UNIX pela Bell Laboratories, especificamente por Dennis
M. Ritchie e Ken Thompson no incio da dcada de 70, e rodava em um DEC PDP11 (Digital
Equipment Corporation). A linguagem C foi utilizada para portar o UNIX para outros
computadores. A linguagem "C" possui uma caracterstica dual:
considerada linguagem estruturada de alto-nvel e...
"Assembly" de alto-nvel, que permite escrever programas muito prximos linguagem
de mquina, sendo usada para desenvolver muitas aplicaes como compiladores,
interpretadores, processadores de texto e mesmo sistemas operacionais. Ex: UNIX, MSDOS, TPW.
A linguagem de programao C tornou-se rapidamente uma das mais importantes e
populares, principalmente por ser muito poderosa, porttil, pela padronizao dos compiladores
existentes (atravs da norma ANSI C) e flexvel. Os programas em C tendem a ser bastante
compactos e de execuo rpida.
A linguagem C baseada em um ncleo pequeno de funes e estruturas bsicas, desta
forma, todo programa desenvolvido a partir deste ncleo bsico. Isto implica na grande
portabilidade de C, haja vista que basta a implementao deste ncleo bsico para um dado
processador e automaticamente j estar disponvel um compilador C para este processador. Por
esta razo, existem compiladores C para a grande parte dos sistemas computacionais atualmente
disponveis. Devido tambm a este pequeno ncleo, um programador C capaz de desenvolver
programas to eficientes, pequenos e velozes quanto os programas desenvolvidos em Assembly. Por
isso, diz-se que C uma linguagem de baixo nvel, i.e., prxima da linguagem de mquina.

2.2 Criando um Programa Executvel


compilar
linkar
Programa: "Ol Mame!!!"

Arq1.C

Arq1.Obj

ABC

linkar

Arq2.Obj
MyProgram.Exe
linkar

Arq3.Obj
CPU

Figura 2 : Ilustrao do processo de criao de um programa em C.


________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
9

Curso de Linguagem Computacional C/C++

Primeiro, datilografe o seu programa com o auxlio de um processador de textos em modo


ASCII. Grave o programa em disco dando a ele um nome como sufixo .C. O programa gerado
chamado de cdigo fonte.
Na seqncia, compile o fonte seguindo as instrues do seu compilador, o que criar um
programa com o sufixo .OBJ em disco. O programa gerado chamado de objeto.
Por fim, basta linkeditar o objeto seguindo as instrues do seu linkeditor o que criar um
programa com sufixo .EXE em disco. O programa gerado chamado de executvel. A Figura 2
apresenta o processo de gerao de um programa em C.

2.3 A Estrutura Bsica de um Programa em C


A forma geral de um programa em "C" a seguinte:
< diretivas do pr-processador >
< declaraes globais >;
main()
{
< declaraes locais >;
/ comentrio /
< instrues >;
}
< outras funes >

Vamos comear por um programa bem simples em C. Voc pode escrever este programa em
um arquivo ASCII e salv-lo com um nome terminando em .C . O programa serve para escrever
na tela a frase Bom Dia!!!!.
/* Programa : Bom Dia! */
#include <stdio.h>
void main()
{
printf(Bom Dia!!!!);
}

Na primeira linha, os smbolos /* e */ servem para delimitar um comentrio do programa.


muito importante que os programas sejam comentados de forma organizada. Isto permite que
outras pessoas possam facilmente entender o cdigo fonte. Os comentrios no so interpretados
pelo compilador, servindo apenas para a documentao e esclarecimento do programador.
Depois, segue-se com uma diretiva para o pr-processador #include <stdio.h>.
Isto advm do fato de C ter um ncleo pequeno de funes bsicas. Ao escrever esta linha de
cdigo, o pr-processador ir acrescentar ao programa todas as funcionalidades definidas na
biblioteca stdio e ir link-la posteriormente ao programa. Desta forma, voc poder usufruir
todos os servios disponveis nesta biblioteca.
Por fim, temos a funo main(). Esta funo indica ao compilador em que instruo
deve ser comeada a execuo do programa. Portanto, esta funo deve ser nica, aparecendo
somente uma vez em cada programa. O programa termina quando for encerrada a execuo da
funo main(). No caso deste programa exemplo, ela no recebe nenhum parmetro e tambm
no retorna parmetro nenhum. Isto fica explcito atravs da palavra-chave void escrita na frente
do programa. Se em vez de void tivssemos escrito int, isto significaria que a funo main()
deveria retornar um valor do tipo inteiro ao final de sua execuo. Como este o valor retornado
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
10

Curso de Linguagem Computacional C/C++

pela funo main(), este tambm ser o valor retornado pelo programa aps a sua execuo. As
funes e as suas caractersticas sero apresentadas em detalhes nos prximos captulos.
int main()
{
printf(Bom Dia!!!!);
return 0; /* indica ao OS que no ocorreu nenhum erro durante a
execuo do programa */
}

Todo o corpo de uma funo em C inicializado e finalizado atravs das chaves { e }. Estas
chaves definem o bloco de instrues a serem executados por esta funo.
A primeira instruo dada dentro do programa printf(Bom Dia!!!!);. Printf
uma funo definida em stdio.h para escrever dados na janela console.
Todas as instrues de programa tm que ser declaradas dentro de alguma funo (na
main() ou outra qualquer). Todas as instrues devem estar dentro das chaves que iniciam e
terminam a funo e so executadas na ordem em que as escrevemos.
As instrues C so sempre encerradas por um ponto-e-vrgula (;). O ponto-e-vrgula parte
da instruo e no um simples separador.
Esta instruo uma chamada funo printf();, os parnteses nos certificam disso e o
ponto-e-vrgula indica que esta uma instruo.
Nota-se que a funo chamada escrevendo-se o nome desta e colocando-se os parmetros
desta dentro dos parnteses. A final de cada instruo em C, faz-se necessrio o acrscimo de um
ponto-vrgula ;.
As variveis em C podem estar dentro de uma funo ou no incio do arquivo fonte.
Variveis declaradas no incio do arquivo fonte so consideradas globais, isto , so visveis (i.e.
acessveis) para todas as funes do programa. Variveis declaradas dentro de uma funo so
consideradas locais, isto , visveis somente pela funo onde so declaradas.
"C" distingue nomes de variveis e funes em maisculas de nomes em minsculas.
Voc pode colocar espaos, caracteres de tabulao e pular linhas vontade em seu
programa, pois o compilador ignora estes caracteres. Em C no h um estilo obrigatrio. Entretanto,
procure manter os programas to organizados quanto for possvel, pois isto melhora muito a
legibilidade do programa, facilitando o seu entendimento e manuteno.

2.4 Variveis
As variveis so o aspecto fundamental de qualquer linguagem de computador. Uma
varivel em C um espao de memria reservado para armazenar um certo tipo de dado e tendo um
nome para referenciar o seu contedo.
O espao de memria de uma varivel pode ser compartilhado por diferentes valores
segundo certas circunstncias. Em outras palavras, uma varivel um espao de memria que pode
conter, a cada tempo, valores diferentes.
/* Programa : Exemplo de variveis! */
#include <stdio.h>
void main()
{
int num;
num = 2;
printf(Este o nmero dois: %d, num);

/* declaracao */
/* atribui um valor */
/* acessa a varivel */

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
11

Curso de Linguagem Computacional C/C++

A primeira instruo,
int num;

um exemplo de declarao de varivel, isto , apresenta um tipo, int, e um nome, num.


A segunda instruo,
num = 2;

atribui um valor varivel e este valor ser acessado atravs de seu nome. Usamos o operador de
atribuio (=) para este fim.
A terceira instruo chama a funo printf() mandando o nome da varivel como
argumento. Esta l o valor da varivel e substitui na posio indicada por %d, compondo assim a
frase apresentada na tela. O emprego da funo printf() ser apresentado em detalhe, posteriormente.
Em C todas as variveis devem ser declaradas.
Se voc tiver mais de uma varivel do mesmo tipo, poder declar-las de uma nica vez
separando seus nomes por vrgulas.
int aviao, foguete, helicoptero;

2.5 Tipos de Dados


O tipo de uma varivel informa a quantidade de memria, em bytes, que esta ir ocupar e a
forma como o seu contedo ser armazenado.
Em C existem apenas 5 tipos bsicos de variveis, que so:
Identificador
char
int
float
double
void

Categoria
Caracter
Inteiro
Real de ponto flutuante
Real de ponto flutuante de dupla preciso
Sem valor.

Com exceo de void, os tipos de dados bsicos podem estar acompanhados por
modificadores na declarao de variveis. Os modificadores de tipos oferecidos em C so:
Modificadores
signed
unsigned
long
short

Efeito
Bit mais significante usado como sinal
Bit mais significante parte do nmero (s +)
Estende preciso
Reduz preciso

Tipos de Dados Resultantes:


Tipo
(signed) char
unsigned char
(short) (signed) int
(short) unsigned int
(signed) long int
unsigned long int

Tamanho
1 Byte
1 Byte
2 Bytes
2 Bytes
4 Bytes
4 Bytes

Valores possveis
-128 a +127
0 a 255
-32.768 a +32.767
0 a 65.535
-2.147.483.648 a +..647
0 a 4.294.967.295

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
12

Curso de Linguagem Computacional C/C++

float
long float
double

4 Bytes
8 Bytes
8 Bytes

3,4E-38 a 3,4E+38
1,7E-308 a 1,7E+308
1,7E-308 a 1,7E+308

Observao: As declaraes que aparecem na tabela acima entre parnteses (), indicam que
estas declaraes so optativas. Por exemplo short unsigned int indica a mesma preciso
que unsigned int.
O tipo int tem sempre o tamanho da palavra da mquina, isto , em computadores de 16 bits
ele ter 16 bits de tamanho.
Emprega-se o complemento de dois dos nmeros positivos para o clculo e representao
dos nmeros negativos.
A escolha de nomes significativos para suas variveis pode ajud-lo a entender o que o
programa faz e prevenir erros. Uma varivel no pode ter o mesmo nome de uma palavra-chave de
C. Em C, letras minsculas e maisculas so diferentes.
Tabela de Palavras Chaves em C:
auto
break
case
char
const
continue

default
do
double
else
enum
extern

float
for
goto
if
int
long

register
return
short
signed
sizeof
static

struct
switch
typedef
union
unsigned
void

volatile
while

Exemplo de um programa que emprega as variveis apresentadas.


void main()
{
float y;
int i;
double x = 3.24;
char c = 'a';
i = 100;
y = (float) i;
}

/
/
/
/
/
/

varivel
varivel
varivel
varivel
varivel
converte

Real no inicializada
Inteira no inicializada
Double inicializada com 3.24
Char inicializada com a
i recebe o valor 100
tipos

/
/
/
/
/
/

Preste ateno na operao y= (float) i;. Esta operao muito empregada para
converso de tipos de variveis diferentes. Suponha que voc tenha uma varivel x de tipo A e
queira convert-la para o tipo B e armazen-la em y deste tipo. Voc pode executar esta operao
atravs do operador:
y = ((B) x);

Ateno: Cuidado ao converter variveis com preciso grande para variveis com preciso
pequena, ou seja, variveis que utilizam um nmero diferente de bits para representar dados. Voc
pode perder informaes importantes por causa desta converso. Por exemplo, se voc converter
um float num int, voc perder todos os dgitos depois da vrgula (preciso).
void main()
{
float y = 3.1415;
int x = 0;
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
13

Curso de Linguagem Computacional C/C++

x = (int) y;

/* Equivalente :

x = 3; */

2.6 Constantes
Um constante tem valor fixo e inaltervel.
No primeiro programa exemplo, mostramos o uso de uma cadeia de caracteres constante
juntamente com a funo printf():
printf(Bom Dia!!!!);

H duas maneiras de declarar constantes em C:


a) usando a diretiva #define do pr-processador:
#define < nome da constante > < valor >

Esta diretiva faz com que toda apario do nome da constante no cdigo seja substituda
antes da compilao pelo valor atribudo. No reservado espao de memria no momento da
declarao define. A diretiva deve ser colocada no inicio do arquivo e tem valor global (isto , tem
valor sobre todo o cdigo).
Exemplo:
#define size 400
#define true 1
#define false 0 /* no usa ";" nem "=" */

b) utilizando a palavra-chave "const":


const < tipo > < nome > = < valor >;

Esta forma reserva espao de memria para uma varivel do tipo declarado. Uma constante
assim declarada s pode aparecer do lado direito de qualquer equao (isto equivale a dizer que no
pode ser atribuido um novo valor aquela varivel durante a execuo do programa).
Exemplo:
const char letra = 'a';
const int size = 400;
const double gravidade = 9.81;
/* Programa: Exemplo do uso de Constantes */
#define Size 4
void main()
{
const char c = c;
const int num = 10;
int val = Size;
}

Em C uma constante caractere escrita entre aspas simples, uma constante cadeia de
caracteres entre aspa duplas e constantes numricas com o nmero propriamente dito.
Exemplos de constantes:
a) caracter: a
b) cadeia de caracteres: Bom Dia !!!!
c) nmero: -3.141523

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
14

Curso de Linguagem Computacional C/C++

2.7 Ponteiros
Uma das mais poderosas caractersticas oferecidas pela linguagem C o uso de ponteiros.
Um ponteiro proporciona um modo de acesso a variveis sem referenci-las diretamente. O
mecanismo usado para isto o endereo da varivel. De fato, o endereo age como intermedirio
entre a varivel e o programa que a acessa.
Basicamente, um ponteiro uma representao simblica de um endereo. Portanto, utilizase o endereo de memria de uma varivel para acess-la.
Um ponteiro tem como contedo um endereo de memria. Este endereo a localizao de
uma outra varivel de memria. Dizemos que uma varivel aponta para uma outra quando a
primeira contm o endereo da segunda.
A declarao de ponteiros tem um sentindo diferente da de uma varivel simples. A
instruo:
int *px;

declara que *px um dado do tipo int e que px um ponteiro, isto , px contm o endereo de uma
varivel do tipo int.
Para cada nome de varivel (neste caso px), a declarao motiva o compilador a reservar
dois bytes de memria onde os endereos sero armazenados. Alm disto, o compilador deve estar
ciente do tipo de varivel armazenada naquele endereo; neste caso inteiro.
O endereo de uma varivel pode ser passado um ponteiro atravs do operador &, como
apresentado abaixo:
/* Exemplo com Ponteiros */
void main()
{
int num, valor; /* declara as varivel inteira num e valor
int *ptr;
/* declara um ponteiro para um inteiro
ptr = 0;
/* inicializa o ponteiro com o endereco 0
ptr = &num;
/* atribui ao ptr o endereo da varivel num
num = 10;
/* atribui varivel inteira o valor 10
valor = *ptr;
/* acessa o contedo apontado por ptr e
/* atribui a valor
}

*/
*/
*/
*/
*/
*/
*/

Neste programa, primeiro declaram-se duas variveis inteiras. Em seguida, declara-se um


ponteiro para uma varivel do tipo inteira.
Este ponteiro tem o seu contedo inicializado com 0. Este um procedimento normal na
manipulao de ponteiros, muito empregado para evitar o aparecimento de erros. Pois, enquanto o
endereo de um ponteiro for nulo, isto indicar que este endereo contm um valor invlido e,
portanto, o contedo representado por este endereo no deve ser acessado.
Na seqncia, emprega-se o operador & para obter o endereo da varivel num e
armazenar este endereo em ptr.
Logo aps, atribumos a varivel inteira num o valor 10. Como ptr contm o endereo de
num, logo ptr poder j acessar o valor 10 armazenado na varivel num. Isto feito na ltima
linha, onde o contedo apontado por ptr acessado e copiado para a varivel valor.
Outro exemplo da manipulao de ponteiros:
void main()
{
int i, j, *ptr; /* declara as variveis */
i = 1;
/* i recebe o valor 1
*/
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
15

Curso de Linguagem Computacional C/C++

j = 2;
/* j recebe o valor 2
*/
ptr = &i;
/* ptr recebe o valor do endereo de i */
*ptr = *ptr + j; /* equivale a: i = i + j */
}

Nosso objetivo neste momento no apresentar todas as potencialidades dos ponteiros.


Estamos aqui apresentando os ponteiros primeiramente como um tipo de dado especial. O
importante aqui entender o contedo de um ponteiro e como este pode ser empregado.
Posteriormente, apresentaremos as funcionalidades dos ponteiros medida que formos evoluindo
no aprendizado de C.

2.8 Exerccios
2.1 Crie o seu programa Hello, World! ou Ol, Mame!;
2.2 Crie um programa que contenha todos os tipos de variveis possveis e as combinaes
dos modificadores possveis. Inicialize estas variveis com valores tpicos. Use o mtodo para a
converso de tipos para converter:
a) A varivelo do tipo char em todos os outros tipos de variveis.
b) A varivelo do tipo double em todos os outros tipos de variveis.
Discuta o que acontece com a preciso das variveis.
2.3 Crie um programa que exemplifique a utilizao de ponteiros. Que contenha pelo menos
a declarao de um ponteiro, sua inicializao com zero, a obteno do endereo de uma varivel
com o operador & e o acesso ao dado representado pelo ponteiro.
2.4 Utilize as diretivas #define para criar constantes e emprege estas constantes para
inicializar as variveis do programa acima.
2.5 Analise o seguinte programa:
/* Testando 1,2,3 */
#define

Default_Y

void main()
{
const int num = 10;
int y = Default_Y;
const int *ptr = 0;
ptr = &num;
*ptr = *ptr + y;
}

Aponte onde est o erro e explique por qu.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
16

Curso de Linguagem Computacional C/C++

3 Entrada/Sada Console
As rotinas de entrada/sada do console se encontram nas bibliotecas "stdio.h" e "conio.h" e,
por isso, estas bibliotecas devem ser includas nos programas aplicativos atravs da diretiva
include:
#include <stdio.h>
#include <conio.h>

Algumas das funes de entrada e sada para a console mais utilizadas so apresentadas a
seguir:

3.1 Printf()
A funo printf() uma das funes de E/S (entrada e sada) que podem ser usadas em C.
Ela no faz parte da definio de C mas todos os sistemas tm uma verso de printf()
implementada. Ela permite a sada formatada na tela.
J vimos duas aplicaes diferentes da funo printf():
printf(Bom Dia!!!!);
printf(Este o nmero dois: %d, num);

A funo printf()pode ter um ou vrios argumentos. No primeiro exemplo ns


colocamos um nico argumento: Bom Dia !!!!. No segundo entretanto, colocamos dois: Este o
nmero dois: %d que est esquerda e o valor 2 direita da vrgula que separa os argumentos.
Sintaxe de printf():
printf(string-formatao, < lista de parmetros >);

A string de formatao pode conter caracteres que sero exibidos na tela e cdigos de
formatao que indicam o formato em que os argumentos devem ser impressos. No nosso segundo
exemplo, o cdigo de formatao %d solicita a printf() para imprimir o segundo argumento em
formato decimal na posio da string onde aparece o %d.
Cada argumento deve ser separado por uma vrgula.
Alm do cdigo de formatao decimal (%d), printf()aceita vrios outros. O prximo
exemplo mostra o uso do cdigo %s para imprimir uma cadeia de caracteres:
/* Exemplo da funo Printf() */
#include <stdio.h>
int main(int argc, char* argv[])
{
printf(%s esta a %d milhoes de milhas \n do sol., Venus, 67);
}

A sada ser:
Venus est a 67 milhoes de milhas
do sol.
Aqui, alm do cdigo de formatao, a expresso de controle de printf() contm um
conjunto de caracteres estranho: \n.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
17

Curso de Linguagem Computacional C/C++

O \n um cdigo especial que informa a printf() que o restante da impresso deve ser
feito em uma nova linha. A combinao de caracteres \n representa, na verdade, um nico caractere
em C, chamado de nova-linha (equivalente ao pressionamento da tecla Enter em um editor de
texto).
Os caracteres que no podem ser obtidos diretamente do teclado para dentro do programa
(como a mudana de linha) so escritos em C, como a combinao do sinal \ (barra invertida) com
outros caracteres. Por exemplo, \n representa a mudana de linha.
A string de formatao define a forma como os parmetros sero apresentados e tem os
seguintes campos:
"%[Flags] [largura] [.preciso] [FNlh] < tipo > [\Escape Sequence]"
onde:
Flags
+
Em branco
#

Efeito
justifica sada a esquerda
apresenta sinal (+ ou -) do valor da varivel
apresenta branco se valor positivo, sinal de - se valor negativo
apresenta zero no incio p/ octais
apresenta Ox para hexadecimais
apresenta ponto decimal para reais

largura = nmero mximo de caracteres a mostrar


preciso = nmero de casas aps a vrgula a mostrar
F = em ponteiros, apresentar como "Far" => base : offset (xxxx : xxxx)
N = em ponteiros, apresentar como "Near" => offset
h = apresentar como "short"
l = apresentar como "long"
Escape Sequence
\\
\
\0
\a
\b
\f
\n
\o
\r
\t
\x
Tipo
%c
%d, %i
%e, %E
%f
%l, %ld
%lf
%o

Efeito
Barra
Aspas
Nulo
Tocar Sino (Bell)
Backspace Retrocesso
Salta Pgina de Formulrio
Nova Linha
Valor em Octal
Retorno do Cursor
Tabulao
Valor em hexadecimal

Formato
Caracter
Inteiro decimal (signed int)
Formato cientfico
Real (float)
Decimal longo
Real longo (double)
Octal (unsigned int)

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
18

Curso de Linguagem Computacional C/C++

%p
%s
%u
%x

Pointer xxxx (offset) se Near, xxxx : xxxx (base: offset) se Far


Apontador de string, emite caracteres at aparecer caracter zero (00H)
Inteiro decimal sem sinal (unsigned int)
Hexadecimal

Abaixo segue alguns exemplos da formatao apresentada acima:


/* Programa de Exemplo da formatao da sada com Printf() */
#include <stdio.h>
int main(int argc, char* argv[])
{
float x;
double y = -203.4572345;
int a, b;
a = b = 12;
x = 3.141523;
printf("Bom dia");
printf("\n\t\tBom dia\n"); /* pula linha aps escrever bom dia */
printf("O valor de x %7.3f\n", x);
printf("Os valores de i, j e y so: %d %d %lf \n", a, b, y);
}

Observao: Caso voc queira imprimir na tela os caracteres especiais \ ou %, voc deve
escrev-los na funo printf() de forma duplicada, o que indicar ao compilador que este no se
trata de um parmetro da funo printf() mas sim que deseja-se imprimir realmente este
caracter. O exemplo abaixo apresenta este caso:
#include <stdio.h>
void main()
{
int reajuste = 10;
printf(O reajuste foi de %d%%. \n, reajuste);
}

a sada ser:
O reajuste foi de 10%.

3.2 Cprintf()
Basicamente cprintf() igual a printf(), mas usa as coordenadas atuais do cursor e
da janela que forem ajustados anteriormente, bem como ajustes de cr de caracteres. Utilize esta
funo para escrever na tela em posies pr-definidas.

3.3 Scanf()
A funo scanf() outra das funes de E/S implementadas em todos os compiladores C.
Ela o complemento de printf() e nos permite ler dados formatados da entrada padro
(teclado).
A funo scanf() suporta a entrada via teclado. Um espao em branco ou um CR/LF
(tecla Enter) definem o fim da leitura. Observe que isto torna inconveniente o uso de scanf()
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
19

Curso de Linguagem Computacional C/C++

para ler strings compostas de vrias palavras (por exemplo, o nome completo de uma pessoa). Para
realizar este tipo de tarefa, veremos outra funo mais adequada na parte referente strings.
Sua sintaxe similar de printf(), isto , uma expresso de controle seguida por uma
lista de argumentos separados por vrgula.
Sintaxe:
scanf(string de definio das variveis, <endereo das variveis>);

A string de definio pode conter cdigos de formatao, precediddos por um sinal % ou


ainda o caracter * colocado aps o % que avisa funo que deve ser lido um valor do tipo indicado
pela especificao, mas no deve ser atribudo a nenhuma varivel (no deve ter parmetros na lista
de argumentos para estas especificaes).
A lista de argumentos deve consistir nos endereoes das variveis. O endereo das variveis
pode ser obtido atravs do operador & apresentado na seco sobre ponteiros (ver 2.7).
Exemplo:
/* Programa exemplo do uso de Scanf() */
#include <stdio.h>
void main()
{
float x;
printf ("Entre com o valor de x : ");
scanf ("%f", &x);
/* l o valor do tipo float (%f) e armazena na
varivel x (&x) */
}

Esta funo funciona como o inverso da funo printf(), ou seja, voc define as
variveis que deveram ser lidas da mesma forma que definia estas com printf(). Desta forma,
os parmetros de scanf() so em geral os mesmos que os parmetros de printf(), no exemplo
acima observa-se esta questo.
O cdigo de formatao de scanf() igual ao cdigo de formatao de printf(). Por
isso, veja as tabelas de formatao de printf() para conhecer os parmetros de scanf().
Outro exemplo de scanf():
/* Segundo Programa exemplo do uso de Scanf() */
#include <stdio.h>
main()
{
float anos, dias;
printf(Digite a sua idade em anos: );
scanf(%f, &anos);
dias = anos*365;
printf(Sua idade em dias e %.0f.\n, dias);
}

3.4 Getch(), Getche() e Getchar()


Em algumas situaes, a funo scanf()no se adapta perfeitamente pois voc precisa
pressionar [enter] depois da sua entrada para que scanf() termine a leitura. Neste caso, melhor
usar getch(), getche() ou getchar().
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
20

Curso de Linguagem Computacional C/C++

A funo getchar() aguarda a digitao de um caracter e quando o usurio apertar a tecla


[enter], esta funo adquire o character e retorna com o seu resultado. getchar() imprime na tela
o character digitado.
A funo getch()l um nico caracter do teclado sem eco-lo na tela, ou seja, sem
imprimir o seu valor na tela. A funo getche() tem a mesma operao bsica, mas com eco.
Ambas funes no requerem que o usurio digite [enter] para finalizar a sua execuo. Veja
exemplo abaixo, junto funo putch()

3.5 Putch() ou Putchar()


A funo putch() apresenta um nico caracter na tela, recebendo-o como parmetro. A
funo putchar() executa a mesma operao, com caracteres.
Exemplo:
/* Exemplo das funoes: getch(), getche(), putch() e putchar() */
#include <stdio.h>
#include <conio.h>
void main()
{
char c1, c2;
c1 = getch();
/* l caracter c1 mas no mostra na tela
c2 = getche();
/* l caracter c2, escrevendo-o na tela
printf("\nO primeiro valor digitado foi: ");
putch(c1);
/* escreve valor de c1 na tela
printf("\nO segundo valor digitado foi: ");
putchar(c2);
}

*/
*/
*/

3.6 Exerccios
3.1 Escreva um programa que contenha uma nica instruo e imprima na tela:
Esta e a linha um.
Esta e a linha dois.
3.2 Escreva um programa que imprima na tela:
Um
Dois
Trs.
3.3 Escreva um programa que pea os dados da conta bancria de um cliente e,
posteriormente, escreve na tela os dados do cliente tambm de forma organizada.
3.4 Escreva um programa que exemplifique todos os tipos de formataes fornecidas pro
printf().
3.5 Escreva um programa que pea ao usurio para entrar com um valor real (float),
converta este valor para uma varivel do tipo char e depois imprima o seu valor na tela em formato
decimal e em formato caracter.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
21

Curso de Linguagem Computacional C/C++

3.6 Faa um programa que pea ao usurio para entrar com um caracter , converta este
nmero para um valor inteiro e apresente na tela o valor deste nmero em formato float e o
endereo da varivel que o contm. Utilize ponteiros para armazenar e acessar este valor.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
22

Curso de Linguagem Computacional C/C++

4 Operadores
4.1 Operadores Aritmticos
C uma linguagem rica em operadores, em torno de 40. Alguns so mais usados que outros,
como o caso dos operadores aritmticos que executam operaes aritmticas.
C oferece 6 operadores aritmticos binrios (operam sobre dois operandos) e um operador
aritmtico unrio (opera sobre um operando). So eles:
Binrios:
=
Atribuio
+
Soma
Subtrao
*
Multiplicao
/
Diviso
%
Mdulo (devolve o resto da diviso inteira)
Unrio:
Menos unrio (indica a troca do sinal algbrico do valor)
O operador = j conhecido dos exemplos apresentados anteriormente. Em C, o sinal de
igual no tem a interpretao dada em matemtica. Representa a atribuio da expresso direita ao
nome da varivel esquerda.
Os operadores + - / * representam as operaes aritmticas bsicas de soma, subtrao,
diviso e multiplicao. A seguir est um programa que usa vrios operadores aritmticos e
converte temperatura Fahrenheit em seus correspondentes graus Celsius.
/* Programa Exemplo dos operadores: + - * / */
#include <stdio.h>
void main()
{
int ftemp = 0;
int ctemp = 0;
printf("Digite temperatura em graus Fahrenheit: ");
scanf("%d", &ftemp);
ctemp = (ftemp - 32)*5/9;
printf("Temperatura em graus Celsius e %d", ctemp);
}

O operador mdulo (%) aceita somente operandos inteiros. Resulta o resto da diviso do
inteiro sua esquerda pelo inteiro sua direita. Por exemplo, 17%5 tem o valor 2 pois quando
dividimos 17 por 5 teremos resto 2.

4.2 Operadores Relacionais


Os operadores relacionais so usados para fazer comparaes.
Em C no existe um tipo de varivel chamada booleana, isto , que assuma um valor
verdadeiro ou falso. O valor zero (0) considerado falso e qualquer valor diferente de 0
considerado verdadeiro e representado pelo inteiro 1. Os operadores relacionais comparam dois
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
23

Curso de Linguagem Computacional C/C++

operandos e retornam 0 se o resultado for falso e 1 se o resultado for verdadeiro. Os operadores


relacionais disponveis em C so:

Operador C
&&
||
!
<
<=
>
>=
==
!=
?:

Funo
E
OU
NO
MENOR
MENOR OU IGUAL
MAIOR
MAIOR OU IGUAL
IGUAL
DIFERENTE
OPERADOR CONDICIONAL TERNRIO

O programa a seguir mostra expresses booleanas como argumento da funo printf():


/* Exemplo de Operadores Relacionais */
#include <stdio.h>
void main()
{
int verdade, falso;
verdade = (15 < 20);
falso = (15 == 20);
printf("Verdadeiro= %d, falso= %d\n", verdade, falso);
}

Note que o operador relacional igual a representado por dois sinais de iguais. Um erro
comum o de usar um nico sinal de igual como operador relacional. O compilador no o avisar
que este um erro, por qu? Na verdade, como toda expresso C tem um valor verdadeiro ou falso,
este no um erro de programa e sim um erro lgico do programador.

4.3 Operadores lgicos binrios


Estes operadores so empregados para comparar os bits contidos em duas variveis, por isso,
so denominados operadores lgicos binrios. Ou seja, estes operadores fazem uma comparao
lgica entre cada bit dos operandos envolvidos. Os operadores binrios disponveis so:
Operador C
&
|
^
~
<<
>>

Funo
E lgico
OU lgico
Ou Exclusivo
No
Desloca esquerda
Desloca direita

A seguir temos um exemplo da aplicao destes operadores.


/* Exemplo usando Operadores Binarios */
#include <stdio.h>
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
24

Curso de Linguagem Computacional C/C++

void main()
{
int i, j, k;
i = 1;
j = 2;
printf("\ti = %x (00000001)\n\tj = %x (00000010)", i, j);
k = i & j; /* k = i AND j */
printf("\n\t i & j => %x (00000000)", k);
k = i ^ j; /* k = i XOR j */
printf("\n\t i ^ j => %x (00000011)", k);
k = i << 2; /* k = i deslocando 2 bits esquerda (4) */
printf("\n\t i << 2 => %x (00000100)", k);
}

Primeiro o programa faz uma comparao binria e(&) entre o nmero 1 (0x00000001) e o
nmero 2 (0x00000010). Por isso o resultado obtido logicamente 0, ou seja, 0x00000000.
Em seguida, o programa faz uma comparao binria ou (^) entre estes dois nmeros,
resultando agora, lgicamente, 3, ou seja, (0x00000011).
Por fim, o programa desloca o nmero 1 em duas casas para a esquerda, representado no
programa pelo operador << 2. Assim, o resultado o nmero 4 ou, em binrio, (0x00000100).
A partir deste exemplo fica clara a utilizao destes operadores.

4.4 Operadores de Ponteiros


Estes operadores j foram apresentados anteriormente na seco sobre ponteiros (ver 2.7). O
primeiro operador server para acessar o valor da varivel, cujo endereo est armazenado em um
ponteiro. O segundo operador server para obter o endereo de uma varivel.
Operador

&

Funo
Acesso ao contedo do ponteiro
Obtm o endereo de uma varivel

O programa abaixo apresenta novamente a aplicao destes operadores.


/* Operadores de Ponteiros */
void main()
{
int i, j, *ptr;
ptr = &i; /* atribui a ptr o endereo da varivel i */
j = *ptr; /* atribui a j o contedo do endereo definido por */
/* ptr = valor de i ! */
}

4.5 Operadores Incrementais e Decrementais


Uma das razes para que os programas em C sejam pequenos em geral que C tem vrios
operadores que podem comprimir comandos de programas. Neste aspecto, destaca-se os seguintes
operadores:
Operador Funo
++
Incrementa em 1
-Decrementa em 1

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
25

Curso de Linguagem Computacional C/C++

O operador de incremento (++) incrementa de um seu operando. Este operador trabalha de


dois modos. O primeiro modo chamado pr-fixado e o operador aparece antes do nome da
varivel. O segundo o modo ps-fixado em que o operador aparece seguindo o nome da varivel.
Em ambos os casos, a varivel incrementada. Porm quando ++n usado numa instruo,
n incrementada antes de seu valor ser usado, e quando n++ estiver numa instruo, n
incrementado depois de seu valor ser usado.
O programa abaixo mostra um exemplo destes operadores, ressaltando esta questo.
/* Operadores de Incremento */
#include <stdio.h>
void main()
{
int n, m, x, y;
n = m = 5;
x = ++n;
y = m++;
printf("O resultado e:\n n = %d; x = ++n = %d;\n m = %d; y = m++ =
%d;", n, x, m, y);
}

Vamos analisar duas expresses seguintes.


a) k = 3*n++;
Aqui, primeiro n multiplicado por 3, depois o resultado atribudo a k e,
finalmente, n incrementado de 1.
b) k = 3*++n;
Aqui, primeiro n incrementado em 1, depois n multiplicado por 3 e, por fim, o
resultado atribudo a k.
Dica: Para evitar problemas, faa uso de parnteses para guiar a exeuo do programa
evitando que o compilador no compreenda a ordem correta de executar a operao.
Abaixo, temos um outro exemplo dos operadores incrementais apresentado vrias aplicaes
destes operadores:
/* Operadore Incrementais 2 */
void main()
{
int i = 10;
int *ptr = 0;
i = i + 1; /* incrementa i */
i++;
/* incrementa i */
i = i - 1; /* decrementa i */
i--;
/* decrementa i */
ptr = &i; /* recebe o endereco de i */
(*ptr)++; /* incrementa valor de i */
ptr++;
/* incrementa em 2 Bytes (1 inteiro ocupa 2 Bytes) */
/* o valor do endereo apontado pelo ponteiro ptr */
}

Ateno para a ltima instruo ptr++. Esta instruo ir altera o endereo armazenado em
ptr. Se o valor deste ponteiro for acessado, o dado representado por este ponteiro no tem mais
nenhuma relao com a varivel i, podendo conter qualquer dado. Por isso, tome cuidado ao
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
26

Curso de Linguagem Computacional C/C++

manipular ponteiros para no acessar variveis com uso deconhecido. Isto poder fazer com que o
seu programa gere erros fatais para o sistema operacional.

4.6 Operadores de Atribuio


O operador bsico de atribuio (=) pode ser combinado com outros operadores para gerar
instrues em forma compacta.
Cada um destes operadores usado com um nome de varivel sua esquerda e uma
expresso sua direita. A operao consiste em atribuir um novo valor varivel que depender do
operador e da expresso direita.
Se x uma varivel, exp uma expresso e op um operador, ento:
x op= exp;
equivale a
x = (x)op(exp);
Operador C:
=
+=
-=
=
/=
%=
>>=
<<=
&=
|=
^=

Funo:
A = B
A += B;
A -= B;
A = B;
A /= B;
A %= B;
A >>= B;
A <<= B;
A &= B;
A |= B;
A ^= B;

A
A
A
A
A
A
A
A
A
A

=
=
=
=
=
=
=
=
=
=

A
A
A
A
A
A
A
A
A
A

+ B;
- B;
B;
/ B;
% B;
>> B;
<< B;
& B;
| B;
^ B;

Exemplo:
/* Operadores de Atribuiao */
#include <stdio.h>
void main()
{
int total = 0;
int cont = 10;
printf("Total=%d\n",
total += 1;
printf("Total=%d\n",
total ^= 2;
printf("Total=%d\n",
total <<= 2;
printf("Total=%d\n",
total *= cont;
printf("Total=%d\n",
}

total);
total);
total);
total);
total);

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
27

Curso de Linguagem Computacional C/C++

4.7 O Operador Lgico Ternrio


O operador condicional possui uma construo um pouco estranha. o nico operador em C
que opera sobre trs expresses. Sua sintaxe geral possui a seguinte construo:
exp1 ? exp2 : exp3

A exp1 avaliada primeiro. Se seu valor for differente de zero (verdadeira), a exp2
avaliada e seu resultado ser o valor da expresso condicional como um todo. Se exp1 for zero,
exp3 avaliada e ser o valor da expresso condicional como um todo.
Na expresso:
max = (a>b)?a:b

a varivel que contm o maior valor numrico entre a e b ser atribuda a max.
Outro exemplo:
abs = (x > 0) ? x : -x; // abs o valor absoluto de x

A expresso
printf( %d uma varivel %s !, x, ((x%2)?Impar:Par);

imprime mpar se x for um nmero mpar, caso contrrio imprimir par.

4.8 Precedncia
O operador ! o de maior precedncia, a mesma que a do operador unrio. A tabela seguinte
mostra as precedncias dos operadores:
Operadores
! - ++ -* / %
+ < > <= >=
== !=
&&
||
= += -= *=

/=

%=

Tipos
Unrios; no lgicos e menos aritmticos
Aritmticos
Aritmticos
Relacionais
Relacionais
Lgico &
Lgico OU
Atribuio

4.9 Exerccios:
4.1 Qual o resultado da seguinte expresso:
int a = 1, b = 2, c = 3;
int result = ++a/a&&!b&&c||b--||-a+4*c>!!b;

4.2 Escreva uma expresso lgica que resulte 1 se o ano for bissexto e 0 se o ano no for
bissexto. Um ano bissexto se for divisvel por 4, mas no por 100. Um ano tambm bissexto se
for divisvel por 400.
4.3 Faa um programa que solicite ao usurio o ano e imprima Ano Bissexto ou Ano
No-Bissexto conforme o valor da expresso do exerccio anterior. Utilize o operador condicional.
4.4 Num cercado, h vrios patos e coelhos. Escreva um programa que solicite ao usurio o
total de cabeas e o total de ps e determine quantos patos e quantos coelhos encontram-se nesse
cercado.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
28

Curso de Linguagem Computacional C/C++

4.5 Uma firma contrata um encanador a 20.000,00 por dia. Crie um programa que solicite o
nmero de dias trabalhados pelo encanador e imprima a quantia lquida que dever ser paga,
sabendo-se que so descontados 8% para imposto de renda.
4.6 Faa um programa que solicite um caractere do teclado por meio da funo getch(); se
for uma letra minuscula imprima-a em maiusculo, caso contrrio imprima o prprio caracter. Use
uma expresso condicional
4.7 Faa um programa que solicite ao usurio uma sequncia binria com 16 bits.
Transforme esta sequncia de 0 e 1 em um nmero inteiro. Depois manipule este nmero inteiro
para verificar se os bits 0, 3, 7, 14 esto habilitados (valor igual a 1). Pea a usurio se ele deseja
modificar algum bit especfico da palavra. Se ele quiser, modifique o bit desejado para o valor por
ele fornecido.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
29

Curso de Linguagem Computacional C/C++

5 Laos
Em C existem 3 estruturas principais de laos: o lao for, o lao while e o lao do-while.

5.1 O Lao For


O lao for engloba 3 expresses numa nica, e til principalmente quando queremos
repetir algo um nmero fixo de vezes.
Sintaxe:
for(incializacao ; teste ; incremento)
instruo;

Os parnteses, que seguem a palavra chave for, contm trs expresses separadas por pontoe-vrgulas, chamadas respectivamente de : expresso de inicializao, expresso de teste e
expresso de incremento. As 3 expresses podem ser compostas por quaisquer instrues vlidas
em C.
Incializao: executada uma nica vez na inicializao do lao. Serve para iniciar
variveis.
Teste: esta a expresso que controla o lao. Esta testada quando o lao inciado ou
reiniciado. Sempre que o seu resultado for verdadeiro, a instrues do lao sero
executadas. Quando a expresso se tornar falsa, o lao terminado.
Incremento: Define a maneira como a varivel de controle do lao ser alterada cada vez
que o lao repetido (conta++). Esta instruo executada, toda vez, imediatamente
aps a execuo do corpo do lao.
for( conta = 0; conta < 10; conta++ )
printf(conta=%d\n, conta);

Exemplo:
/*Laco For 1*/
#include <stdio.h>
void main()
{
int conta;
for(conta = 0; conta < 10; conta += 3)
printf("conta=%d\n", conta);
}

Qualquer uma das expresses de um lao for pode conter vrioas instrues separadas por
vrgulas. A vrgula na verdade um operador C que significa faa isto e isto. Um par de
expresses separadas por vrgula avaliado da esquerda para a direita.
/* Forma Flexivel do Lao for */
#include <stdio.h>
void main()
{
int x, y;
for( x=0, y=0; x+y < 100; x = x+1, y++)
printf("%d\n", x+y);
}
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
30

Curso de Linguagem Computacional C/C++

Podemos usar chamadas a funes em qualquer uma das expresses do lao.


Qualquer uma das trs partes de um lao for pode ser omitida, embora os pontos-e-vrgulas
devam permanecer. Se a expresso de inicializao ou a de incremento forem omitidas, elas sero
simplesmente desconsideradas. Se a condio de teste no est presente considerada
permanentemente verdadeira.
O corpo do lao pode ser composto por vrias instrues, desde que estas estejam
delimitadas por chaves { }. O corpo do lao pode ser vazio, entretanto o ponto-e-vrgula deve
permanecer para indicar uma instruo vazia.
Quando um lao est dentro de outro lao, dizemos que o lao interior est aninhado . Para
mostrar esta estrutura preparamos um programa que imprime tabuada.
/* tabuada */
#include <stdio.h>
void main()
{
int i,j,k;
printf("\n");
for(k=0; k<=1; k++)
{
printf("\n");
for(i=1; i<5; i++)
printf("Tabuada do %3d
", i+4*k+1);
printf("\n");
for(i=1; i<=9; i++)
{
for(j = 2+4*k; j<=5+4*k; j++)
printf("%3d x%3d = %3d
", j, i, j*i);
printf("\n");
}
}
}

5.2 O Lao While


O lao while utiliza os mesmos elementos que o lao for, mas eles so distribudos de
maneira diferente no programa.
Sintaxe:
while(expresso de teste)
instruo;

Se a expresso de teste for verdadeira (diferente de zero), o corpo do lao while ser
executado uma vez e a expresso de teste avaliada novamente. Este ciclo de teste e execuo
repetido at que a expresso de teste se torne falsa (igual a zero), ento o lao termina.
Assim como o for, o corpo do lao while pode conter uma instruo terminada por (;),
nenhuma instruo desde que possua um (;) e um conjunto de instrues separadas por chaves { }.
Abaixo temos um exemplo, onde um lao while substtuiu um antigo lao for.
/*Laco While 1*/
#include <stdio.h>
void main()
{
int conta = 0;
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
31

Curso de Linguagem Computacional C/C++

while(conta < 10)


{
printf("conta=%d\n", conta);
conta++;
}
}

Quando se conhece a priori o nmero de loops que o lao deve fazer, recomenda-se o uso do
lao for. Caso o nmero de iteraes dependa das instrues executadas, ento se recomenda o uso
do lao while.
Os laos while podem ser aninhados como o lao for. C permite que no inteior do corpo de
um lao while, voc possa utilizar um outro lao while.

5.3 O Lao Do-While


O lao Do-While cria um ciclo repetido at que a expresso de teste seja falsa (zero). Este
lao bastante similar ao lao while.
A diferena que no lao do-while o teste de condio avaliado depois do lao ser
executado. Assim, o lao do-while sempre executado pelo menos uma vez.
Sintaxe:
do
{
instruo;
} while(expresso de teste);

Embora as chaves no sejam necessrias quando apenas uma instruo est presente no
corpo do laop do-while, elas so geralmente usadas para aumentar a legibilidade.
Exemplo usando os laos while e do-while:
/* Programa de Exemplo do laco Do-While */
#include <stdio.h>
#include <conio.h>
#include <stdlib.h> /* requerida para rand() */
void main()
{
char ch, c;
int tentativas;
do
{
ch = rand()%26 + 'a';
tentativas = 1;
printf("\nDigite uma letra de 'a' a 'Z':\n");
while((c=getch())!= ch)
{
printf("%c e incorreto. Tente novamente. \n\n",c);
tentativas++;
}
printf("\n%c e correto",c);
printf("\nvoce acertou em %d tentativas", tentativas);
printf("\nQuer jogar novamente? (s\\n): ");
}while(getche()=='s');
}

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
32

Curso de Linguagem Computacional C/C++

5.4 Break e Continue


O comando break pode ser usado no corpo de qualquer estrutura do lao C. Causa a sada
imediata do lao e o controle passa para o prximo estgio do programa. Se o comando break
estiver em estruturas de laos aninhados, afetar somente o lao que o contm e os laos internos a
este.
O comando continue fora a prxima interao do lao e pula o cdigo que estiver abaixo.
Nos while e do-while um comando continue faz com que o controle do programa v diretamente
para o teste condicional e depois continue o processo do lao. No caso do lao for, o computador
primeiro executa o incremento do lao e, depois, o teste condicional, e finalmente faz com que o
lao continue.

5.5 Goto
O comando goto faz com que o programa pule para a instruo logo aps o label passado
como parmetro. Este comando desnecessrio e desaconselhado. Foi implementado somente para
manter a compatibilidade com outros compiladores.
A instruo goto tem duas partes: a palavra goto e um nome. O nome segue as convees de
nomes de variveis C. Por exemplo:
goto parte1;

Para que esta instruo opere, deve haver um rtulo (label) em outra parte do programa. Um
rtulo um nome seguindo por dois pontos.
parte1:
printf(Anlise dos Resultados.\n);

A instruo goto causa o desvio do controle do programa para a instruo seguinte ao rtulo
com o nome indicado. Os dois pontos so usados para separar o nome da instruo.

5.6 Exerccios
5.1 Escreva um programa que imprima os caracteres da tabela ASCII de cdigos de 0 a 255.
O programa deve imprimir cada caracter, seu cdigo decima e hexadecimal. Monte uma tabela
usando os parmetros de formatao de printf().
5.2 Escreva um programa, utilizando um lao while, que leia caracteres do teclado.
Enquanto o usurio no pressionar a tecla ESC de cdigo 27, os caracteres lidos no so ecoados no
vdeo. Se o caracter lido for uma letra minscula, o programa a imprime em maisculo e, se for
qualquer outro caracter, ele mesmo impresso.
5.3 Elabore um programa que solicite um nmero inteiro ao usurio e crie um novo nmero
inteiro com os dgitos em ordem inversa. Por exemplo o nmero 3567 deve ser escrito 7653.
5.4 Escreva um programa que desenhe uma moldura na tela do micro, desenhando um sol
com as tuas iniciais no meio da tela e escrevendo Feliz Natal e o seu nome embaixo.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
33

Curso de Linguagem Computacional C/C++

6 Comandos para Tomada de Deciso


Uma das tarefas fundamentais de qualquer programa decidir o que deve ser executado a
seguir. Os comandos de deciso permitem determinar qual a ao a ser tomada com base no
resultado de uma expresso condicional. Isto significa que podemos selecionar entre aes
alternativas dependendo de critrios desenvolvidos no decorrer da execuo do programa.
C oferece 3 principais estruturas de deciso: if, if-else, switch. Estas estruturas so o tema
deste captulo.

6.1 If
O comando if usado para testar uma condio e caso esta condio seja verdadeira, o
programa ir executar uma instruo ou um conjunto delas. Este um dos comandos bsicos para
qualquer linguagem de programao.
Sintaxe:
if(expresso de teste)
instruo;

Como C no possui variveis booleanas, o teste sobre a condio opera como os operadores
condicionais, ou seja, se o valor for igual a zero (0) a condio ser falsa e se o valor for diferente
de zero, a condio ser verdadeira.
Como os laos, o comando if pode ser usado para uma nica instruo ou para um
conjunto delas. Caso se utilize para um conjunto de instrues, este conjunto deve ser delimitado
por chaves { e }.
Um comando if pode estar dentro de outro comando if. Dizemos ento que o if interno
est aninhado.
O programa abaixo mostra exemplos do uso e da sintaxe dos comandos if. O primeiro if
mostra a forma aninhada do comando if, o segundo apresenta a sintaxe bsica e o ltimo um
exemplo onde o comando if executa um bloco de instrues.
/* Programa exemplo para o comando if */
#include <stdio.h>
#include <conio.h>
void main()
{
char ch;
printf("Digite uma letra de 'a' a 'Z':");
ch = getche();
if(ch >= 'A')
/* Dois comandos if aninhados */
if(ch <= 'z')
printf("\n Voce digitou um caracter valido!");
if(ch == 'p') /* Forma basica de um comando if */
printf("\nVoce pressionou a tecla 'p'!");
if(ch != 'p') /* Comando if executando um bloco de instrucoes */
{
printf("\nVoce nao digitou a tecla 'p'!);
printf(\n Digite qualquer caracter para finalizar.");
ch = getche();
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
34

Curso de Linguagem Computacional C/C++

}
}

6.2 If-Else
No exemplo anterior o comando if executar uma nica instruo ou um grupo de
instrues, se a expresso de teste for verdadeira. No far nada se a expresso de teste for falsa.
O comando else, quando associado ao if, executar uma instruo ou um grupo de
instrues entre chaves, se a expresso de teste do comando if for falsa.
O if-else tambm permite o aninhamento de outros comandos if, ou if-else dentro
do bloco de instrues do aps o else.
Sintaxe:
if(expresso de teste)
instruo_1;
else
instruo_2;

Exemplo:
/* Programa exemplo do If-Else */
#include <stdio.h>
void main()
{
int x, y;
for(y=1; y<24; y++) /* passo de descida */
{
for(x=1; x<24; x++) /* passo de largura */
if(x==y || x==24-y) /* diagonal? */
printf("\xDB"); /* cor escura */
else
printf("\xB0"); /* cor clara */
printf("\n"); /* Nova Linha */
}
}

6.3 Switch
O comando switch permite selecionar uma entre vrias aes alternativas. Embora
construes if-else possam executar testes para escolha de uma entre vrias alternativas, muitas
vezes so deselegantes. O comando switch tem um formato limpo e claro.
A instruo switch consiste na palavra-chave switch seguida do nome de uma varivel
ou de um nmero constante entre parnteses. O corpo do comando switch composto de vrios
casos rotulados por uma constante e opcionalmente um caso default. A expresso entre
parnteses aps a palavra-chave switch determina para qual caso ser desviado o controle do
programa.
O corpo de cada caso composto por qualquer nmero de instrues. Geralmente, a ltima
instruo break. O comando break causa a sada imediata de todo o corpo do switch. Na
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
35

Curso de Linguagem Computacional C/C++

falta do comando break, todas as instrues aps o caso escolhido sero executadas, mesmo as
que pertencem aos casos seguintes.
Sintaxe:
switch(varivel ou constante)
{
case constante1:
instruo;
instruo;
break;
case constante2:
instruo;
instruo;
break;
case constante3:
instruo:
instruo:
break;
default:
instruo;
instruo;
}

Voc no poder usar uma varivel nem uma expresso lgica como rtulo de um caso. Pode
haver nenhuma, uma ou mais instrues seguindo cada caso. Estas instrues no necessitam estar
entre chaves.
O corpo de um switch deve estar entre chaves.
Se o rtulo de um caso for igual ao valor da expresso do switch, a execuo comea nele.
Se nenhum caso for satisfeito e existir um caso default, a execuo comear nele. Um caso
default opcional.
No pode haver casos com rtulos iguais.
A seguir apresentamos um exemplo que calcula o dia da semana a partir de uma data. O ano
deve ser maior ou igual a 1600, pois nesta data houve uma redefinio do calendrio.
/* Exemplo do comando switch */
/* Calcula o dia da semana a partir de uma data */
#include <stdio.h>
#include <conio.h>
void main()
{
int D, M, A, i;
long int F = 0;
do
{
do
{
printf("\nDigite uma data na forma dd/mm/aaaa: ");
scanf("%d/%d/%d", &D, &M, &A);
} while(A<1600 || M<1 || M>12 || D<1 || D>31);
F = A + D + 3*(M-1) - 1;
if(M<3)
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
36

Curso de Linguagem Computacional C/C++

{
A--;
i = 0;
}
else
i = .4*M+2.3;
F+= A/4 - i;
i = A/100 + 1;
i *= .75;
F -= i;
F %= 7;
switch(F)
{
case 0:
printf("\nDomingo");
break;
case 1:
printf("\nSegunda-Feira");
break;
case 2:
printf("\nTerca-Feira");
break;
case 3:
printf("\nQuarta-Feira");
break;
case 4:
printf("\nQuinta-Feira");
break;
case 5:
printf("\nSexta-Feira");
break;
case 6:
printf("\nSabado");
break;
}
}while(getche()!=27); /* Tecla ESC nao for pressionada */
}

6.4 Exerccios
6.1 Crie um programa que desenhe na tela um tabuleiro de xadrez.
6.2 Crie um programa que desenhe na tela o seu quadro de horrios deste semestre.
6.3 Escreva um programa que solicite ao usurio trs nmeros inteiros a, b, e c onda a
maior que 1. Seu programa deve somar todos os inteiros entre b e c que sejam divisveis por a.
6.4 A sequncia de Fiboncci a seguinte:
1, 1, 2, 3, 5, 8, 13, 21, ...
os dois primeiros termos so iguais a 1. Cada termo seguinte igual `a soma dos dois
anteriores. Escreva um programa que solicitie ao usurio o nmero do termo e calcule o valor do
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
37

Curso de Linguagem Computacional C/C++

termo. Por exemplo: se o nmero fornecido pelo usurio for igual a 7, o programa dever imprimir
13.
6.5 Implemente um jogo da velha, onde o programa desenha na tela um tabuleiro e voc
pede a dois usurios (A e B) na respectiva ordem, que jogada eles querem realizar e depois atualiza
o desenho. O programa deve perceber quando o jogo acabou e anunciar o vencedor.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
38

Curso de Linguagem Computacional C/C++

7 Funes
As funes servem para agrupar um conjunto de instrues de acordo com a tarefa que elas
desempenham. Uma vez implementada corretamente esta tarefa, voc no precisa mais se preocupar
em implementar esta tarefa, basta usar a sua funo. Por exemplo, quando usamos printf() para
imprimir informaes na tela, no nos preocupamos como o programa realiza esta tarefa, pois a
funo j fornecia este servio de forma adequada.
As funes quando bem empregadas, facilitam bastante a organizao modular do programa,
permitem a reutilizao de partes do programa e facilitam a sua manuteno.
Uma funo uma unidade de cdigo de programa autnoma desenhada para cumprir uma
tarefa particular. Provavelmente a principal razo da existncia de funes impedir que o
programador tenha que escrever o mesmo cdigo repetidas vezes.

7.1 Sintaxe
A estrutura de uma funo C bastante semelhante da funo main(). A nica diferena
que main()possui um nome especial pois a funo main() a primeira a ser chamada quando o
programa executado.
Sintaxe:
<tipo retorno> <nome>(<tipo parmetro> <nome parmentro>, <...> <...>)
{
<declaraes locais>;
<comandos>;
return <expresso ou valor compatvel com o tipo de retorno>;
}

O tipo de retorno define o tipo de dado o qual a funo retornar com o resultado de sua
execuo. Nome indica qual o nome da funo.
Em seguida temos a lista de argumentos da funo inseridos entre os parnteses aps o nome
da funo e separados por vrgulas. Os argumentos so declarados no cabealho da funo com o
tipo parmetro e em seguida o nome do parmetro. Uma funo pode ter tantos argumentos quanto
voc queira definir. Quando uma funo no necessita de parmetros, o nome desta deve ser
seguido por parnteses ( ) sem nenhum parmetro no seu interior.
A lista de instrues a serem executadas pela funo vem aps a lista de parmetros e deve
ser delimitada por chaves { e }. As instrues utilizam os parmetros para executarem a tarefa.
Dentro do bloco de instrues da funo, primeiramente declara-se e inicializa-se as
variveis locais e posteriormente temos os comandos da funo (instrues).
O comando return encerra a funo e retorna ao ponto do programa onde esta foi
chamada. No entanto, return no precisa ser o ltimo comando da funo. Infelizmente, uma
funo em C s pode retornar um resultado e este repassado atravs de return. Algumas
linguagens como Matlab permitem que uma funo retorne mais do que uma nica varivel
contendo o resultado.
Funes com tipo de retorno void, no utilizam o comando return pois estas no
retornam nenhum tipo de dado. O comando return utilizado quando queremos finalizar esta
funo antes de executar todas as instrues. Neste caso, ele aparece sem nenhum parmetro a sua
direita, somente o ponto-e-vrgula. Quando uma funo no tem um tipo de retorno definido, o
compilador C considera que o tipo de retorno adotado void.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
39

Curso de Linguagem Computacional C/C++

Do mesmo modo que chamamos uma funo de biblioteca C (printf(), getche(), ...)
chamamos nossas prprias funes. Os parnteses que seguem o nome so necessrios para que o
compilador possa diferenciar a chamada a uma funo de uma varivel que voc esqueceu de
declarar. Visto que a chamada de uma funo constitui uma instruo de programa, deve ser
encerrada por ponto-e-vrgula. Entretanto, na definio de uma funo, o ponto-e-vrgula no pode
ser usado.

7.2 Exemplos
Abaixo apresentamos um exemplo do emprego das funes:
/* Beeptest - Exemplo do uso de funcoes */
/* Testa a funcao doisbeep */
#include <stdio.h>
/* doisbeep() */
/* toca o auto-falante duas vezes */
doisbeep()
{
int k;
printf("\x7");
/* Beep 1 */
for(k=1; k<10000; k++)
/* Gera um pequeno delay */
;
printf("\x7");
/* Beep 2 */
}
/* funao principal */
void main()
{
doisbeep();
printf("Digite um caracterere: ");
getche();
doisbeep();
}

A declarao da funo doisbeep() equivalente a seguinte declarao:


void doisbeep(void)

isto acontece pois quando o tipo retornado ou o parmetro for void (representando que nenhum
dado ser passado), estes podem ser omitidos j que C considera este tipo como default.
Em C, todos os argumentos de funes so passados por valor. Isto significa que funo
chamada dada uma cpia dos valores dos argumentos, e ela cria outras variveis temporrias para
armazenar estes valores. A diferena principal que, em C, uma funo chamada no pode alterar o
valor de uma varivel da funo que chama; ela s pode alterar sua cpia temporria.
C permite a criao de funes recursivas, isto , uma funo que dentro do seu corpo de
instrues {} existe uma chamada de funo a si prpria. Este caso funciona como uma chamada
para uma outra funo qualquer. Basta que na definio da funo voc faa uma chamada prpria
funo e voc j ter implementado uma funo recursiva. Entretanto, tenha cuidado com funes
recursivas para no fazer com que o programa entre em loops infinitos. Exemplo:
long int Fatorial(long int i)
{
if(i > 1)
return i*Fatorial(i-1);
else return 1;
}
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
40

Curso de Linguagem Computacional C/C++

Cada chamada recursiva da funo fatorial coloca mais uma varivel i do tipo long int na
pilha (stack). portanto necessrio ter cuidado com funes recursivas, pois estas podem causar um
estouro da pilha.
/* Esfera - Exemplo de funcao */
/* calcula a area da esfera */
#include <stdio.h>
float area(float r); /* declaracao do prototipo da funcao */
float potencia(float num, int pot);
void main()
{
float raio = 0;
printf("Digite o raio da esfera: ");
scanf("%f", &raio);
printf("A area da esfera e' %.2f", area(raio));
}
/* area() */
/* retorna a area da funcao */
float area(float r) /* definicao da funcao */
{
return (4*3.14159*potencia(r,2));
/* retorna float */
}
/* potencia() */
/* eleva a uma potencia positiva um parametro dado */
float potencia(float num, int pot)
{
float result = 0;
/* declaracao de var. local */
int i = 0;
if(pot < 0)
return 0; /* Indica que houve erro */
if(pot == 0)
return 1;
result = num;
for(i = 1; i < pot; i++)
result *= num;
return result;
}

7.3 Prototipagem
Toda funo que for utilizada em main() e que for declarada aps main(), tem que ser
prototipada. O prottipo consiste de uma verso simplificada do cabealho da funo, na forma:
<tipo retorno> <nome da funo> (<tipo dos parmetros>);

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
41

Curso de Linguagem Computacional C/C++

Se main() for declarado por ltimo, nenhuma prototipagem necessria. Prottipos so


tambm utilizados para escrever programas compostos de vrios mdulos, como veremos mais
frente. Feita a declarao do prottipo da funo, esta poder ser chamada ou definida em qualquer
parte do seu programa, por isso que o prottipo de uma funo tem um papel importante para a
organizao e flexibilidade do seu cdigo fonte.
O programa anterior e o exemplo abaixo apresentam a forma de se criar o prottipo de uma
funo.
double Raiz(double); /* prottipo */
main()
{
double x,y;
x = 4.0;
y = Raiz(x);
}
double Raiz(double valor)
{
/* <calculo da raiz do valor>; */
return valor;
}

7.4 Classes de Armazenamento


Todas as variveis e funes em C tm dois atributos: um tipo e uma classe de
armazenamento. Os tipos ns j conhecemos. As 4 classes de armazenamento sero vistas a seguir:
auto, extern, static e register.

7.4.1 Auto
As variveis que temos visto em todos os nossos exemplos esto confinadas nas funes que
as usam; isto , so visveis ou acessveis somente s funes onde esto declaradas. Tais variveis
so chamadas locais ou automticas, pois so criadas quando a funo chamada e destrudas
quando a funo termina a sua execuo.
As variveis declaradas dentro de uma funo so automticas por default. Variveis
automticas so as mais comuns dentre as 4 classes. A classe de variveis automticas pode ser
explicitada usando-se a palavra auto.
As duas declaraes abaixo so equivalentes:
auto int n;
int n;

7.4.2 Extern
Todas as funes C e todas as variveis declaradas fora de qualquer funo tm a classe de
armazenamento extern. Variveis com este atributo sero conhecidas por todas as funes
declaradas depois dela. A declarao de variveis externas feita da mesma maneira como
declaramos variveis dentro do bloco de uma funo.
Uma varivel definida fora de qualquer funo dita extern. A palavra extern indica
que a funo usar mais uma varivel externa. Este tipo de declarao, entretanto, no obrigatrio
se a definio original ocorre no mesmo arquivo fonte. Abaixo temos um exemplo:
/* Exemplo da variavel de tipo extern */
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
42

Curso de Linguagem Computacional C/C++

#include <stdio.h>
/* Declaracao de variaveis extern */
int teclanum;
/* Declaracao de funcoes */
void parimpar(void);
void main()
{
extern teclanum;
printf("Digite teclanum: ");
scanf("%d", &teclanum);
parimpar();
}
/* parimpar() */
/* checa se teclanum e' par ou impar */
void parimpar(void)
{
extern teclanum;
if(teclanum % 2)
printf("teclanum e' impar. \n");
else
printf("teclanum e' par. \n");
}

7.4.3 Static
Variveis static de um lado se assemelham s automticas, pois so conhecidas somente
as funes que as declaram e de outro lado se assemelham s externas pois mantm seus valores
mesmo quando a funo termina.
Declaraes static tm dois usos importantes e distintos. O mais elementar permitir a
variveis locais reterem seus valores mesmo aps o trmino da execuo do bloco onde esto
declaradas.
/* uso do tipo static */
#include <stdio.h>
/* declaracao de prototipo */
void soma();
void main()
{
soma();
soma();
soma();
}
/* soma() */
/* usa variavel static */
void soma()
{
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
43

Curso de Linguagem Computacional C/C++

static int i = 0;
i++;
printf("i = %d\n", i);
}

Observe que i no inicializada a cada chamada de soma(). Portanto, a sada ser:


i = 0
i = 1
i = 2

7.4.4 Variveis Estticas Externas


O segundo e mais poderoso uso de static associado a declaraes externas. Junto a
construes externas, permite um mecanismo de privacidade muito importante programao
modular.
A diferena entre variveis externas e externas estticas que variveis externas podem ser
usadas por qualquer funo abaixo de (a partir das) suas declaraes, enquanto que variveis
externas estticas somente podem ser usadas pelas funes de mesmo arquivo-fonte e abaixo de
suas declaraes. Isto , voc pode definir uma varivel static em um arquivo fonte onde esto
todas as funes que necessitam acesso a esta varivel. Os demais arquivos fontes no tero acesso
a ela.

7.4.5 Register
A classe de armazenamento register indica que a varivel associada deve ser guardada
fisicamente numa memria de acesso muito mais rpida chamada registrador. Um registrador da
mquina um espao de memria junto ao microprocessador onde se podem armazenar variveis
do tipo inteiro ou char. Opera como uma varivel do tipo auto, mas possui um tempo de acesso
muito mais rpido, isto , o programa torna-se mais rpido usando register. Variveis que
usualmente utilizam este tipo so as variveis de laos e argumentos de funes, justamente, para
que possamos aumentar a velocidade do programa.
Como os computadores possuem um nmero limitado de registradores (2 para o IBM-PC), o
seu programa tambm s poder utilizar um nmero limitado de variveis register. Mas isto
no nos impede de declarar quantas variveis register quisermos. Se os registradores estiverem
ocupados o computador simplesmente ignora a palavra register das nossas declaraes.
register int i;
for(i = 0; i< 10; i++)
printf(Nmero: %d, i);

7.5 Exerccios
7.1 Um nmero primo qualquer inteiro positivo divisvel apenas por si prprio e por 1.
Escreva uma funo que receba um inteiro positivo e, se este nmero for primo, retorne 1, caso
contrrio retorne 0. Faa um programa que imprima na tela os n primeiros nmeros primos, onde
n ser fornecido pelo usurio.
7.2 Crie um programa para gerar nmeros aleatrios, utilizando variveis static para
armazenar o valor da semente.
7.3 Crie um programa para calcular o fatorial de um nmero, para tal implemente uma
funo recursiva.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
44

Curso de Linguagem Computacional C/C++

7.4 Escreva um programa que solicite ao usurio um ano e imprima o calendrio desse ano.
Utilize os programas desenvolvidos nos exerccios 4.2 e 4.3. Organize o programa de forma
adequada atravs de funes.
7.5 Escreva uma funo recursiva de nome soma() que receba um nmero inteiro positivo n
como argumento e retorne a soma dos n primeiros nmeros inteiros. Por exemplo, se a funo
recebe n = 5, deve retornar 15, pois:
15 = 1 + 2 + 3 + 4 + 5

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
45

Curso de Linguagem Computacional C/C++

8 Diretivas do Pr-Processador
O pr-processador C um programa que examina o cdigo fonte em C e executa certas
modificaes no cdigo, baseado em instrues chamadas diretivas. O pr-processador faz parte do
compilador e pode ser considerado uma linguagem dentro da linguagem C. Ele executado
automaticamente antes da compilao. Diretivas do pr-processador seriam instrues desta
linguagem. As instrues desta linguagem so executadas antes do programa ser compilado e tm a
tarefa de alterar os cdigos-fonte, na sua forma de texto.
Instrues para o pr-processador devem fazer parte do texto que criamos, mas no faro
parte do programa que compilamos, pois so retiradas do texto compilador antes da compilao.
Diretivas do pr-processador so instrues para o compilador propriamente dito. Mais
precisamente, elas operam diretamente no compilador antes do processo de compilao ser iniciado.
Linhas normais de programa so instrues para o microprocessador; diretivas do pr-processador
so instrues para o compilador.
Todas as diretivas do pr-processador so iniciadas com o smbolo (#). As diretivas podem
ser colocadas em qualquer parte do programa, mas costume serem colocadas no incio do
programa, antes de main(), ou antes do comeo de uma funo particular.

8.1 Diretiva #define


A diretiva #define pode ser usada para definir constantes simblicas com nomes
apropriados. Como por exemplo, podemos criar uma constante para conter o valor de pi:
#define

PI

3.14159

e depois utilizar o valor desta constante no programa:


area_esfera = (4*raio*raio*PI);

Quando o compilador encontra #define, ele substitui cada ocorrncia de PI no programa


por 3.14159.
O primeiro termo aps a diretiva #define (PI), que ser procurada, chamada
identificador. O segundo termo (3.14159), que ser substituda, chamada texto. Um ou mais
espaos separam o identificador do texto.
Note que s podemos escrever um comando deste por linha. Observe tambm que no h
ponto-e-vrgula aps qualquer diretiva do pr-processador.
A diretiva #define pode ser usada no s para definir constantes, como mostra o exemplo
seguinte:
#include <stdio.h>
#define
ERRO printf("\n Erro.\n")
void main()
{
int i;
printf("\nDigite um numero entre 0 a 100: ");
scanf("%d", &i);
if(i<0||i>100)
ERRO;
}

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
46

Curso de Linguagem Computacional C/C++

8.2 Macros
A diretiva #define tem a habilidade de usar argumentos. Uma diretiva #define com
argumentos chamada de macro e bastante semelhante a uma funo. Eis um exemplo que ilustra
como macro definida e utilizada:
/* Exemplo do uso de Macros*/
#include <stdio.h>
#define
PRN(n)
printf("%.2f\n",n);
void main()
{
float num1 = 27.25;
float num2;
num2 = 1.0/3.0;
PRN(num1);
PRN(num2);
}

Quando voc usar a diretiva #define nunca deve haver espao em branco no identificador.
Por exemplo, a instruo
#define PRN (n) printf(%.2f\n,n)

no trabalhar corretamente, porque o espao entre PR e (n) interpretado como o fim do


identificador.
Para definir um texto muito grande devemos delimitar a linha anterior com uma barra
invertida \ e prosseguir com a definio em outra linha.
Toda ocorrncia de PRN(n) em seu programa substituda por
printf(%.2f\n,n). O n na definio da macro substitudo pelo nome usado na chamada a
macro
em
seu
programa;
portanto,
PRN(num1)ser
substitudo
por
printf(%.2f\n,num1). Assim, n age realmente com um argumento.
Macros aumentam a clareza do cdigo, pois permitem a utilizao de nomes sugestivos para
expresses.
Por segurana, coloque parnteses envolvendo o texto todo de qualquer diretiva #define que
use argumentos, bem como envolvendo cada argumento. Por exemplo:
#define SOMA(x,y) x+y
ans = 10 * SOMA(3,4);

O complilador substitura SOMA(3,4) por 3+4, e o computador executar:


ans = 10 * 3+4;

ou seja, um erro. Para evitar isto, voc deve definir a macro da seguinte forma:
#define

SOMA(x,y)

((x)+(y))

Como macros so simples substituies dentro dos programas, o seu cdigo aparecer em
cada ponto do programa onde forem usadas. Assim, a execuo do programa ser mais rpida que a
chamada a uma funo toada vez que se fizer necessrio. Em contra partida, o cdigo do programa
ser aumentado, pois o cdigo da macro ser duplicado cada vez que a macro for chamada. Outra
vantagem do uso de macros a no necessidade de especificar o tipo do dado.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
47

8.3 Diretiva #undef


A diretiva #undef remove a mais recente definio criada com #define.
#define
#define
#define
...
#undef
#define
...
#undef
...
#undef
...
#undef

GRANDE
ENORME
SOMA(x,y)

3
8
((x)+(y))

GRANDE
ENORME 10

/* cancela a definio de GRANDE


/* redefine ENORME para o valor 10

*/
*/

ENORME

/* ENORME volta a valer 8

*/

ENORME

/* cancela a definio de ENORME

*/

SOMA

/* cancela a macro SOMA

*/

Observe que, para remover uma macro, somente o nome da macro deve constar na diretiva
#undef. No deve ser includa a lista de argumento.

8.4 Diretiva #include


A diretiva #include causa a incluso de um cdigo fonte em outro.
Aqui est o exemplo de sua utilidade: suponha que voc escreveu vrias frmulas
matemticas para calcular reas de diversas figuras.
Os arquivos de incluso so textos escritos em caracteres ASCII normais, criados
geralmente para incorporar definies de constantes, macros, prottipos de funes, definies de
tipos de dados complexos e declaraes de variveis externas. Geralmente, os arquivos de incluso
tm nome terminado com o sufixo .H (header ou cabealho).
Por exemplo, o arquivo conio.h contm o prottipo das funes getch() e getche()
e por esse motivo includo nos programas que fazem uso destas funes.
Voc pode colocar estas frmulas em macros em um programa separado. No instante em
que voc precisar reescrev-las para a utilizao em seu programa use a diretiva #include para
inserir este arquivo no seu cdigo fonte. Exemplo:
#define
#define
#define
#define

PI
AREA_CIRCULO(raio)
AREA_RETANG(base,altura)
AREA_TRIANG(base,altura)

3.14159
(PI*(raio)*(raio))
((base)*(altura))
((base)*(altura)/2)

Grave o programa acima como areas.h. Quando voc quiser utilizar estas macros, basta
incluir nos seus outros programas uma das diretivas:
#include <areas.h> /* para arquivos localizados na biblioteca do compilador */
#include areas.h /* para arquivos locais ou localizados na biblioteca do compilador */
O uso consciente das diretivas #define e #include podem melhorar e muito o desempenho e
a organizao dos seus projetos de software. Procure explor-las para conhecer todo os seus
potenciais.

Curso de Linguagem Computacional C/C++

8.5 Compilao Condicional


O pr-processador oferece diretivas que permitem a compilao condicional de um
programa. Elas facilitam o desenvolvimento do programa e a escrita de cdigos com maior
portabilidade de uma mquina para outra ou de um ambiente a outro. So elas, as diretivas:
#if, #ifdef, #ifndef, #elif, #else e #endif

Cada diretiva #if deve terminar pela diretiva #endif. Entre #if e #endif pode ser
colocado qualquer nmero de #elif, mas s se permite uma nica diretiva #else. A diretiva
#else opcional e, se estiver presente, deve ser a ltima anterior a #endif.
Abaixo apresentamos um exemplo onde definimos o valor de uma constante com #define
e depois a utilizamos para fazer uma compilao condicional :
#define DEBUG 1
...
#if DEBUG == 1
printf(\nERRO = , erro1);
#elif DEBUG == 2
printf(\nERRO = , erro2);
#else
printf(\nERRO no documentado.);
#endif

Para testar constantes definidas com #define que no tenham valor nenhum, podemos
utilizar #ifdef e #ifndef. Por exemplo:
#define VERSAO_DEMO
...
#ifdef VERSAO_DEMO
#define
NUM_REC
20
#include
progdemo.h
else
#define
NUM_REC
MAXINT
#include
program.h
#endif

O ltimo exemplo mostra como um nico programa-fonte pode gerar dois executveis
diferentes: se a diretiva que define VERSAO_DEMO for inserida, o executvel poder manipular
somente 20 registros e estar criada a verso demo de seu programa. Caso esta diretiva no esteja
presente, o programa poder manipular o nmero mximo de registros.
A diretiva #ifndef verifica a no-definio da constante. Por exemplo:
#ifndef WINDOWS
#define VERSAO \nVerso DOS
#else
#define VERSAO \nVerso Windows
#endif

8.6 Operador defined


Uma alternativa ao uso de #ifdef e #ifndef o operador defined.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
49

Curso de Linguagem Computacional C/C++

#if defined(UNIX) && !defined(INTEL_486)


...
#endif

8.7 Diretiva #error


A diretiva #error provoca uma mensagem de erro do compilador em tempo de
compilao.
#if TAMANHO > TAMANHO1
#error Tamanho incompatvel
#endif

8.8 diretiva #pragma

#pragma inline - indica ao compilador C a presena de cdigo Assembly no arquivo.


#pragma warn - indica ao compilador C para ignorar "warnings" (avisos)

8.9 Exerccios
8.1 Escreva uma macro que tenha valor 1 se o seu argumento for um nmero mpar, e o
valor 0 se for par.
8.2 Escreva uma macro que encontre o maior entre seus trs argumentos.
8.3 Escreva uma macro que tenha valor 1 se o seu argumento for um caractere entre 0 e
9, e 0 se no for.
8.4 Escreva uma macro que converta um dgito ASCII entre 0 e 9 a um valor numrico
entre 0 e 9.
8.5 Escreva um programa que solicite ao usurio uma letra e retorne o nmero equivalente
desta letra na tabela ASCII em decimal e hexadecimal. Utilize a compilao condicional para gerar
um programa com interface para diferentes lnguas, por exemplo uma para portugus e outra para
ingls. Caso nenhuma das duas for definida, gere um erro de compilao. Dica, coloque o texto de
cada lngua em um header diferente. Por exemplo, os textos em portugus ficam definidos em
progport.h e os textos em ingls em progingl.h
8.6 Faa com que o programa do exerccio 7.4, escreva o calendrio de um ano qualquer
dado pelo usurio em trs lnguas diferentes: alemo, ingls e portugus. Utilize a mesma idia que
o programa anterior.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
50

Curso de Linguagem Computacional C/C++

9 Matrizes
Uma matriz um tipo de dado usado para representar uma certa quantidade de variveis de
valores homogneos.
Imagine que voc esteja precisando armazenar e manipular as notas de um ano inteiro de um
conjunto de 40 alunos. Voc certamente precisar de uma maneira conveniente para referenciar tais
colees de dados similares. Matriz o tipo de dado oferecido por C para este propsito.
Um matriz uma srie de variveis do mesmo tipo referenciadas por um nico nome, onde
cada varivel diferenciada atravs de um nmero chamado subscrito ou ndice. Colchetes so
usados para conter o subscrito. A declarao:
int notas[5];

aloca memria para armazenar 5 inteiros e anuncia que notas uma matriz de 5 membros ou
elementos.
Vamos agora fazer um programa que calcula a mdia das notas da prova do ms de Junho de
5 alunos.
/* Exemplo de matrizes
/* media das notas de 5 alunos
#include
#define

<stdio.h>
NUM_ALUNOS

*/
*/

void main()
{
int notas[NUM_ALUNOS];
/* Declaracao de matrizes */
int i, soma;
for(i=0; i<NUM_ALUNOS; i++)
{
printf("Digite a nota do aluno %d: ", i);
scanf("%d", &notas[i]); /* atribuindo valores a matriz */
}
soma = 0;
for(i=0; i<NUM_ALUNOS; i++)
soma = soma + notas[i]; /* lendo os dados da matriz */
printf("Media das notas: %d.", soma/NUM_ALUNOS);
}

9.1 Sintaxe de Matrizes


As dimenses so definidas entre colchetes, aps a definio convencional do tipo de
varivel.
<Tipo> <nome> [<dimenso1>] [<dimenso2>] ... ;

Em C, matrizes precisam ser declaradas, como quaisquer outras variveis, para que o
compilador conhea o tipo de matriz e reserve espao de memria suficiente para armazen-la. Os
elementos da matriz so guardados numa seqncia contnua de memria, isto , um seguido do
outro.
O que diferencia a declarao de uma matriz da declarao de qualquer outra varivel a
parte que segue o nome, isto , os pares de colchetes [ e ] que envolvem um nmero inteiro, que
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
51

Curso de Linguagem Computacional C/C++

indica ao compilador o tamanho da matriz. A dimenso da matriz vai depender de quantos pares de
colchetes a declarao da matriz tiver. Por exemplo:
int notas[5];
/* declarao de uma matriz unidimensional = vetor */
unsigned float tabela[3][2];
/* matriz bidimensional
*/
char cubo[3][4][6];
/* matriz tridimensional
*/

Analisando-se a primeira declarao: a palavra int declara que todo elemento da matriz do
tipo int, notas o nome dado a matriz e [5] indica que a nossa matriz ter 5 elementos do tipo int.
Por definio uma matriz composta por elementos de um nico tipo.
O acesso aos elementos da matriz feito atravs do nmero entre colchetes seguindo o nome
da matriz. Observe que este nmero tem um significado diferente quando referencia um elemento
da matriz e na declarao da matriz, onde indica o seu tamanho.
Quando referenciamos um elemento da matriz este nmero especifica a posio do
elemento na matriz. Os elementos da matriz so sempre numerados por ndices iniciados por 0
(zero). O elemento referenciado pelo nmero 2
notas[2]

no o segundo elemento da matriz mas sim o terceiro, pois a numerao comea em 0. Assim o
ltimo elemento da matriz possui um ndice, uma unidade menor que o tamanho da matriz.
O acesso com notas[i] pode ser tanto usado para ler ou escrever um dado na matriz.
Voc pode tratar este elemento como um varivel simples, no caso de notas[i], como uma varivel
inteira qualquer.
Como proceder caso voc no conhea a quantidade de termos que voc precisa para a tua
matriz? Aplique a idia apresentada no programa exemplo acima, com a diretiva:
#define

NUM_ALUNOS

para alocar um nmero maior de termos, de forma a possuir espao suficiente alocado para
conter todos os possveis termos da matriz.
Ateno: A linguagem C no realiza verificao de limites em matrizes; por isto nada
impede que voc v alm do fim da matriz. Se voc transpuser o fim da matriz durante uma
operao de atribuio, ento atribuir valores a outros dados ou at mesmo a uma parte do cdigo
do programa. Isto acarretar resultados imprevisveis e nenhuma mensagem de erro do compilador
avisar o que est ocorrendo.
Como programador voc tem a responsabilidade de providenciar a verificao dos limites,
sempre que necessrio. Assim a soluo no permitir que o usurio digite dados, para elementos
da matriz, acima do limite.

9.2 Inicializando Matrizes


Em C a inicializao de uma matriz feita em tempo de compilao. Matrizes das classes
extern e static podem ser inicializadas. Matrizes da classe auto no podem ser inicializadas.
Lembre-se de que a inicializao de uma varivel feita na instruo de sua declarao e uma
maneira de especificarmos valores iniciais pr-fixados.
O programa a seguir exemplifica a inicializao de uma matriz:
/* exemplo de inicializao de matrizes
/* programa que produz troco
#include
#define

<stdio.h>
LIM

*/
*/

void main()
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
52

Curso de Linguagem Computacional C/C++

{
int d, valor, quant;
static int tab[] = {50, 25, 10, 5, 1};
printf("Digite o valor em centavos: ");
scanf("%d", &valor);
for(d=0; d<LIM; d++)
{
quant = valor/tab[d];
printf("Moedas de %d centavos = %2d\n", tab[d], quant);
valor %= tab[d];
}
}

A instruo que inicializa a matriz :


static int tab[] = {50, 25, 10, 5, 1};

A lista de valores colocada entre chaves e os valores so separados por vrgulas. Os


valores so atribudos na seqncia, isto , tab[0] = 50, tab[1] 25, tab[2] 10 e assim por diante.
Note que no foi necessria a declarao da dimenso da matriz. Caso tivssemos escrito
explicitamente a dimenso da matriz, esta deveria se maior ou igual a dimenso fornecida pelo
colchetes. Se h menos inicializadores que a dimenso especificada, os outros sero zero. um erro
ter-se mais inicializadores que o necessrio.
Se em seu programa voc deseja inicializar uma matriz, voc deve criar uma varivel que
existir durante toda a execuo do programa. As classes de variveis com esta caracterstica so
extern e static.
A linguagem C permite matrizes de qualquer tipo, incluindo matrizes de matrizes. Por
exemplo, uma matriz de duas dimenses uma matriz em que seus elementos so matrizes de uma
dimenso. Na verdade, em C, o termo duas dimenses no faz sentido pois todas as matrizes so de
uma dimenso. Usamos o termo mais de uma dimenso para referncia a matrizes em que os
elementos so matrizes.
As matrizes de duas dimenses so inicializadas da mesma maneira que as de dimenso
nica, isto , os elementos (matrizes) so colocados entre as chaves depois do sinal de igual e
separados por vrgulas. Cada elemento composto por chaves e seus elementos internos separados
por vrgulas. Como exemplo segue abaixo uma matriz bidimensional:
char tabela[3][5]
{ {0, 0, 0,
{0, 1, 1,
{1, 1, 0,

=
0, 0},
1, 0},
0, 1} };

Cada elemento da matriz tabela na verdade ser outra matriz, ento por exemplo:
tabela[2] == {1, 1, 0, 0, 1}

Da mesma maneira se aplica para matrizes de trs ou mais dimenses:


int tresd[3][2][4] =
{ { {1, 2, 3, 4} , {5, 6, 7, 8} },
{ {7, 9, 3, 2} , {4, 6, 8, 3} },
{ {7, 2, 6, 3} , {0, 1, 9, 4} } };

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
53

Curso de Linguagem Computacional C/C++

A matriz de fora tem trs elementos, cada um destes elementos uma matriz de duas
dimenses de dois elementos onde cada um dos elementos uma matriz de uma dimenso de quatro
nmeros.
Como podemos acessar o nico elemento igual a 0 na matriz do exemplo anterior? O
primeiro ndice [2], pois o terceiro grupo de duas dimenses. O segundo ndice [1], pois o
segundo de duas matrizes de uma dimenso. O terceiro ndice [0], pois o primeiro elemento da
matriz de uma dimenso. Ento, temo que a primitiva abaixo verdade:
Tresd[2][1][0] == 0

9.3 Matrizes como Argumentos de Funes


C permite passar um matriz como parmetro para uma funo.
A seguir apresentamos como exemplo o mtodo de Ordenao Bolha como exemplo de
passagem de matrizes como argumentos. Este um mtodo famoso de ordenao de elementos em
uma matriz devido a sua simplicidade e eficincia.
A funo comea considerando a primeira varivel da matriz, list[0]. O objetivo colocar o
menor item da lista nesta varivel. Assim, a funo percorre todos os itens restantes da lista, de
list[1] a list[tam-1], comparando cada um com o primeiro item. Sempre que encontrarmos um item
menor, eles so trocados. Terminada esta operao, tomado o prximo item, list[1]. Este item
dever conter o prximo menor item. E novamente so feitas as comparaes e trocas. O processo
continua at que a lista toda seja ordenada.
/* Ordena.c
/* ordena os valores da matriz

*/
*/

#include <stdio.h>
#define
TAMAX
30
void ordena(int list[], int tam);
void main()
{
int list[TAMAX], tam=0, d;
do
{
printf("Digite numero: ");
scanf("%d", &list[tam]);
} while(list[tam++] != 0);
ordena(list, --tam);
for(d=0; d<tam; d++)
printf("%d\n", list[d]);
}
/* ordena(), ordena matriz de inteiros */
void ordena(int list[], int tam)
{
int register j, i;
int temp;
for(j = 0; j < tam-1; j++)
for(i = j + 1; i < tam; i++)
if(list[j] > list[i])
{
temp = list[i];
list[i] = list[j];
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
54

Curso de Linguagem Computacional C/C++

list[j] = temp;
}
}

O nico elemento novo no programa acima a instruo:


ordena(list, --tam);

ela uma chamada funo ordena() que ordena os elementos de uma matriz segundo o mtodo
bolha. Esta funo tem dois argumentos: o primeiro a matriz list e o segundo a varivel que
contm o tamanho da matriz.
A matriz foi passada como argumento da funo quando escrevemos somente o seu nome
como parmetro da funo.
Quando desejamos referenciar um elemento da matriz devemos acess-lo atravs do nome
da matriz seguida de colchetes, onde o ndice do elemento escrito entre os colchetes. Entretanto se
desejamos referenciar a matriz inteira, basta escrever o nome desta, sem colchetes. O nome de uma
matriz desacompanhada de colchetes representa o endereo de memria onde a matriz foi
armazenada.
O operador & no pode ser aplicado a matriz para se obter o endereo desta, pois, a
endereo da matriz j est referenciado no seu nome. Portanto, a instruo abaixo seria invlida:
&list;

O operador & somente pode ser aplicado a um elemento da matriz. Portanto, a instruo:
int * ptr = &list[0];

ser vlido e ir retornar o endereo da primeira varivel da matriz. Como a rea de


memria ocupada por uma matriz comea atravs do primeiro termo armazenado nesta, portanto, os
endereos da matriz e do primeiro elemento sero equivalentes:
list == &list[0];

Assim, a funo ordena() recebe um endereo de uma varivel int e no um valor inteiro
e deve declar-lo de acordo. O tipo :
int []

indica um endereo de uma varivel int.

9.4 Chamada Por Valor e Chamada Por Referncia


Quando um nome de uma simples varivel usado como argumento na chamada a uma
funo, a funo toma o valor contido nesta varivel e o instala em uma nova varivel e em nova
posio de memria criada pela funo. Portanto as alteraes que forem feitas nos parmetros da
funo no tero nenhum efeito nas variaes usadas na chamada. Este mtodo conhecido como
chamada por valor.
Entretanto, as matrizes so consideradas um tipo de dado bastante grande, pois so formadas
por diversas variveis. Por causa disto, a linguagem C++ determina ser mais eficiente existir uma
nica cpia da matriz na memria, sendo portanto irrelevante o nmero de funes que a acessem.
Assim, no so passados os valores contidos na matriz, somente o seu endereo de memria.
Desta forma, a funo usa o endereo da matriz para acessar diretamente os elementos da
prpria matriz da funo que chama. Isto significa que as alteraes que forem feitas na matriz pela
funo afetaro diretamente a matriz original.
Quando se passa o nome de uma matriz para uma funo, no se cria uma cpia dos dados
desta mas sim, utiliza-se diretamente os dados da matriz original atravs do endereo passado. Esta
tipo de passagem de parmetros denominado passagem de parmetros por referncia.
A seguir apresentamos um exemplo de passagem de uma matriz bidimensional como
parmetro de uma funo. O programa exemplo avalia a eficincia de funcionrios de uma loja,
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
55

Curso de Linguagem Computacional C/C++

quanto ao nmero de peas vendidas por cada um. O primeiro ndice da matriz indica o nmero de
funcionrios da loja e o segundo ndice, o nmero de meses a serem avaliados.
/* Exemplo da matrizes bidimensionais
/* histograma horizontal
#include <stdio.h>

*/
*/

#define
FUNC
4
/* numero de funcionarios */
#define
MES
3
/* nuemro de meses
*/
#define
MAXBARRA
50
/* tamanho maximo da barra */
void grafico(int p[][MES], int nfunc); /* declaracao da funcao */
void main()
{
int pecas[FUNC][MES]; /* declaracao de matriz bidimensional*/
int i, j;
for(i=0; i<FUNC; i++)
for(j=0; j<MES; j++)
{
printf("Numero de pecas vendidas pelo funcionario");
printf("%d no mes %d: ", i+1, j+1);
scanf("%d", &pecas[i][j]);
}
grafico(pecas, FUNC);
}
/*
grafico(), desenha um histograma */
void grafico(int p[][MES], int nfunc)
{
int register i, j;
int max, tam = 0, media[FUNC];
for(i=0; i<nfunc; i++)
{
media[i] = 0;
for(j=0; j<MES; j++)
media[i] += p[i][j];
media[i] /= MES;
}
max = 0;
for(i = 0; i< nfunc; i++)
if(media[i]>max)
max = media[i];
printf("\n\n\n\n FUNC - MEDIA\n--------------\n");
for(i=0;i<FUNC; i++)
{
printf("%5d - %5d : ", i+1, media[i]);
if(media[i]>0)
{
if((tam=(int)(((float)media[i])*MAXBARRA/max)) <= 0)
tam = 1;
}
else
tam = 0;
for(; tam>0; --tam)
printf("%c", '>');
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
56

Curso de Linguagem Computacional C/C++

printf("\n");
}
}

O mtodo de passagem do endereo da matriz para a funo idntico ao da passagem de


uma matriz de uma dimenso, no importando quantas dimenses tem a matriz, visto que sempre
passamos o seu endereo.
grafico(pecas, FUNC);

Como no h verificao de limites, uma matriz com a primeira dimenso de qualquer valor
pode ser passada para a funo chamada. Mas uma funo que recebe uma matriz bidimensional
dever ser informada do comprimento da segunda dimenso para saber como esta matriz est
organizada na memria e assim poder operar com declaraes do tipo:
pecas[2][1]

pois, para encontrar a posio na memria onde pecas[2][1] est guardada, a funo multiplica
o primeiro ndice (2) pelo nmero de elementos da segunda dimenso (MES) e adiciona o segundo
ndice (1), para finalmente somar ao endereo da matriz (pecas). Caso o comprimento da segunda
matriz no seja conhecido, ser impossvel saber onde esto os valores.

9.5 Strings
C no possui um tipo de dado especial para tratar strings. Desta forma, uma das aplicaes
mais importante de matrizes em C justamente a criao do tipo string, caracterizado por uma
sequncia de caracteres armazenados terminados por \0 (que possui o valor 0 na tablea ASCII) em
uma matriz. Por esta razo que C no fornece uma estrutura amigvel para a manipulao de
string comparada com outras linguagens como Pascal, por exemplo. Somente com o advento da
orientao a objetos (C++) que C veio a fornecer uma estrutura amigvel e flexvel para tratar
strings. Esta estrutura ser vista somente nos captulos posteriores. Aqui, apresentaremos string na
sua forma bsica em C.
String uma matriz tipo de char que armazena um texto formado de caracteres e sempre
terminado pelo caractere zero (\0). Em outras palavras, string uma srie de caracteres, onde cada
um ocupa um byte de memria, armazenados em seqncia e terminados por um byte de valor zero
(\0). Cada caracter um elemento independente da matriz e pode ser acessado por meio de um
ndice.

9.5.1 Strings Constantes


Qualquer seqncia de caracteres delimitadas por aspas duplas considerada pelo
compilador como uma string constante. O compilador aloca uma matriz com tamanho uma (1) unidade maior que o nmero de caracteres inseridos na string constante, armazenando estes caracteres
nesta matriz e adicionando automaticamente o caracter delimitador de strings \0 no final da
matriz. Vrios exemplos de strings constantes esto presentes ao longo de texto, exemplos como :
printf(Bom Dia!!!!);
O importante lembrar que o compilador sempre adiciona o caracter \0 a strings
constantes antes de armazen-las na forma de matriz para poder marcar o final da matriz. Observer
que o caracter \0, tambm chamado de NULL, tem o valor zero decimal (tabela ASCII), e no se
trata do caracter 0, que tem valor 48 decimal (tabela ASCII). A terminao \0 importante, pois
a nica maneira que as funes possuem para poder reconhecer onde o fim da string.

9.5.2 String Variveis


Um das maneiras de receber uma string do teclado atravs da funo scanf() pelo
formato %s. A funo scanf() l uma string at voc apertar a tecla [enter], adiciona o caracter
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
57

Curso de Linguagem Computacional C/C++

\0 e armazena em uma matriz de caracteres. Perceba que o endereo da matriz e passado


escrevendo-se somente o nome da matriz. Abaixo apresentamos um exemplo, nele fica claro que se
voc digitar uma frase com um nmero maior de caracteres do que a matriz alocada, (char[15])
um erro de memria ir ocorrer. Isto se deve ao fato de scanf() no testar a dimenso de matriz e
simplesmente adquirir uma seqncia de caracteres at encontrar um caracter do [enter], espao
simples ou tabulao. Depois ela armazena a string na matriz fornecida, sem testa a dimenso da
matriz. A definio de uma string segue o mesmo formato da definio de matrizes, entretanto o
tipo empregado o tipo char.
/* string 1, le uma string do teclado e imprime-a */
#include <stdio.h>
void main()
{
char nome[15]; /* declara uma string com 15 caracteres */
printf("Digite seu nome: ");
scanf("%s", nome);
printf("Saudacoes, %s.", nome);
}

Se voc escrever Pedro Silva no programa acima, a funo scanf() ir eliminar o segundo
nome. Isto se deve por que scanf() utiliza qualquer espao, quebra de linha ou tabulao para
determinar o fim da leitura de uma string.
Neste caso, a funo gets() se aplica de forma mais eficiente para a aquisio de strings.
A funo gets() adquire uma string at se pressionada a tecla [enter], adicionando o caracter \0
para especificar o fim da string e armazen-la em uma matriz. Desta forma podemos utilizar
gets() para ler strings com espaos e tabulaes.
Para imprimir strings utilizamos as duas funes principais printf() e puts().
O formato de impresso de strings com prinf() ns j conhecemos, basta escrever o
parmetro %s no meio da string de formatao de printf() e posteriormente passar o nome da
matriz de caracteres, terminada com \0, como parmetro.
Puts() tem uma sintaxe bem simples tambm. Chamando a funo puts() e passandose o nome da matriz de caracteres terminada por \0 como parmetro, teremos a string impressa na
tela (sada padro) at encontrar o caracter \0. Aps a impresso, puts() executa uma quebra de
linha automaticamente [enter], o que impossibilita a sua aplicao para escrever duas strings na
mesma linha. Abaixo , temos um exemplo:
char nome[] = Alexandre Orth;
puts(nome);

Em C, a forma formal da inicializao de strings ocorre da mesma maneira que uma matriz,
ou seja, inicializamos termo por termo como a seguir:
char text[] = {B, o, m, , d, i, a, !, \0};

C fornece ainda uma maneira bem simples, que foi apresentada no outro exemplo acima.
Note que na forma formal de inicializao temos que adicionar explicitamente o caracter \0 para
determinar o fim da matriz. J na forma simples, o compilador faz isto automaticamente para voc.

9.5.3 Funes para Manipulao de Strings


Em C existem vrias funes para manipular matrizes e tentar tornar a vida do programador
um pouco mais fcil. Veremos aqui as 4 funes principais: strlen(), strcat(), strcmp()
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
58

Curso de Linguagem Computacional C/C++

e strcpy(). Note que estas funes exigem que o caracter \0 esteja delimitando o final da
string.
A funo strlen() aceita um endereo de string como argumento e retorna o tamanho da
string armazenada a partir deste endereo at um caractere antes de 0, ou seja, ela retorna o
tamanho da matriz que armazena a string menos um, descontando assim o caracter de final da string
\0. Sintaxe de strlen():
strlen(string);
A funo strcat() concatena duas strings, isto , junta uma string ao final de outra. Ela
toma dois endereos de strings como argumento e copia a segunda string no final da primeira e esta
combinao gera uma nova primeira string. A segunda string no alterada. Entretanto, a matriz da
primeira string deve conter caracteres livres (ou seja, caracteres alocados localizados aps o
delimitador de final de string \0) suficientes para armazenar a segunda string. A funo
strcat() no verifica se a segunda string cabe no espao livre da primeira. Sintaxe de
strcat():
strcat(string1, string2);
A funo strcmp() compara duas strings e retorna:
< 0
0
> 0

:
:
:

no caso da string 1 < que a string 2


no caso da string 1 = a string 2
no caso da string 1 > que a string2

Neste contexto, menor que (<) ou maior que (>) indica que, se voc colocar string1 e
string2 em ordem alfabtica, o que aparecer primeiro ser menor que o outro. Sintaxe de
strcmp():
strcmp(string1, string2);
A funo strcpy() simplesmente copia uma string para outra. Note, que a string1 deve
conter espao suficiente para armazenar os dados da string2. Sintaxe da funo strcpy():
strcpy(string1, string2);
Abaixo vamos mostrar um exemplo que apagar um caracter do interior de uma string. Neste
exemplo vamos implementar a funo strdel() que move, um espao esquerda, todos os
caracteres que esto a direita do caracter sendo apagado.
/* delete, apaga caractere de uma string */
#include <stdio.h>
void strdel(char str[], int n);
void main()
{
char string[81];
int posicao;
printf("Digite string, [enter], posicao\n");
gets(string);
scanf("%d", &posicao);
strdel(string, posicao);
puts(string);
}
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
59

Curso de Linguagem Computacional C/C++

/* strdel(), apaga um caractere de uma string */


void strdel(char str[], int n)
{
strcpy(&str[n], &str[n+1]);
}

9.6 Exerccios
9.1 Crie um programa para calcular a matriz transposta de uma dada matriz. Aloque uma
memria para uma matriz bidimensional com dimenso mxima de 10x10. Crie uma funo para
inicializar a matriz com zero. Depois questione o usurio para sob a dimenso da matriz que ele
deseja calcular a transposta, considerando a dimenso mxima permitida. Depois, adquira os
valores dos termos que compem a matriz, solicitando ao usurio que fornea estes dados. Por fim,
calcule a transporta da matriz e escreva na tela o resultado final da matriz.
9.2 Continue o programa anterior e agora calcule o tamanho de memria alocada para a
matriz e que no est sendo utilizada. Ou seja, considerando o tipo de dado da matriz, que a matriz
inicial tem tamanho 10x10 e o tamanho utilizado pelo usurio, quantos bytes de memria o
computador alocou para a matriz e quantos bytes de memria o usurio realmente utilizou. Crie
uma funo que calcule este dado comparando duas matrizes de dimenses quaisquer. Reflita sobre
este problema.
9.3 A decomposio LDU uma decomposio famosa de matrizes aplicada para calcular
inversas de matrizes e resolver problemas de equaes lineares. Utilize o programa 9.1 e crie um
programa que calcule a decomposio LDU de uma matriz, preferencialmente, com pivotamento.
9.4 Escreva uma funo que indique quantas vezes aparece um determinado caracter em
uma dada string.
9.5 Escreva uma funo que localize um caracter em uma string e depois o substitua por
outro.
9.6 Escreva uma funo que insira um determinado character em uma determinada posio
de uma string.
9.7 Escreva uma funo que retire todos os caracteres brancos, tabulaes ou nova linha
[enter] de uma dada string.
9.8 Escreva um programa que converta todas os caracteres minsculos de uma string para o
correspondente caracter maisculo.
9.9 Refaa o seu exerccio 6.2 para criar uma tabela com os seus horrios ocupados e
compromissos na semana. Armazene o valor de cada compromisso atravs de uma tabela de strings.
Inicialize a tabela com valor 0, e solicite ao usurio que fornea o seu horrio. Por fim, apresente na
tela o resultado obtido.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
60

Curso de Linguagem Computacional C/C++

10 Tipos Especiais de Dados


Em C podemos definir novos tipos de dados, adicionando complexidade aos tipos de dados
j existentes. Com a finalidade de tornar a vida do programador mais fcil e permitir que este crie
novos tipos de dados, compostos pelos tipos de dados j pr-existentes (char, int, float, double e
matrizes destes tipos).

10.1 Typedef
Typedef nos apresenta a primeira forma de criar um novo tipo de dado. Typedef permite a
definio de novos tipos de variveis. Os novos tipos so sempre compostos de uma ou mais
variveis bsicas agrupadas de alguma maneira especial .
Sintaxe:
typedef <tipo> <definio>;

Exemplo da definio de um novo tipo de dado:


typedef double real_array [10]; /* novo tipo */
real_array x, y;
/* declara variveis tipo real_array */

No exemplo acima, ambas x e y foram declaradas como sendo do tipo real-array e por
isso, representam um vetor de valores reais (double) com capacidade para armazenar 10 dados deste
tipo.

10.2 Enumerados (Enum)


Permitem atribuir valores inteiros seqenciais constantes. Tipos enumerados so usados
quando conhecemos o conjunto de valores que uma varivel pode assumir. A varivel deste tipo
sempre int e, para cada um dos valores do conjunto, atribumos um nome significativo para
represent-lo. A palavra enum enumera a lista de nomes automaticamente, dando-lhes nmeros em
seqncia (0, 1, 2, etc.). A vantagem que usamos estes nomes no lugar de nmeros, o que torna o
programa mais claro.
Abaixo apresentamos exemplos da aplicao de tipos enumerados e de suas definies:
/* Exemplo de tipos enumerados */
/* definicao de novos tipos de dados */
enum dias
{
segunda, /* atribui: segunda = 0; */
terca,
/* atribui: terca
= 1; */
quarta, /* atribui: quarta = 2; */
quinta, /* atribui: quinta = 3; */
sexta,
/* atribui: sexta
= 4; */
sabado, /* atribui: sabado = 5; */
domingo /* atribui: domingo = 6; */
};
enum cores
{
verde
= 1,
azul
= 2,
preto, /* como no foi dado valor, recebe valor anterior + 1 = 3 */
branco
= 7
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
61

Curso de Linguagem Computacional C/C++

};
enum boolean
{
false,
true
};

/* false = 0 */
/* true = 1 */

void main()
{
enum dias dia1, dia2; /* declara varivel "dias" do tipo enum */
enum boolean b1;
/* declara varivel do tipo enum boolean */
dia1 = terca;
dia2 = terca + 3;
if (dia2 == sabado)
b1 = true;

/* dia2 = sexta */

A palavra enum define um conjunto de nomes com valores permitidos para esse tipo e
enumera esses nomes a partir de zero (default) ou, como em nosso programa, a partir do primeiro
valor fornecido. Se fornecemos um valor a alguns nomes e no a outros, o compilador atribuir o
prximo valor inteiro aos que no tiverem valor. A sintaxe fica clara no exemplo acima.
Um varivel de tipo enumerado pode assumir qualquer valor listado em sua definio.
Valores no listados na sua definio no podem ser assumidos por esta varivel. Tipos enumerados
so tratados internamente como inteiros, portanto qualquer operao vlida com inteiros permitida
com eles.

10.3 Estruturas (Struct)


Estruturas permitem definir estruturas complexas de dados, com campos de tipos diferentes.
Observe que nas matrizes (arrays), todos os campos so do mesmo tipo. As structs permitem,
entretanto, criar elementos semelhantes a arrays, mas composta de elementos com tipos diferentes
de dados.
Por meio da palavra-chave struct definimos um novo tipo de dado. Definir um tipo de dado
significa informar ao compilador o seu nome, o seu tamanho em bytes e o formato em que ele deve
ser armazenado e recuperado na memria. Aps ter sido definido, o novo tipo existe e pode ser
utilizado para criar variveis de modo similar a qualquer tipo simples.
Abaixo apresentamos as duas sintaxe que podem ser empregadas para a definio de
estruturas e para a declarao de variveis deste tipo:
Sintaxe :
struct <nome> /* Definio */
{
<tipo> <nome campo>;
}[<variveis deste tipo>];
/* Declarao de Variveis */
struct <nome> <nome varivel>;

Exemplo :
struct Dados_Pessoais
{
char Nome[81];
int
Idade;
float Peso;
} P1;
/* Declarao de Variveis */
struct Dados_Pessoais P2, P3;

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
62

Curso de Linguagem Computacional C/C++

typedef struct <nome> /* Def.*/


{
<tipo> <nome campo>;
} <nome tipo>;
/* Declarao de variveis/
<nome tipo> <nome varivel>;

typedef struct Dados_Pessoais


{
char Nome [ 81];
int Idade;
float Peso;
} Pessoa;
/* Declarao de variveis/
Pessoa P1, P2;

Definir uma estrutura no cria nenhuma varivel, somente informa ao compilador as


caractersticas de um novo tipo de dado. No h nenhuma reserva de memria. A palavra struct
indica que um novo tipo de dado est sendo definido e a palavra seguinte ser o seu nome.
Desta forma, faz-se necessrio a declarao de variveis deste tipo. Na primeira sintaxe,
mostramos no exemplo como podemos declarar um varivel do tipo da estrutura Dados_Pessoais
j na definio da estrutura (P1) e como podemos criar outras variveis deste tipo ao longo do
programa (P2 e P3). J na segunda sintaxe, a forma da declarao de variveis deve ser sempre
explcita, como mostrado no exemplo.
Uma vez criada a varivel estrutura, seus membros podem ser acessados por meio do
operador ponto. O operador ponto conecta o nome de uma varivel estrutura a um membro desta.
Abaixo, fornecemos exemplos de acesso as variveis definidas por meio de estruturas:
gets(P1.Nome);
P1.Idade = 41;
P3.Peso = 75.6;

A linguagem C trata os membros de uma estrutura como quaisquer outras variveis simples.
Por exemplo, P1.Idade o nome de uma varivel do tipo int e pode ser utilizada em todo lugar onde
possamos utilizar uma varivel int.
A inicializao de estruturas semelhante inicializao de uma matriz. Veja um exemplo:
struct data
{
int dia;
char mes[10];
int ano;
};
data natal = { 25, Dezembro, 1994};
data aniversario = { 30, Julho, 1998};

Uma varivel estrutura pode ser atribuda atravs do operador igual (=) a outra varivel do
mesmo tipo:
aniversario = natal;

Certamente constatamos que esta uma estupenda capacidade quando pensamos a respeito:
todos os valores dos membros da estrutura esto realmente sendo atribudos de uma nica vez aos
correspondentes membros da outra estrutura. Isto j no possvel, por exemplo, com matrizes.
Estruturas no permitem operaes entre elas, somente entre os seus membros.
Aps definirmos um tipo de dado atravs de uma estrutura, podemos incluir este tipo de
dado como membro de uma outra estrutura. Isto cria o que chamamos tipos aninhados de estruturas,
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
63

Curso de Linguagem Computacional C/C++

onde uma estrutura contm no seu interior como membro outra estrutura. Esta operao funciona
assim como uma matriz bidimensional na verdade uma matriz de matrizes unidimensionais.
Estruturas podem ser passadas para funes assim como qualquer outra varivel, sendo
declarada e utilizada da mesma forma. Funes podem tambm retornar uma estrutura como o
resultado do seu processamento. Para tal, basta declarar o tipo de retorno de uma funo como
sendo um tipo declarado por uma struct. Esta uma forma de fazer com que uma funo retorne
mais de um parmetro.
Podemos criar uma matriz para estruturas assim como criamos uma matriz de um tipo
qualquer, basta declarar o tipo da matriz como o tipo definido pela estrutura. A seguir apresentamos
um exemplo envolvendo matrizes de estruturas, onde trataremos de uma matriz de estruturas que
contm os dados necessrios para representar um livro. A forma de acesso aos membros da
estrutura, armazenadas na matriz fica clara no exemplo.
As funes atoi() e atof() apresentadas no exemplo abaixo servem para converter
strings para um tipo inteiro ou float, respectivamente, e esto definidas em stdlib.
/* livros, mantem lista de livros na memoria */
#include <stdio.h>
#include <stdlib.h> /* para atof() e atoi() */
/* definicao de tipos */
struct list
{
char
titulo[30];
char
autor[30];
int
regnum;
double
preco;
};
/* declaracao de variaveis e funcoes*/
struct list
livro[50];
int
n = 0;
void
novonome();
void
listatotal();
void main()
{
char ch;
while(1)
{
printf("\nDigite 'e' para adicionar um livro");
printf("\n'l' para listar todos os livros: ");
ch = getche();
switch(ch)
{
case 'e' :
novonome();
break;
case 'l':
listatotal();
break;
default:
puts("\nDigite somente opcoes validas!!!!");
}
}
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
64

Curso de Linguagem Computacional C/C++

}
/* novonome(), adiciona um livro ao arquivo */
void novonome()
{
char numstr[81];
printf("\nRegistro %d. \nDigite titulo: ", n+1);
gets(livro[n].titulo);
printf("\nDigite autor: ");
gets(livro[n].autor);
printf("\nDigite o numero do livro (3 digitos): ");
gets(numstr);
livro[n].regnum = atoi(numstr); /* converte string p/ int */
printf("\nDigite preco: ");
gets(numstr);
livro[n].preco = atof(numstr);
n++;
}
/* listatotal(), lista os dados de todos os livros */
void listatotal()
{
int i;
if(!n)
printf("\nLista vazia.\n");
else
for(i=0; i<n; i++)
{
printf("\nRegistro: %d.\n", i+1);
printf("\nTitulo: %s.\n", livro[i].titulo);
printf("\nAutor: %s.\n", livro[i].autor);
printf("\nNumero do registro: %3d.\n", livro[i].regnum);
printf("\nPreco: %4.3f. \n", livro[i].preco);
}
}

10.4 Unies
A palavra union usada, de forma semelhante a struct, para agrupar um nmero de
diferentes variveis sob um nico nome. Entretanto, uma union utiliza um mesmo espao de
memria a ser compartilhado com um nmero de diferentes membros, enquanto uma struct aloca
um espao diferente de memria para cada membro.
Em outras palavras, uma union o meio pelo qual um pedao de memria ora tratado
como uma varivel de um certo tipo, ora como outra varivel de outro tipo.
Por isso, unies so usadas para poupar memria e o seu uso no recomendado a no ser
em casos extremamente necessrios, pois a utilizao irresponsvel das unies podem causar a
perda de dados importantes do programa. Quando voc declara uma varivel do tipo union,
automaticamente alocado espao de memria suficiente para conter o seu maior membro.
Sintaxe:
union <nome>
{
<tipo> <campo1>;
:
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
65

Curso de Linguagem Computacional C/C++

<tipo n> <campo n>;


};

Exemplo do emprego das unies:


typedef unsigned char byte;
union Oito_bytes
{
double x;
/*um double de 8 bytes */
int
i[4];
/* um array com 4 inteiros = 8 bytes */
byte j[8];
/* um array de 8 bytes */
} unionvar;
void main()
{
unionvar.x = 2.7;
unionvar.i[1] = 3; /* sobreescreve valor anterior ! */
}

Para verificar que o tamanho de uma varivel union igual ao tamanho do maior membro,
vamos utilizar a funo sizeof(). A funo sizeof() resulta o tamanho em bytes ocupado por
uma dada varivel. Veja o teste realizado abaixo, onde apresentamos o valor em bytes ocupado por
cada membro da unio e o valor em bytes ocupado pela unio inteira. Podemos verificar tambm
que todos os membros da unio ocupam a mesma posio da memria utilizando o operador & para
obter a posio da memria onde esto armazenados os dados.
/* Sizeof(), mostra o uso de sizeof() */
#include <stdio.h>
union num
{
char str[20];
int i;
float f;
} x; // Cria a variavel do tipo union num.
void main()
{
printf("Sizeof(str[20]) =%d bytes, mem:%p.\n",sizeof(x.str), x.str);
printf("Sizeof(i) = %d bytes, \tmem: %p.\n", sizeof(x.i), &(x.i));
printf("Sizeof(f) = %d bytes, \tmem: %p.\n", sizeof(x.f), &(x.f));
printf("Sizeof(x) = %d bytes, \tmem: %p.\n", sizeof(x), &(x));
}

A sada do programa ser como esperado:


Sizeof(str[20]) = 20 bytes, mem: 50EF:0D66.
Sizeof(i) = 2 bytes,
mem: 50EF:0D66.
Sizeof(f) = 4 bytes,
mem: 50EF:0D66.
Sizeof(x) = 20 bytes,
mem: 50EF:0D66.

10.5 Bitfields
Bitfields so um tipo especial de estrutura cujos campos tem comprimento especificado em
bits. Estas so teis quando desejamos representar dados que ocupam somente um bit.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
66

Curso de Linguagem Computacional C/C++

Sintaxe:
struct <nome>
{
<tipo> <campo> : <comprimento em bits>;
};

Exemplo aplicando bitfields:


#define ON 1
#define OFF 0
struct Registro_Flags
/* declara bitfield */
{
unsigend int Bit_1 : 1;
unsigend int Bit_2 : 1;
unsigend int Bit_3 : 1;
unsigend int Bit_4 : 1;
unsigend int Bit_5 : 1;
unsigend int Bit_6 : 1;
unsigend int Bit_7 : 1;
unsigend int Bit_8 : 1;
};
main( )
{
struct Registro_Flags Flags;
/* declara varivel Flags */
Flags.Bit_1 = ON;
Flags.Bit_2 = OFF;
}

10.6 Exerccios
10.1 Escreva uma estrutura para descrever um ms do ano. A estrutura deve ser capaz de
armazenar o nome do ms, a abreviao em letras, o nmero de dias e o nmero do ms. Escreva
tambm um tipo enumerado para associar um nome ou uma abreviao ao nmero do ms.
10.2 Declare uma matriz de 12 estruturas descritas na questo anterior e inicialize-a com os
dados de um ano no-bissexto.
10.3 Escreva uma funo que recebe o nmero do ms como argumento e retorna o total de
dias do ano at aquele ms. Escreva um programa que solicite ao usurio o dia, o ms e o ano.
Imprima o total de dias do ano at o dia digitado.
10.4 Escreva um programa para cadastrar livros em uma biblioteca e fazer consultas a estes.
10.5 Refaa o programa do exerccio 8.6 utilizando as estruturas aqui desenvolvidas.
10.6 Crie uma estrutura para descrever restaurantes. Os membros deve armazenar o nome, o
endereo, o preo mdio e o tipo de comida. Crie uma matriz de estruturas e escreva um programa
que utilize uma funo para solicitar os dados de um elemento da matriz e outra para listar todos os
dados.
10.7 Crie um programa que faa o controle de cadastro de usurios e controle de alocao
para uma locadora de fitas de vdeo. Utilize uma estrutura para os clientes e outra para as fitas.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
67

Curso de Linguagem Computacional C/C++

11 Ponteiros e a Alocao Dinmica de Memria


No captulo sobre tipos de dados, definimos o que era ponteiro. Ponteiros so tipos especiais
de dados que armazenam o endereo de memria onde uma varivel normal armazena os seus
dados. Desta forma, empregamos o endereo dos ponteiros como uma forma indireta de acessar e
manipular o dado de uma varivel.
Agora apresentaremos diversas aplicaes de ponteiros, justificaremos por que este so
intensivamente empregados na programao C e apresentaremos algumas de suas aplicaes tpicas.

11.1 Declarao de Ponteiros e o Acesso de Dados com Ponteiros


C permite o uso de ponteiros para qualquer tipo de dado, sendo este um dado tpico de C
(int, float, double, char) ou definido pelo programador (estruturas, unies). Como havamos visto
anteriormente (2.7), os ponteiros so declarados da seguinte forma:
<tipo> * <nome da varivel> = <valor inicial>;
float *p, float *r = 0;

A sintaxe basicamente a mesma que a declarao de variveis, mas o operador * indica


que esta varivel de um ponteiro, por isso *p e *r so do tipo float e que p e r so ponteiros para
variveis float.
Lembrando,
*p = 10;

faz com que a varivel endereada por p tenha o seu valor alterado para 10, ou seja, * um
operador que faz o acesso a varivel apontada por um ponteiro. O operador & aplicado a uma
varivel normal retorna o valor do seu endereo, podemos dizer ento:
int num = 15;
p = &num; /* p recebe o endereo de num */

11.2 Operaes com Ponteiros


A linguagem C oferece 5 operaes bsicas que podem ser executadas em ponteiros. O
prximo programa mostras estas possibilidades. Para mostrar o resultado de cada operao, o
programa imprimir o valor do ponteiro (que um endereo), o valor armazenado na varivel
apontada e o endereo da varivel que armazena o prprio ponteiro.
/* operacoes com ponteiros */
#include <stdio.h>
void main()
{
int x = 5, y = 6;
int *px;
int *py = 0; /* ponteiro inicializado com 0 */
printf("Endereco contigo incialmente em :\n");
printf("\tpx = %p \n\tpy = %p.\n", px, py);
printf("Cuidado ao usar ponteiros nao incializados como px!!!\n\n");
px = &x;
py = &y;
if(px<py)
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
68

Curso de Linguagem Computacional C/C++

printf("py - px = %u\n", py-px);


else
printf("px - py = %u\n", px-py);
printf("px =
printf("py =
px++;
printf("px =
py = px + 3;
printf("py =
printf("py -

%p, \t*px = %d, \t&px = %p\n", px, *px, &px);


%p, \t*py = %d, \t&py = %p\n\n", py, *py, &py);
%p, \t*px = %d, \t&px = %p\n\n", px, *px, &px);
%p, \t*py = %d, \t&py = %p\n", py, *py, &py);
px = %u\n", py-px);

Resultado do programa:
Endereo contido inicialmente em:
px = 21CD:FFFF
py = 0000:0000
Cuidado ao utilizar ponteiros no inicializados como px!!!!
px py = 1
px = 4F97:2126, *px = 5,
py = 4F97:2124, *py = 6,

&px = 4F97:2120
&py = 4F97:211C

px = 4F97:2128, *px = 20375,

&px = 4F97:2120

py = 4F97:212E, *py = 20351,


py px = 3

&py = 4F97:211C

Primeiramente, o programa exemplo acima declara as variveis inteiras x e y, declarando


dois ponteiros para inteiros tambm. Note que um ponteiro foi inicializado com 0 e o outro no.
Para mostrar a importncia da inicializao de ponteiros, resolvemos mostrar na tela o valor inicial
destes. Caso, tentssemos acessar o valor da varivel apontada pelo ponteiro py, o programa no
executaria esta operao pelo fato do ponteiro conter um endereo invlido 0. Entretanto, se
tentarmos acessar o valor da varivel apontada por px, o computador executar esta operao sem
problema, pois o endereo est vlido, e assim poderemos cometer um erro gravssimo acessando
reas de memrias inadequadas ou proibidas.
Inicialize sempre os seus ponteiros com o valor zero ou NULL.
Em seguida, atribumos um valor vlido aos ponteiros utilizando o operador (&) para obter o
endereo das variveis x e y.
O operador (*) aplicado na frente do nome do ponteiro, retornar o valor da varivel
apontada por este ponteiro.
Como todas as variveis, os ponteiros variveis tm um endereo e um valor. O operador
(&) retorna a posio de memria onde o ponteiro est localizado. Em resumo:
O nome do ponteiro retorna o endereo para o qual ele aponta.
O operador & junto ao nome do ponteiro retorna o endereo onde o ponteiro est
armazenado.
O operador * junto ao nome do ponteiro retorna o contedo da varivel apontada.
No programa acima, apresentamos esta idia de forma clara, mostrando na tela estes valores
para os dois respectivos ponteiros.
Podemos incrementar um ponteiro atravs de adio regular ou pelo operador de
incremento. Incrementar um ponteiro acarreta a movimentao do mesmo para o prximo tipo
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
69

Curso de Linguagem Computacional C/C++

apontado. Por exemplo, se px um ponteiro para um inteiro e px contm o endereo 0x3006. Aps
a execuo da instruo:
px++;

o ponteiro px conter o valor 0x3008 e no 0x3007, pois a varivel inteira ocupa 2 bytes. Cada vez
que incrementamos px ele apontar para o prximo tipo apontado, ou seja, o prximo inteiro. O
mesmo verdadeiro para decremento. Se px tem valor 0x3006 depois da instruo:
px--;

ele ter valor 0x3004.


Voc pode adicionar ou subtrair de e para ponteiros. A instruo:
py = px + 3;

far com que py aponte para o terceiro elemento do tipo apontado aps px. Se px tem valor 0x3000,
depois de executada a instruo acima, py ter o valor 0x3006.
Novamente, tenha cuidado na manipulao de ponteiros para no acessar regies invlidas
de memria ou ocupadas por outros programas.
Voc pode encontrar a diferena entre dois ponteiros. Esta diferena ser expressa na
unidade tipo apontado, ento, se py tem valor 0x4008 e px o valor 0x4006, a expresso
py - px

ter valor 1 quando px e py so ponteiros para int.


Testes relacionais com >=, <=, > e < so aceitos entre ponteiros somente quando os dois
operandos so ponteiros. Outro cuidado a se tomar quanto ao tipo apontado pelo operandos. Se
voc comparar ponteiros que apontam para variveis de tipo diferentes, voc obter resultados sem
sentido.
Variveis ponteiros podem ser testadas quanto igualdade (==) ou desigualdade (!=) onde
os dois operandos so ponteiros (px == py) ou um dos operandos NULL (px != NULL ou px != 0).

11.3 Funes & Ponteiros


Um das maneiras mais importantes para passar argumentos para uma funo ou para que a
funo retorne um resultado atravs de ponteiros. Ponteiros so empregados em funes
principalmente quando necessitamos de umas das seguintes caractersticas:
ponteiros permitem que uma funo tenha acesso direto as variveis da funo
chamadora, podendo efetuar modificaes nestas variveis;
para tipos de dados complexos ou de grande dimenso (estruturas, matrizes, ...) mais
fcil e mais rpido acessar estes dados indiretamente atravs de um ponteiro do que
realizar uma cpia destes para que a funo possa utilizar o valor copiado.
Podemos utilizar ponteiros de estruturas complexas ou matrizes como forma de fazer
com que funes retornem mais de um valor como resultado;
A passagem de parmetro com ponteiros geralmente mais rpida e eficiente do que
com o prprio dado, haja visto que o compilador no faz uma cpia deste dado e um
ponteiro necessita somente de 4 bytes para armazenar o seu valor.
Para tal, basta que em vez da funo chamadora passar valores para a funo chamada, esta
passe endereos usando operadores de endereos (&). Estes endereos so de variveis da funo
chamadora onde queremos que a funo coloque os novos valores. Estes endereos devem ser
armazenados em variveis temporrias da funo chamada para permitir posteriormente o seu
acesso.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
70

Curso de Linguagem Computacional C/C++

No exemplo a seguir mostramos como ponteiros podem ser usados como parmetros da
funo.
/* testa funca que altera dois valores */
#include <stdio.h>
void altera(int *, int *);
void main()
{
int x = 0, y = 0;
altera(&x, &y);
printf("O primeiro e %d, o segundo e %d.", x, y);
}
/* altera(), altera dois numeros da funcao que chama*/
void altera(int *px, int *py)
{
if(px != 0)
*px = 3;
if(py != 0)
*py = 5;
}

Note, que o objetivo da funo prover modificaes nas duas variveis x e y. Numa forma
simples, s poderamos efetuar esta operao utilizando-se uma estrutura para conter x e y, ou
criando uma funo para alterar cada parmetro. Entretanto, passando-se o endereo das variveis x
e y permitimos a funo chamada que altera-se diretamente os seus valores.
O valor do endereo das variveis foi obtido com o operador &. A funo necessitou apenas
da declarao de um tipo ponteiro em seu cabealho para estar apta a receber endereos de variveis
como um de seus parmetros.
Uma vez conhecidos os endereos e os tipos das variveis do programa chamador, a funo
pode no somente colocar valores nestas variveis como tambm tomar o valor j armazenado
nelas. Ponteiros podem ser usados no somente para que a funo passe valores para o programa
chamador, mas tambm para que o programa chamador passe valores para a funo.
Outro aspecto importante o teste efetuado antes de utilizar a o ponteiro recebido como
parmetro:
if(px != 0)
*px = 3;

Isto serve para que a funo verifique se o valor de endereo recebido vlido. Tome muito
cuidado com a manipulao de ponteiros, um erro no programa ou em uma funo do sistema
operacional, pode gerar um ponteiro invlido e o acesso a rea de memria representada por este
ponteiro pode causar um erro fatal no seu programa. Este um dos mtodos para prever erros com
ponteiros.

11.4 Ponteiros & Matrizes


Voc no percebe, mas C trata matrizes como se fossem ponteiros. O tipo matriz na
verdade uma forma mais amigvel que C fornece para tratar um ponteiro que aponta para uma lista
de variveis do mesmo tipo.
O compilador transforma matrizes em ponteiros quando compila, pois a arquitetura do
microcomputador entende ponteiros e no matrizes.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
71

Curso de Linguagem Computacional C/C++

Qualquer operao que possa ser feita com ndices de uma matriz pode ser feita com
ponteiros. O nome de uma matriz um endereo, ou seja, um ponteiro. Ponteiros e matrizes so
idnticos na maneira de acessar a memria. Na verdade, o nome de uma matriz um ponteiro
constante. Um ponteiro varivel um endereo onde armazenado um outro endereo.
Suponha que declaramos uma matriz qualquer :
int table = {10, 1, 8, 5, 6}

e queremos acessar o terceiro elemento da matriz. Na forma convencional por matriz, fazemos isto
atravs da instruo:
table[2]

mas a mesma instruo pode ser feita com ponteiros, considerando que o nome do vetor na
verdade um ponteiro para o primeiro elemento do vetor:
*(table+2)

A expresso (table+2) resulta no endereo do elemento de ndice 2 da matriz. Se cada


elemento da matriz um inteiro (2 bytes), ento vo ser pulados 4 bytes do incio do endereo da
matriz para atingir o elemento de ndice 2.
Em outras palavras, a expresso (table+2) no significa avanar 2 bytes alm de table e
sim 2 elementos da matriz: 2 inteiros se a matriz for inteira, 2 floats se a matriz for float e assim por
diante. Ou seja,
*(matriz + indice) == matriz[indice]

Existem duas maneiras de referenciar o endereo de um elemento da matriz: em notao de


ponteiros, matriz+indice, ou em notao de matriz, &matriz[indice].
Vamos mostrar um exemplo para esclarecer estes conceitos:
/* media de um numero arbitrario de notas */
/* exemplo de ponteiros */
#include
<stdio.h>
#define
LIM 40
void main()
{
float notas[LIM], soma = 0.0;
int register i = 0;
do
{
printf("Digite a nota do aluno %d: ", i);
scanf("%f", notas+i);
if(*(notas+i) > 0)
soma += *(notas+i);
}while(*(notas+i++) > 0);
printf("Media das notas: %.2f", soma/(i-1));
}

O operador de incremento ou decremento no pode ser aplicado a ponteiros constantes. Por


exempo, no podemos substituir o comando (notas + i++) por (notas++), haja visto que notas um
ponteiro constante.
Para fazer isto, precisamos criar um ponteiro varivel qualquer, atribuir a ele o endereo da
matriz e depois incrementar o valor deste ponteiro:
float * ptr = 0;
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
72

Curso de Linguagem Computacional C/C++

ptr = notas;
(notas + i++) == (ptr++) /* so equivalentes */

Como, ptr apontar para uma matriz do tipo float, o operador (++) incrementa em 4 bytes a
cada operao.
Podemos passar matrizes como parmetros para funes, passando-se como parmetro um
ponteiro para o primeiro elemento da matriz e depois utilizando este ponteiro para acessar todos os
elementos da matriz. Esta sintaxe funciona exatamente igual como se estivessemos passando um
ponteiro de uma varivel normal como parmetro. Veja a seco anterior para verificar esta sintaxe.

11.5 Ponteiros & Strings


Como strings so na verdade tratadas em C como matrizes simples de caracteres
finalinazadas por 0 (caracter \0), podemos utilizar as facilidades fornecidas pelos ponteiros para
manipular strings tambm. Abaixo mostramos um exemplo que ilustra este caso:
/* procura um caractere em uma string */
#include <stdio.h>
#include <conio.h>
char * procstr(char *, char);
void main()
{
char *ptr;
char ch, lin[81];
puts("Digite uma sentenca: ");
gets(lin);
printf("Digite o caractere a ser procurado: ");
ch=getche();
ptr = procstr(lin, ch);
printf("\nA string comeca no endereco %p.\n", lin);
if(ptr) /* if(ptr != 0) */
{
printf("Primeira ocorrencia do caractere: %p.\n", ptr);
printf("E a posicao: %d", ptr-lin);
}
else
printf("\nCaractere nao existe.\n");
}
char * procstr(char * l, char c)
{
if(l == 0)
return 0;
while((*l != c)&&(*l != '\0'))
l++;
if(*l != '\0')
return l;
return 0;
}

Primeiramente, fornecemos aqui um exemplo de funo que retorna como resultado um


ponteiro. Note que, antes de acessarmos o valor deste ponteiro, testamos se este um ponteiro
vlido para no cometer nenhum erro acessando uma rea imprpria da memria.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
73

Curso de Linguagem Computacional C/C++

O programa utilizou a manipulao de ponteiros para localizar a posio de um caracter em


uma string e fornecer a sua posio ao usurio. A maioria das funes em C manipulam strings
como ponteiros e, por isso, so extremamente rpidas e otimizadas.
Em vez de declararmos uma string como uma tabela, podemos faze-lo diretamente como
sendo um ponterio. O tipo (char *) reconhecido em C como sendo um tipo string, ou seja, um
ponteiro para uma sequncia de caracteres. Por isso, as inicializaes abaixo so equivalentes:
char * salute = Saudacoes;
char salute[] = Saudacoes;

Entretanto, esta inicializao alocar memria somente para o correspondente nmero de caracteres
da string passada mais um caracter \0 para delimitar a string. Nenhum espao a mais de memria
ser alocado neste caso.
As duas formas provocam o mesmo efeito, mas so diferentes: a primeira declara salute
como um ponteiro varivel e a segunda como um ponteiro constante. O valor de um ponteiro
constante no pode ser modificado, j um ponteiro varivel pode ter seu valor modificado, por um
incremento (++), por exemplo.
Podemos criar em C matrizes de ponteiros para strings. Esta uma das maneiras mais
econmicas para alocar memria para uma matriz de strings sem desperdiar memria. Por
exemplo, a inicializao:
static char * list[5] =
{
Katarina,
Nigel,
Gustavo,
Francisco,
Airton
};

Vai alocar uma matriz com 5 elementos, onde cada elemento conter o valor de um ponteiro
para uma lista de caracteres (string). Desta forma, o espao de memria necessrio para alocar ser
somente o tamanho estritamente necessrio. Como a string de ponteiros, basta alocar espao para
cada elemento de 2 bytes, enquanto que a sequncia de carateres apontado por este ponteiro pode
estar em qualquer posio de memria.
Se quisssemos fazer a mesma inializao utilizando uma matriz de vetores de caracteres,
isto implicaria que teramos que alocar uma tabela MxN para conter todos os caracteres e isto nos
levaria a disperdiar algumas posies da memria que no chegaram nunca a conter algum
caracter, j que as strings se caracterizam por conter um comprimento diferentes de caracteres.
Por isto, uma das razes para se inicializar strings com ponteiros a alocao mais
eficiente de memria. Uma outra razo a de obter maior flexibilidade para manipular matrizes de
strings.
Por exemplo, suponha que desejsemos reordenar as strings da matriz acima. Para fazer isto,
no precisamos remover as strings de sua posio e escrev-las em outra matriz na ordem correta,
basta trocar de posio os ponteiros que apontam para as strings. Reordenando os ponteiros,
obteremos a ordem desejada das strings sem ter que se preocupar em reescrever as strings em outra
posio de memria.

11.6 Ponteiros para Ponteiros


A habilidade da linguagem C de tratar partes de matrizes como matrizes cria um novo tpico
de C, ponteiros que apontam para ponteiros. Esta habilidade d a C uma grande flexibilidade na
criao e ordenao de dados complexos.
Vamos analisar um exemplo de acesso duplamente indireto de dados derivados de uma
matriz de duas dimenses.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
74

Curso de Linguagem Computacional C/C++

/* uso de ponteiros para ponteiros */


#include <stdio.h>
#define
LIN 4
#define
COL 5
void main()
{
static int tabela[LIN][COL] =
{
{13, 15, 17, 19, 21},
{20, 22, 24, 26, 28},
{31, 33, 35, 37, 39},
{40, 42, 44, 46, 48} };
int c = 10;
int j, k;
int * ptr = ( int *) tabela;
for(j=0; j<LIN; j++)
for(k=0; k<COL; k++)
*(ptr + j*COL + k) += c;
for(j=0; j<LIN; j++)
{
for(k=0; k<COL; k++)
printf("%d ", *(*(tabela+j)+k));
printf("\n");
}
}

Neste exemplo, estamos utilizando o ponteiro tabela para acessar os termos da matriz
bidimensional. Mas como fazer para acessar um termo posicionado em tabela[i][j]?
Como tabela uma matriz para inteiros, cada elemento ocupar dois bytes e cada coluna
com 5 elementos ocupar 10 bytes. Abaixo, mostramos o armazenamento desta tabela na memria
(Os endereos esto em nmeros decimais para facilitar o entendimento).
Tabela:
Mem\offset
1000
1010
1020
1030

i\j
i\offset
0
1
2
3

0
0
13
20
31
40

1
2
15
22
33
42

2
4
17
24
35
44

3
6
19
26
37
46

4
8
21
28
39
48

Vamos tentar agora acessar o elemento tabela[2][4], onde a tabela tem dimenso 4x5.
a) *(tabela + 2*5 + 4)
Note que, podemos tratar uma matriz mxn como sendo um vetor simples de inteiros, pois as
linhas so posicionadas na memria uma aps a outra. Ento, se calcularmos a posio de memria
ocupada por tabela[2][4], poderemos acessar o seu valor atravs de um ponteiro:
int * ptr = tabela : contm o endereo inicial da matriz, no caso 1000.
(ptr + 2*5) == (ptr + 10) : contm a posio incial da terceira linha da tabela (tabela[2]),
no caso 1020 pois cada elemento ocupa 2 bytes (int). Isto fica claro na matriz acima.
Sabendo-se que a terceira linha comea aps 2 linhas com 5 elementos, basta adicionar o
nmero de termos contidos nestas linhas ao ponteiro da matriz e obtemos um ponteiro
para o ncio da linha 2.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
75

Curso de Linguagem Computacional C/C++

((ptr + 2*5) + 4) == (ptr + 14) : contm a posio de memria onde est o termo
tabela[2][4], no caso 1028. Com o ponteiro da linha, queremos agora acessar o termo 4
desta linha. Ento, basta adicionar 4 ao ponteiro da linha, que obtemos um ponteiro para
o referido termo.
*(ptr + 2*5 + 4) == *(ptr + 14) : calculada a posio de memria onde est o referido
termo, basta utilizar o operador (*) para acess-lo.

b) *( *(tabela + 2) + 4)
Considere a declarao da seguinte tabela 4x5:
int tabela[4][5];

Queremos agora criar um vetor que contenha a terceira linha desta tabela. Podemos fazer
isto, usando uma das duas declaraes equivalentes:
int linha[5] = tabela[2];
int linha[5] = *(tabela + 2);

/* eq. 1 */

Note que, uma matriz na verdade um vetor contendo outras matrizes de ordem menor. Na
declarao acima, fazemos a atribuio de um elemento da matriz tabela, isto , um vetor com 5
inteiros, para uma matriz que contm 5 inteiros. A diferena das notaes que a segunda utiliza a
manipulao de ponteiros na sua declarao.
Agora, vamos acessar o quinto termo de linha, isto , linha[4]. Podemos fazer isto pelo
mtodo convecional de matrizes ou por ponteiros. Os dois mtodos abaixo so equivalentes:
int num = linha[4];
int num = *(linha + 4);
Desta forma, conseguimos acessar indiretamente o termo tabela[2][4]. Primeiro
atribumos a terceira linha da tabela a um vetor simples e depois acessamos o quinto elemento deste
vetor. Entretanto, C nos permite realizar o mesmo mtodo de acesso, sem criar este passo
intermedirio, basta fazer:
int tabela[4][5];
int num = *(*(tabela + 2) + 4); /* tabela[2][4]; */

Assim, *(tabela+2) retorna o endero da terceira linha da matriz tabela, equivalente a


escrevermos &tabela[2][0]. Ao adicionarmos 4 a este endereo, calculamos o endereo do
quinto elemento nesta linha.
Portanto, o endereo do quinto elemento (*(tabela+2)+4) e o contedo deste
endereo *(*(tabela+2)+4), que 39. Esta expresso m ponteiro para ponteiro. Este
princpio aplicado para matrizes de qualquer dimenso, em outras palavras:
tabela[j][k] = *(*(tabela + j) + k);
cubo[i][j][k] = *(*(*(cubo + i) + j) + k);

Desta maneira, C nos permite criar ponteiros para ponteiros e fazer estruturas to complexas
e flexveis quanto desejarmos. O operador *(ptr) pode ento ser aninhado para obter o valor final
apontado pela sequncia de ponteiros. Esta tcnica pode fornecer grande velocidade de execuo e
economia de memria, mas tenha cuidado para construir um cdigo claro de forma a evitar
problemas devido a um gerenciamento ruim destes ponteiros.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
76

Curso de Linguagem Computacional C/C++

11.7 Argumentos da Linha de Comando


C permite que um programa receba uma lista de parmetros atravs da funo main(). A
forma geral da funo main dada por:
int main(int argc, char* argv[]);

onde argc o nmero de argumentos passados para a funo, e argv uma matriz de string que
contm todos os argumentos passados. A funo main() nesta forma geral necessita retornar um
valor indicando o resultado do programa ao sistema operacional.No caso, o retorno do valor 0
indicar que o programa foi executado adequadamente.
Suponha que voc tenha criado um programa chamado jogo e tenha executado ele no
sistema operacional com a linha de comando:
C:> jogo

xadrex.txt

3.14159

Ao executar o programa passo-a-passo, verificaremos que argc ser igual a 4, indicando que
o usurio forneceu 4 parmetros ao programa. Sendo que os parmetros esto armazenados em argv
na forma de string e contero os seguintes valores:
argv[0]
argv[1]
argv[2]
argv[3]

==
==
==
==

jogo;
xadrex.txt;
2;
3.14159;

Conhecendo como funciona os parmetros da funo main(), voc j pode utilizar a


atribuio abaixo para obter os valores fornecidos, bastando converter o parmetro do formato
ASCII para o tipo de dado requerido :
char * param = argv[3];

11.8 Ponteiros para Estruturas


Como j mostramos ponteiros so mais fceis de manipular que matrizes em diversas
situaes, assim ponteiros para estruturas so mais fceis de manipular que matrizes de estruturas.
Vrias representaes de dados que parecem fantsticas so constitudas de estruturas contendo
ponteiros para outras estruturas. O nosso prximo exemplo mostra como definir um ponteiro para
estrutura e us-lo para acessar os membros da estrutura.
/* mostra ponteiro para estrutura */
#include <stdio.h>
struct lista /* declara estrutura */
{
char titulo[30];
char autor[30];
int regnum;
double preco;
};
int main(int argc, char * argv[])
{
static struct lista livro[2] =
{
{ "Helena", "Machado de Assis", 102, 70.50 },
{ "Iracema", "Jose de Alencar", 321, 63.25 }
};
struct lista *ptrl = 0;
/* ponteiro para estrutura */
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
77

Curso de Linguagem Computacional C/C++

printf("Endereco #1: %p
#2: %p\n", &livro[0], &livro[1]);
ptrl = &livro[0];
printf("Ponteiro #1: %p
#2: %p\n", ptrl, ptrl + 1);
printf("ptrl->preco: R$%.2f \t (*ptrl).preco:
R$%.2f\n", ptrl->preco, (*ptrl).preco);
ptrl++;
/* Aponta para a proxima estrutura */
printf("ptrl->titulo: %s \tptrl->autor: %s\n",
ptrl->titulo, ptrl->autor);
return 0;
}

A declarao feita como se estivssemos declaradando uma varivel de qualquer tipo,


adicionando-se o operador (*) na frente do nome da varivel. Por isso, a declarao de um ponteiro
para uma estrutura feito na forma :
struct lista *ptrl;
O ponteiro ptrl pode ento apontar para qualquer estrutura do tipo lista.
A atribuio de um endereo a um ponteiro de estrutura funciona da mesma forma como
uma varivel qualquer, empregando-se o operador (&):
ptrl = &(livro[0]);
Vimos no captulo sobre estruturas como fazer o acesso a um elemento de uma estrutura
atravs do operador (.). Por exemplo, se quizermos ler o valor do preco da primeira estrutura da
matriz livro, procederamos da forma:
livro[0].preco = 89.95;

Mas como proceder com ponteiros? Podemos faz-lo de duas formas.


Primeiro, podemos utilizar o operador (*) para obter a estrutura apontada por um ponteiro
e depois empregar o operador normal (.) para acessar um elemento desta estrutura. Aplicando no
exemplo acima, teremos:
(*ptrl).preco = 89.95;

O segundo mtodo utiliza o operador (->) que nos permite acessar um elemento de uma
estrutura apontada por um dado ponteiro. Aplicando-se este operador no problema acima, temos:
ptrl->preco = 89.95;

Em outras palavras, um ponteiro para estrutura seguido pelo operador (->) trabalha da
mesma maneira que o nome de uma estrutura seguido pelo operador (.). importante notar que
ptrl um ponteiro, mas ptrl->preco um membro da estrutura apontada. Neste caso, ptrl>preco uma varivel double.
O operador (.) conecta a estrutura a um membro dela; o operador (->) conecta um
ponteiro a um membro da estrutura.

11.9 Alocao Dinmica de Memria


A linguagem C oferece um conjunto de funes que permitem a alocao ou liberao
dinmica de memria. Desta forma, podemos alocar memria para um programa de acordo com a
sua necessidade instntanea de memria.
A memria de trabalho do computador (RAM) usualmente subdividida em vrios
segmentos lgicos dentro de um programa. Estes segmentos so:
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
78

Curso de Linguagem Computacional C/C++

segmento de dados, onde so alocadas as variveis globais (extern), definidas em prerun-time;


o segmento de cdigo, onde esto as instrues de mquina do programa em si;
o segmento de pilha (stack), onde as funes alocam provisoriamente suas variveis
locais (auto). Este segmento tambm usado para passagem de parmetros;
o segmento extra, que pode conter mais variveis globais;

Toda a rea de memria restante entre o fim do programa e o fim da RAM livre chamada
de heap. O heap usado para a criao de variveis dinmicas, que so criadas em run-time (isto ,
durante a execuo do programa). Este tipo de varivel til quando no se sabe de antemo
quantas variveis de um determinado tipo sero necessrias para a aplicao em questo.
Quando escrevemos um programa utilizando o mtodo de declarao de variveis visto
anteriormente (alocao esttica de memria), o programa ao ser executado alocar somente um
bloco fixo de memria para armazenar todos os seus dados. Isto resolve o problema de termos um
espao de memria alocado para podermos armazenar os dados do programa. Entretanto, como
visto no captulo de matrizes, este mtodo no otimiza a utilizao do espao de memria alocado.
Por exemplo, imagine que voc precise de uma matriz temporria para armazenar alguns dados
temporrios durante a execuo de uma dada funo de manipulao de matrizes. Para tal, voc
dever declarar esta matriz na funo, o que implicar que o computador ir alocar um bloco de
memria para esta matriz. Este espao de memria ficar alocado ao seu programa durante toda a
execuo deste, apesar do programa s utilizar uma vez esta matriz e, posteriormente, no precisar
mais desta matriz e nem do espao de memria alocado a esta.
Com a alocao dinmica de memria, podemos, em tempo de execuo, fazer com que
um programa aloque um determinado espao de memria, utilize este espao por um
determinado tempo e depois o libere, para que outros programas possam vir a utiliz-lo. No
caso do nosso exemplo, podemos fazer com que sempre que a funo for chamada, ela alocar um
espao de memria para armazenar a referida matriz e aps o seu uso, o programa liberar este
bloco de memria para que outro programa o utilize. Desta forma, se executarmos esta funo
apenas uma vez, o programa ir liberar esta memria posteriormente, permitindo assim que outros
programas faam um uso mais adequado desta.
Desta forma, a alocao dinmica de memria utilizada em programas para alocar e
liberar blocos temporrios de memrias durante a execuo de um programa (por isso
chamado alocao dinmica). Este bloco de memria solicitado ao sistema operacional que
procura um espao livre de memria para o programa. Se o sistema operacional achar um bloco de
memria livre do tamanho do bloco solicitado, este passa o bloco de memria para o controle do
programa e no ir permitir que nenhum outro programa utilize esta memria enquanto ela estiver
alocada. No final do seu uso, o programa libera novamente esta memria ao sistema operacional.
Outro exemplo de aplicao da alocao dinmica de memria na utilizao de
matrizes quando no sabemos de antemo quantos elementos sero necessrios. Desta forma,
podemos utilizar a alocao dinmica de memria para somente alocar a quantidade necessria de
memria e no momento em que esta memria for requerida.

11.9.1 Malloc()
A funo malloc() utilizada para fazer a alocao dinmica de um bloco de memria a
um dado programa. A funo malloc() toma um inteiro sem sinal como argumento. Este nmero
representa a quantidade em bytes de memria requerida. A funo retorna um ponteiro para o
primeiro byte do novo bloco de memria que foi alocado.
importante verificar que o ponteiro retornado por malloc() para um tipo void. O
conceito de ponteiro para void deve ser introduzido para tratar com situaes em que seja
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
79

Curso de Linguagem Computacional C/C++

necessrio que uma funo retorne um ponteiro genrico, i.e., que possa ser convertido em um
ponteiro para qualquer outro tipo de dado. Este ponteiro void pode ser convertido para um ponteiro
do tipo de dado desejado (int, float, struct, ...) empregando-se o mtodo de converso de tipos
apresentado na seco sobre tipos de dados (ver 2.5). No prximo exemplo, mostraremos o seu
emprego novamente.
Quando a funo malloc() no encontrar espao suficiente de memria para ser alocado,
esta retornar um ponteiro NULL, i.e., um ponteiro invlido.
O exemplo abaixo mostra como a funo malloc() opera. Este programa declara uma
estrutura chamada xx e chama malloc() 4 vezes. A cada chamada, malloc() retorna um
ponteiro para uma rea de memria suficiente para guardar um nova estrutura.
/* testa malloc() */
#include <stdio.h>
struct xx
{
int numl;
char chl;
};
void main()
{
struct xx *ptr = 0;
int j;
printf("sizeof(struct xx) = %d\n", sizeof(struct xx));
for(j=0; j<4; j++)
{
ptr = (struct xx *) malloc(sizeof(struct xx));
printf("ptr = %x\n", ptr);
}
}

Note que em nenhuma parte do programa declaramos qualquer varivel estrutura. De fato,
a varivel estrutura criada pela funo malloc(); o programa no conhece o nome desta
varivel; mas sabe onde ela est na memria, pois malloc() retorna um ponteiro para ela. As
variveis criadas podem ser acessadas usando ponteiros, exatamente como se tivessem sido
declaradas no incio do programa.
A cada chamada de malloc() devemos nform-la do tamanho da estrutura que queremos
guardar. Ns podemos conhecer este tamanho adicionando os bytes usados por cada membro da
estrutura, ou atravs do uso de um novo operador em C unrio chamado sizeof(). Este operador
produz um inteiro igual ao tamanho, em bytes, da varivel ou do tipo de dado que est em seu
operando. Por exemplo, a expresso
sizeof(float)

retornar o valor 4, haja vista que um float ocupa 4 bytes. No programa exemplo, usamos
sizeof() em printf() e ele retorna 3, pois a estrutura xx consiste em um caracter e um
inteiro.
Ento, sizeof() forneceu o tamanho em bytes da estrutura para que malloc() pudesse
alocar o espao de memria requerido. Feito isto, malloc() retornou um ponteiro do tipo void,
que foi convertido para o tipo struct xx atravs da expresso:
(struct xx *)
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
80

Curso de Linguagem Computacional C/C++

11.9.2 Calloc()
Uma outra opo para a alocao de memria o uso da funo calloc(). H uma grande
semelhana entre calloc() e malloc() que tambm retorna um ponteiro para void apontando
para o primeiro byte do bloco solicitado.
A nova funo aceita dois argumentos do tipo unsigned int. Um uso tpico mostrado
abaixo:
long * memnova;
memnova = (long *) calloc(100, sizeof(long));

O primeiro argumento o nmero de clulas de memrias desejadas e o segundo argumento


o tamanho de cada clula em bytes. No exemplo acima, long usa quatro bytes, ento esta
instruo alocar espao para 100 unidades de quatro bytes, ou seja, 400 bytes.
A funo calloc() tem mais uma caracterstica: ela inicializa todo o contedo do
bloco com zero.

11.9.3 Free()
A funo free()libera a memria alocada por malloc() e calloc(). Aceita, como
argumento, um ponteiro para uma rea de memria previamente alocada e ento libera esta rea
para uma possvel utilizao futura.
Sempre que um espao de memria for alocado, este deve ser necessariamente liberado aps
o seu uso. Se no for liberada, esta memria ficar indiponvel para o uso pelo sistema operacional
para outros aplicativos. A utilizao consciente da alocao e liberao dinmica de memria,
permite um uso otimizado da memria disponvel no computador.
A funo free()declara o seu argumento como um ponteiro para void. A vantagem desta
declarao que ela permite que a chamada funo seja feita com um argumento ponteiro para
qualquer tipo de dado.
long * memnova;
memnova = (long *)calloc(100, sizeof(long));
/* usa memnova */
free(memnova); /* libera a memria alocada */

11.10

Exerccios

11.1 Escreva um programa que receba duas strigns como argumentos e troque o contedo de
string1 como string2.
11.2 Escreva um programa que inverta a ordem dos caracteres de uma string. Por exemplo,
se a string recebida Saudacoes deve ser modificada para seocaduaS.
11.3 Reescreva o programa do exerccio 9.1 utilizando alocao dinmica de memria.
11.4 Reescreva o programa do exerccio 9.3 utilizando alocao dinmica de memria.
11.5 A lista encadeada se assemelha a uma corrente em que as estruturas esto penduradas
sequencialmente. Isto , a corrente acessada atravs de um ponteiro para a primeira estrutura,
chamada cabea, e cada estrutura contm um ponteiro para a sua sucessora, e o ponteiro da ltima
estrutura tem valor NULL (0) indicando o fim da lista. Normalmente uma lista encadeada criada
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
81

Curso de Linguagem Computacional C/C++

dinamicamente na memria. Crie um programa com uma lista encadeada para armazenar dados de
livros em uma biblioteca.
11.6 Crie um programa com lista encadeada para catalogar clientes e fitas em uma vdeo
locadora.
11.7 Crie uma estrutura para descrever restaurantes. Os membros devem armazenar o nome,
o endereo, o preo mdio e o tipo de comida. Crie uma lista ligada que apresente os restaurantes de
um certo tipo de comida indexados pelo preo. O menor preo deve ser o primeiro da lista. Escreva
um programa que pea o tipo de comida e imprima os restaurantes que oferecem ete tipo de comida.
11.8 Escreva um programa para montar uma matriz de estruturas para armazenar as notas de
40 alunos. A primeira coluna da matriz deve conter o nome do aluno, a segunda o telefone, a
terceira a data de nascimento, depois seguem as notas em lista e na ltima coluna deve ser calculada
a mdia at o presente momento. A professora deve ser capaz de inserir e retirar alunos, e poder
editar os dados dos alunos. A professora deve poder tambm listar os dados de todos alunos na
forma de uma tabela na tela do computador. A lista de alunos deve ser indexada pelo nome destes.
Utilize a idia da lista ligada e da alocao dinmica de memria.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
82

Curso de Linguagem Computacional C/C++

12 Manipulao de Arquivos em C
Neste captulo, veremos brevemente a manipulao de arquivos em C. Em um captulo
posterior, ser apresentada novamente a manipulao de arquivos agora utilizando C++.

12.1 Tipos de Arquivos


Uma maneira de classificar operaes de acesso a arquivos conforme a forma como eles
so abertos: em modo texto ou em modo binrio.
Arquivos em modo texto, operam em dados armazenados em formato texto, ou seja, os
dados so traduzidos para caracteres e estes caracteres so escritos nos arquivos. Por esta razo, fica
mais fcil de compreender os seus formatos e localizar possveis erros.
Arquivos em modo binrio, operam em dados binrios, ou seja, os dados escritos neste
formato so escritos na forma binria, no necessitando de nenhuma converso do tipo do dado
utilizado para ASCII e ocupando bem menos memria de disco (arquivos menores).
Uma outra diferena entre o modo texto e o modo binrio a forma usada para guardar
nmeors no disco. Na forma de texto, os nmeros so guardados como cadeias de caracteres,
enquanto que na forma binria so guardados com esto na memria, dois bytes para um inteiro,
quatro bytes para float e assim por diante.

12.2 Declarao, abertura e fechamento


C declara um tipo especial de estrutura, chamada FILE, para operar com arquivos. Este tipo
definido na biblioteca stdio.h, que deve ser incluida na compilao com a diretiva #include para
permitir operaes sobre arquivos. Os membros da estrutura FILE contm informaes sobre o
arquivo a ser usado, tais como: seu atual tamanho, a localizao de seus buffers de dados, se o
arquivo est sendo lido ou gravado, etc.
Toda operao realizada sobre um arquivo (abertura, fechamento, leitura, escrita) requer um
apontador para uma estrutura do tipo FILE:
FILE *File_ptr;

A abertura de um arquivo feita com a funo fopen():


File_ptr = fopen(Nome do Arquivo,<I/O mode>);

onde as opes para a abertura do arquivo esto listadas abaixo:


I/O mode Funo:
Read, abre arquivo para leitura. O arquivo deve existir.
r
Write, abre arquivo para escrita. Se o arquivo estiver presente ele ser destrudo e
w
reinicializado. Se no existir, ele ser criado.
Append, abre arquivo para escrita. Os dados sero adicionados ao fim do arquivo se
a
este existir, ou um novo arquivo ser criado.
Read, abre um arquivo para leitura e gravao. O arquivo deve existir e pode ser
r+
atualizado.
Write, abre um arquivo para leitura e gravao. Se o arquivo estiver presente ele ser
w+
destrudo e reinicializado. Se no existir, ele ser criado.
Append, abre um arquivo para atualizaes ou para adicionar dados ao seu final.
a+
Text, arquivo contm texto dados em ASCII.
t
Binary, arquivo contm dados em binrio.
b
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
83

Curso de Linguagem Computacional C/C++

A funo fopen() executa duas tarefas. Primeiro, ela preenche a estrutura FILE com as
informaes necessrias para o programa e para o sistema operacional, assim eles podem se
comunicar. Segundo, fopen() retorna um ponteiro do tipo FILE que aponta para a localizao na
memria da estrutura FILE.
A funo fopen() pode no conseguir abrir um arquivo por algum motivo (falta de
espao em disco, arquivo inexistente, etc.) e por isso esta retornar um ponteiro invlido, isto ,
contendo o valor NULL (0). Por isso, teste sempre se o ponteiro fornecido por fopen() vlido
antes de utilizado, caso contrrio o seu programa pode vir a ter uma falha sria.
Quando terminamos a gravao do arquivo, precisamos fech-lo. O fechamento de um
arquivo feito com a funo fclose():
fclose(File_ptr);

Quando fechamos um arquivo que o sistema operacional ir salvar as suas modificaes


ou at mesmo criar o arquivo, no caso de ser um arquivo novo. At ento, o sistema operacional
estava salvando as alteraes em um buffer antes de escrever estes dados no arquivo. Este
procedimento executado para otimizar o tempo de acesso ao disco empregado pelo sistma
operacional. Por isso, no esquea de fechar um arquivo, seno os seus dados podem ser perdidos e
o arquivo no seja criado adequadamente.
Uma outra razo para fechar o arquivo a deliberar as reas de comunicao usadas, para
que estejam disponveis a outros arquivos. Estas reas incluem a estrutura FILE e o buffer.
Uma outra funo que fecha arquivos a funo exit(). A funo exit() difere da
funo fclose() em vrios pontos. Primeiro, exit() fecha todos os arquivos abertos. Segundo,
a funo exit() tambm termina o programa e devolve o controle ao sistema operacional.
A funo fclose() simplesmente fecha o arquivo associado ao ponteiro FILE usado
como argumento.

12.3 Leitura e escrita de caracteres


A funo usada para ler um nico caracter de um arquivo getc() enquanto que a funo
putc() escreve um caracter em um arquivo. Abaixo, apresentamos exemplos destas funes:
Escrita

Leitura

#include <stdio.h>
FILE *fileptr;
char filename[65];
char mychar;
fileptr = fopen(filename,w);
putchar(mychar,fileptr);
fclose(fileptr);

#include <stdio.h>
FILE *fileptr;
char filename[65];
int mychar;
int i = 0;
fileptr = fopen(filename,r);
mychar = getchar(fileptr);
while(mychar != EOF)
{
printf(%c, mychar);
mychar = getchar(fileptr);
}
fclose(fileptr);

12.4 Fim de Arquivo (EOF)


EOF um sinal enviado pelo sistema operacional para indicar o fim de um arquivo. O sinal
EOF (Fim de Arquivo) enviado pelo sistema operacional para o programa C no um caracter, e
sim um inteiro de valor 1 e est definido em stdio.h.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
84

Curso de Linguagem Computacional C/C++

Perceba que no exemplo anterior de leitura de caracteres, ns usamos uma varivel inteira
para guardar os caracteres lidos para que possamos interpretar o sinal de EOF. Se usarmos uma
varivel do tipo char, o caractere de cdigo ASCII 255 decimal (0xFF em Hexa) ser interpretado
como EOF. Queremos usar todos os caracteres de 0 a 255 em nosso arquivo e uma varivel inteira
nos assegura isto. Neste exemplo, EOF usado para ler todos os caracteres de um dado arquivo,
quando no conhecemos de antemo a quantidade de caracteres deste arquivo.
A marca de fim de arquivo pode ser diferente para diferentes sistemas operacionais. Assim,
o valor de EOF pode ser qualquer. O seu arquivo stdio.h define EOF com o valor correto para o seu
sistema operacional; assim, em seus programas, use EOF para testar fim de arquivo.
O fim de um arquivo pode tambm ser determinado utilizando-se a funo feof(), que
recebe como parmetro um ponteiro vlido para a estrutura FILE.

12.5 Leitura e escrita de strings


A funo fputs() escreve uma string em um arquivo e, por isso, toma dois argumentos,
sendo o primeiro a matriz de caracteres que ser gravada e o segundo o ponteiro para a estrutura
FILE do arquivo a ser gravado. Observe que a funo fputs() no coloca automaticamente o
caractere de nova-linha no fim de cada linha. No programa exemplo abaixo, fazemos isto
explicitamente com o caracter \n.
A funo gets() l uma linha por vez de um arquivo texto. A funo gets() toma 3
argumentos. O primeiro um ponteiro para o buffer onde ser colocada a linha lida. O segundo
um nmero inteiro que indica o limite mximo de caracteres a serem lidos. Na verdade, este nmero
deve ser pelo menos um maior que o nmero de caracteres lidos, pois gets() acrescenta o
caractere NULL (\0) na prxima posio livre. O terceiro argumento um ponteiro para a
estrutura FILE do arquivo a ser lido. A funo termina a leitura aps ler um caractere de nova linha
(\n) ou um caractere de fim de arquivo (EOF).
Escrita:
#include <stdio.h>
FILE *fileptr;
char filename[65];
char line[81];
fileptr = fopen(filename, w);
fputs(line, fileptr); /* fprintf(fileptr,%s\n, line) */
*/
fputs(\n, fileptr); /* pode ser usado aqui no lugar
fclose(fileptr);
/* dos dois fputs */

Leitura:
#include <stdio.h>
FILE *fileptr;
char filename[65];
char line[81];
fileptr = fopen(filename, r);
/* fscanf(fileptr, %s, line); */
fgets(line, 80, fileptr);
close(fileptr);
/* pode ser usado no lugar de fgets */

12.6 Arquivos Padres


C define um conjunto de arquivos padres utilizados para acessar alguns perfecos do
computador (como a impressora) ou para ler da entrada padro (normalmente o teclado) ou escrever
para a sada padro (normalmente a tela).

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
85

Curso de Linguagem Computacional C/C++

Desta forma, _streams[] foi criada como uma matriz de estruturas FILE. Se voc perder um
tempo e analisar o seu arquivo stdio.h, encontrar vrias constantes simblicas definidas como:
#define
#define
#define
#define
#define

stdin
stdout
stderr
stdaux
stdprn

(&_streams[0])
(&_streams[1])
(&_streams[2])
(&_streams[3])
(&_streams[4])

Estas constantes podem ser usadas para acessar qualquer um dos 5 arquivos padro que so
predefinidos pelo MS-DOS e abertos automaticamente quando o seu programa inicia a sua
execuo e fechados ao seu fim.
Nome:
stdin
stdout
stderr
stdaux
stdprn

Perifrico:
Standard input device (teclado)
Standard output device (tela)
Standard error device (tela)
Standard auxiliary device (porta serial)
Standard printing device (impressora paralela)

Cada uma destas constantes pode ser tratada como um ponteiro para uma estrutura FILE dos
arquivos in, out, err, aux e prn respectivamente. Voc pode usar os ponteiros FILE definidos em
stdio.h para acessar os perifricos predefinidos pelo MS-DOS ou usar seus nomes e definir os
ponteiros necessrios. Como exemplo, a instruo:
fgets(string, 80, stdin);

l uma string do teclado.


A instruo:
fputs(string, stdprn);

imprimir uma string na impressora.

12.7 Gravando um Arquivo de Forma Formatada


Nos captulos iniciais apresentamos a funo printf() para imprimir na tela dados de
forma formatada. Para realizar a mesma tarefa, entretanto no para escrever na tela mas sim para
um arquivo, foi criada a funo fprintf(). Esta funo similar a printf() exceto que o
ponteiro para FILE tomado como primeiro argumento. Como em printf(), podemos formatra
os dados de vrias maneiras; todas as possibilidades de formato de printf() operam com
fprintf().
Da mesma forma foi criada a funo fscanf(), que como scanf(), l um dado
formatado. A diferena consiste que fscanf() l um dado de um arquivo e recebe um ponteiro
para FILE como primeiro argumento.
Exemplo :
#include <stdio.h>
FILE *fptr;
int size = 0;
fptr = fopen(dados.txt, rw);
fscanf(fptr, %d, &size);
fprintf(fptr, %s %d %f, Casa Nova, 12, 13.45);
fclose(fptr);
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
86

Curso de Linguagem Computacional C/C++

12.8 Leitura e escrita de valores binrios


Quando desejamos operar com arquivos no modo binrio, basta adicionar o caracter b no
I/O Mode da funo open(), como apresentado anteriormente. As funes apresentadas
anteriormente podem ser usadas para ler e escrever no modo binrio, entretanto apresentaremos
aqui duas novas funes que facilitam este processo: fwrite() e fread(). Estas funes so
empregadas para escrever/ler os dados armazenados em um bloco de memria (um buffer de
memria) em um arquivo. Aplicaes tpicas e na escrita/leitura de dados complexos como matrizes
e estruturas.
A funo fwrite() toma 4 argumentos. O primeiro um ponteiro do tipo void que aponta
para a localizao na memria do dado a ser gravado. O segundo argumento um nmero inteiro
que indica o tamanho do tipo de dado a ser gravado. Normalmente, pode-se utilizar o operador
sizeof() para se obter este valor. O terceiro argumento um nmero inteiro que informa a
fwrite() quantos itens do mesmo tipo sero gravados. O quarto argumento um ponteiro para a
estrutura FILE do arquivo onde queremos gravar.
A funo fread() toma tambm 4 argumentos. O primeiro um ponteiro void para a
localizao da memria onde sero armazenados os dados lidos. O segundo indica tambm a
quantidade de bytes do tipo de dado a ser lido. O terceiro argumento informa a quantidade de itens a
serem lidos a cada chamada, e o quarto argumento um ponteiro para a estrutura FILE do arquivo a
ser lido.
A funo fread() retorna o nmero de itens lidos. Normalmente este nmero deve ser
igual ao terceiro argumento. Se for encontrado o fim do arquivo, o nmero ser menor que o valor
do terceiro argumento, podendo ser zero caso nenhum dado tenha sido lido.
As funes fread()e fwrite() trabalham com qualquer tipo de dado, incluindo
matrizes e estruturas, e armazenam nmeros em formato binrio.
Escrita:
fileptr = fopen(filename, wb);
fwrite(&dados, sizeof(dados),1 ,fileptr);

Leitura:
fileptr = fopen(filename, rb);
fread(&dados,sizeof(dados),1 ,fileptr);

Se "filename" for inicializado com prn, os dados so enviados a impressora.


Exemplo:
fileptr=fopen(filename,rb);
while(!feof(fileptr))
{
fread(&dados, sizeof(dados),1,fileptr);
}
fclose(fileptr);

12.9 Exerccios
12.1 Escreva um programa que imprima um arquivo na tela de 20 em 20 linhas. O arquivo
de entrada deve ser fornecido na linha de comando. A cada impresso de 20 linhas, o programa
aguarda o pressionamento de uma tecla.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
87

Curso de Linguagem Computacional C/C++

12.2 Escreva um programa que imprima o tamanho de um arquivo em bytes. O nome do


arquivo deve ser fornecido na linha de comando.
12.3 Escreva um programa que criptografa um arquivo usando o operador de complemento
de bit-a-bit (~). Quando o programa executado para um arquivo j criptografado, o arquivo
recomposto e volta ao original.
12.4 Refaa o problema 11.5, agora salvando a lista de livros em um arquivo. Permita que o
usurio possa retirar um livro desta lista, apagando-o do arquivo, ou adicionar um livro em uma
posio determinada na lista, reescrendo a lista no arquivo. Utilize o modo texto para a manipulao
de arquivos.
12.5 Como o exemplo anterior, refaa o problema 11.6 mas agora utilizando o modo binrio.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
88

Curso de Linguagem Computacional C/C++

13 Programao em C++
A linguagem C foi e continua sendo uma das linguagens mais importantes na rea da
informtica. Apesar do seu timo desempenho em termos de programas otimizados, velozes e
portteis sofreu duras crticas com relao qualidade do cdigo gerado considerando-se outros
aspectos de relevncia da engenharia de software como: legibilidade do cdigo, sua reusabilidade e
facilidade de manuteno.
Um programa de computador sempre busca representar uma dada realidade (mundo real ou
modelo abstrato: matemtico) atravs de uma linguagem de programao. Quando criamos qualquer
programa simples de computador, estamos na verdade criando um modelo da realidade e usando
este modelo para analisar e estudar esta realidade. O nvel de detalhe com que criamos um
programa depende diretamente do nvel de detalhe necessrio para modelar o ambiente de acordo
com as necessidades impostas pelo usurio.
Modelar um determinado ambiente complexo utilizando-se somente as estruturas e
funcionalidades disponveis por C (linguagem estrutural) uma tarefa rdua. Por esta razo, alguns
programadores em C no conseguem muitas vezes entender determinados cdigos em C, pois no
conseguem entender o modelo da realidade gerado por este programa ou a sua estrutura.
Neste sentido, criou-se uma forma totalmente nova e revolucionria para se modelar e
simular um ambiente dado (mundo real ou sistema abstrato): a Orientao a Objetos. A Orientao
a Objetos busca modelar um ambiente utilizando-se dos prprios elementos presentes neste
ambiente, ou seja, os objetos. Todo ambiente pode ser modelado e simulado a partir de uma
descrio dos objetos que o compe e das relaes entre eles.
Por exemplo, suponha que voc esteja criando um programa para permitir que um arquiteto
crie um modelo grfico de uma sala-de-estar e apresente este modelo ao seu cliente. Empregando a
metodologia de Orientao a Objetos, primeiramente o arquiteto ter que identificar os objetos que
compem a sala-de-estar que, considerando o nvel de abstrao do seu modelo, devem ser
descritos. Neste caso, podemos facilmente listar alguns objetos que podem ser definidos: janela,
porta, parede, sof, mesa, quadro, tapete, vaso de flores, etc.
A quantidade de objetos e o nvel de detalhe da sua descrio dependero necessariamente
do nvel de abstrao do modelo, ou seja, daquilo que o arquiteto considera importante que esteja no
modelo. Por exemplo, representar o objeto mesa pode significar para um marceneiro definir a sua
geometria, o tipo de material, o tipo de verniz requerido e o tipo do seu acabamento, enquanto que
para um arquiteto significa definir a textura da mesa, o tom da sua cor, o seu custo, a durabilidade
desta, etc. Por isso, importante ter em mente, as necessidades do seu cliente antes de criar um
modelo super detalhado e ineficiente.
Aps a definio dos objetos que compem um dado ambiente, precisamos definir as
relaes entre estes. Por exemplo, precisamos definir que um objeto porta e um objeto janela
esto posicionados sob a mesma parede, ou seja, so propriedades de um terceiro objeto chamado
parede. Assim, como outro objeto parede pode no conter uma janela mas um objeto do tipo
quadro. Podemos at criar um objeto chamado sala que contm todos os objetos presentes na
sala descrita pelo arquiteto e permitir que este arquiteto venha criar futuramente outros objetos
como cozinha ou quarto e possa, assim, modelar toda uma residncia.
Com este breve esclarecimento j apontamos algumas das propriedades vantajosas
fornecidas pela programao Orientada a Objetos. A linguagem C++ foi criada a partir da
linguagem C, acrescentando novas estruturas e mecanismos que possibilitam a gerao de
programas segundo a metodologia de Orientao a Objetos. Algumas linguagens como Smalltalk
refletem muito mais a cultura ou a metodologia Orientada a Objetos, favorecendo a gerao de
programas segundo esta metodologia. C++ uma espcie de adaptao de C a metodologia de
Orientao a Objetos e, por isso, no possui todas as facilidades e mecanismos de uma linguagem
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
89

Curso de Linguagem Computacional C/C++

puramente Orientada a Objetos como Smalltalk. Entretanto, C++ herda de C a capacidade de gerar
programas pequenos, otimizados, de baixo-nvel e portveis. Estes motivos propiciaram a grande
difuso que a linguagem C++ vem sofrendo nos ltimos anos.
A gerao de cdigos em C++ requer normalmente um tempo maior de desenvolvimento
que um programa em C normal. Entretanto os ganhos em reusabilidade e em diminuio dos tempos
de manuteno do programa, fazem com que C++ seja mais atrativo para a gerao de mdios e
grandes sistemas. Emprega-se C basicamente quando temos que fazer um programa em pouco
tempo, com grandes restries na dimenso do cdigo e no tempo disponvel para o processamento
do programa (requisistos de tempo-real).
A reusabilidade advm do fato que objetos definidos para representar um dado ambiente,
podem ser empregados para representar um outro ambiente. Por exemplo, para representar o
ambiente sala-de-estar, haviamos definido o objeto mesa. Podemos, entretanto, utilizar o mesmo
objeto mesa para representar o ambiente cozinha, sem precisar redefini-lo novamente. Neste
aspecto, ganhamos em tempo de desenvolvimento.
A modelagem orientada a objetos fornece uma estrutura bem clara para o cdigo fonte do
programa. Isto permite que outro programador possa entender o programa criado, reutilizar partes
em outros programas e, ainda, facilmente localizar erros no cdigo fonte. Por exemplo, suponha que
na hora em que o programa estiver desenhando o objeto mesa na tela para o cliente do arquiteto
aparea algum defeito na mesa. Poderemos, ento, facilmente concluir que: ou o objeto mesa est
mal representado (erro dentro da definio do objeto mesa), ou a relao deste objeto com os
demais est mal definida (por exemplo, a posio deste objeto na sala), ou o mecanismo
responsvel pelo desenho deste objeto na tela no est operando corretamente. Isto nos permite que,
rapidamente, possamos localizar, isolar e, em seguida, corrigir este erro.
A programao orientada a objeto se baseia no encapsulamento de uma estrutura de dados
com as prprias rotinas de tratamento dos mesmos e na capacidade de herana destes dados e
rotinas por outros objetos derivados.
A programao orientada a objeto traz consigo uma srie de vantagens e tambm algumas
desvantagens. Como vantagens podem-se citar:
existem muitas ferramentas de apoio ao desenvolvimento de programas;
os programas tm uma estrutura altamente modular, o que permite um mais fcil
controle e expanso dos mesmos. Por exemplo, basta alterar as caractersticas de um
objeto "me" para que todos os objetos "filhos" (que herdaram propriedades) sejam
tambm automaticamente alterados de forma correspondente;
a programao orientada a objeto se baseia fortemente na prpria forma de pensar
humana, ao contrrio da forma algortmica e procedural da programao convencional.
Por outro lado, h tambm desvantagens relativas a esta forma de programao:
grande necessidade de memria;
grande complexidade de gerenciamento interno das estruturas dos objetos, o que implica
em velocidade de execuo menor.
difcil otimizao de tempo de execuo dos programas. A otimizao de programas
freqentemente requer uma violao das prprias regras de programao orientada a
objeto.

Estas desvantagens tm se tornado menos crticas nos ltimos anos devido ao grande
aumento da velocidade de processamento dos computadores bem como ao aumento de sua
capacidade de memria.
Nesta etapa do trabalho, buscaremos agora apresentar os mecanismos mais importantes
fornecidos pela linguagem C++, descrevendo no somente a sintaxe de C++ mas tambm conceitos
envolvidos na programao Orientada a Objetos. Neste captulo, apresentaremos brevemente quais
so as novidades da linguagem C++. Posteriormente, apresentaremos os demais mecanismos da
orientao a objetos.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
90

Curso de Linguagem Computacional C/C++

13.1 Palavras-chave C++


A linguagem C++ inclui apenas 14 novas palavras reservadas s j existentes no C:
catch
class
delete
friend

inline
new
operator

private
protected
public

template
this
virtual

13.2 Sintaxe & Variveis


A linguagem C permite a declarao de variveis dentro de uma funo, somente antes da
chamada a instrues desta funo, ou seja, primeiro declaramos as variveis e depois podemos
efetuar uma dada instruo. Em C++, alm destas formas pode-se declarar uma varivel em
qualquer ponto de um programa, inclusive entre instrues ou mesmo dentro delas.
Em C++, no necessrio utilizar a palavra typedef para se definir uma estrutura. A prpria
etiqueta especificando nome (estrutura ou unio) j um tipo nome. Mesmo que no tenhamos
usado o typedef, o compilador C++ permitir declaraes de variveis estruturadas sem a
necessidade de struct. Assim, podemos redefinr a estrutura list da seguinte maneira :
struct list
{
char
titulo[30];
char
autor[30];
int
regnum;
double
preco;
};
list * livros; // declarao de uma varivel do tipo list

Em C++, toda varivel que no for declarada explicitamente como static, ser considerada
do tipo extern automaticamente. Alm deste default, o C++ ampliou o conceito de escopo para
variveis de tipos compostos (estruturas e classes). Essa ampliao consiste em tornar visveis ou
inacessveis membros particulares de estruturas e classes. Abordaremos isto quando do estudo de
classes.
Suponha que ao definir uma funo voc tenha criado uma varivel local com o mesmo
nome que uma varivel global (extern). Ao utilizar o nome da varivel, voc estar acessando
dentro da funo somente a varivel local. Entretanto, voc pode utilizar o operador :: (escopo) para
acessar a varivel global. Veja o exemplo:
int n = 10; // varivel extern, referenciada por: n ou ::n
void calc()
{
int n = 5; // varivel auto, local
n = ::n;
// varivel local recebe o valor da var. extern.
}

A linguaguem C++ apresenta uma outra forma de comentrios: uma linha iniciada pelo para
de caracteres de barra //, como indicam os seguintes exemplos:
// Este um comentario em C++
// Aps a barra dupla, tudo comentrio at o final da linha.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
91

Curso de Linguagem Computacional C/C++

13.3 Laos e Comandos de Deciso


A linguagem C++ no modifica sintaxe ou comportamento dos laos e comandos
condicionais do C. Porm, permite a declarao de variveis na regio de inicializao do for, ou
seja, antes do lao estas variveis inexistem. Exemplo:
int j =0;
for(int i =0, j=3; i+j<10; i = j++ )

13.4 I/O em C++: Stream


A linguagem C++ permite a utilizao dos mecanismos de I/O definidos em C, mas define
novas bibliotecas, mais adequadas ao paradigma da Orientao a Objetos. Essas bibliotecas
constituem a chamada biblioteca Stream do C++, sendo esta biblioteca toda definida em termos de
classes de objetos. Nela esto os trs objetos: cin, cout e cerr destinados entrada e sada de dados
via terminal ou via arquivos. As definies e declaraes necessrias para o uso de streams esto
contidas no arquivo <iostream.h>.

13.4.1 A stream de sada cout


Cout um objeto de uma clase de I/O predefinida em C++. Para mostrar os dados em um
programa C++, deve-se utilizar a stream cout. Por default cout est associada a uma sada
padro (stdout), i.e., o ao terminal de vdeo. Sintaxe de cout :
cout << expresso;

onde,
<< : o operador de insero usado a fim de direcionar a sada de dados para a sada
padro (vdeo).
expresso : qualquer combinao de caracteres ou varivel.
Abaixo apresentamos alguns exemplos da utilizao de cout. Note que em nenhuma das
declaraes da stream cout so formatados os dados a serem apresentados. Essa formatao feita
pela prpria stream.
Variveis

C++

int x = 2;
Float f = 1.2, g = 3;
Double dou = 2.14;
Char ch = F;

Cout << x =
Cout << f <<
Cout << valor
<< dou <<

Resultado
<< x;
<< g;
=
\nsex = << ch;

x = 2
1.20 3.00
valor = 2.14
sex = F

No ltimo exemplo acima, mostramos o uso do caracter especial \n para fazer com que o
computador pule uma linha antes de continuar escrevendo dados na tela. Podemos utilizar todos os
caracteres especiais definidos para printf() da mesma maneira que utilizamos agora \n. Uma
lista completa destes caracteres est em 3.1.
O objeto cout utiliza flags de formatao para sinalizar as opes de formatao dos
dados. Os flags (sinalizadores) de formato (definidos em <iomanip>) so os seguintes:
Manipulador
skipws
left
right
internal

Significado
Ignora o espao em branco na entrada
Sada ajustada esquerda
Sada ajustada direita
Preenchimento aps indicador de sinal ou base

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
92

Curso de Linguagem Computacional C/C++

dec
oct
hex
showbase
showpoint
uppercase
showpos
scientific
fixed
unitbuf
stdio

Converso em decimal
Converso em octal
Converso em hexadecimal
Mostra o indicador de base na sada
Mostra ponto decimal (para float)
Sada hexadecimal maiscula
Mostra o sinal + em inteiros positivos
usa notao cientfica de ponto flutuante 1.23E2
usa notao de ponto flutuante 1.23
Libera (flush) todas as streams depois da insero
Libera (flush) stdout, stderr depois de insero

A sintaxe para usar esses sinalizadores (ou flags) a seguinte:


cout.setf(ios::<sinalizador>);
// para ligar
cout.setf(ios::scientific);
cout << 12.345; // Imprimir : 0.12345E2
cout.unsetf(ios::<sinalizador>); // para desligar
cout.unsetf(ios::scientific);
cout << 12.345
// Imprimir: 12.345

O objeto cout permite estabelecer o tamanho de um campo para a impresso. Isto significa
que podemos definir o nmero de colunas que sero ocupados por um valor ou texto a ser impresso.
Geralmente, a definio de tamanho de campos usada para alinhamento e esttica de um relatrio.
Os manipuladores de formato so utilizados para manipular a formatao dos dados em
streams de sada. Alguns manipuladores so idnticos ao sinalizadores, a diferena est na forma
mais compacta e na incluso de outra biblioteca de classes <iomanip>.
Manipulador
dec
oct
hex
ws
endl
ends
flush
setbase(n)
resetiosflags(long)
setiosflags(long)
setfill(int n)
setprecision(int n)
setw(int n)

Significado
Passa ara base decimal
Passa ara base octal
Passa ara base hexadecimal
Extrai caracteres de espao em branco
Insere nova linha e libera stream
Insere trmino nulo em string \0
Libera o buffer de sada ostream alocado
Ajusta o formato de converso para a base n. default n = 0;
Limpa os bits de formato em ins ou outs especificadas.
Ajusta os bits de fomato em ins ou outs especificadas.
Ajusta o caracter de preenchimento para n
Ajusta a preciso do ponto flutuante para n
Ajusta o tamanho do campo para n

Exemplo do uso destes manipuladores:


//
Exemplo do emprego de Cout
#include <iostream>
#include <iomanip>
using namespace std;
int main(int argc, char* argv[])
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
93

Curso de Linguagem Computacional C/C++

{
float lap = 4.875;
float bor = 234.5421234546;
int can = 42;
int cad = -8;
cout << "\n\n" << setiosflags(ios::left);
cout << setprecision(2);
cout << "\n\t" << "Lapis
" << setw(12)
cout << "\n\t" << "Borracha " << setw(12)
cout << "\n\t" << "Canetas " << setw(12)
cout << "\n\t" << "Cadernos " << setw(12)
cout << "\n\t" << setfill('.') << "Fitas

<< lap;
<< bor;
<< can;
<< cad;
" << setw(12) << "TYE";

return 0;
}

Observao: Todos esses cabealhos usados oferecem recursos no ambiente de nomes std,
de modo que, para usar os nomes que eles oferecem, precisamos ou usar qualificao explcita com
std: : ou trazer os nomes para o ambiente de nomes global com
using namespace std;
Observao: quando a funo main( ) chamada, esta recebe dois argumentos especificando
o nmero de argumentos, usualmente chamado argc, e um array de argumentos, usualmente
chamado de argv. Os argumentos so strings de caracteres, de modo que o tipo de argv char*
[argc+1]. O nome do programa passado como argv[0], de modo que argc sempre no mnimo 1.
A lista de argumentos terminada por um zero; isto , argv[argc] = = 0.
Observao: Se o tamanho do campo especificado em setw for menor que o tamanho
mnimo necessrio para imprimir o valor associado, a impresso utilizar o nmero necessrio de
colunas, ignorando o tamanho do campo.
Outro exemplo do emprego destes manipuladores:
//
Exemplo do emprego de hex, dec e oct
#include <iostream>
int main(int argc, char* argv[])
{
int
n = 15;
cout << "\n" << "Hexadecimal \t" << hex << n;
cout << "\n" << "Decimal
\t" << dec << n;
cout << "\n" << "Octal
\t" << oct << n;
return 0;
}

13.4.2 A stream de entrada cin


A forma de entrar com dados em um programa C++ atravs do objeto cin. Tratra-se de um
fluxo associado entrada padro do computador (stdin, i.e, o teclado). A sintaxe de cin :
cin >> varivel;

onde
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
94

Curso de Linguagem Computacional C/C++

>> : o operador de extrao usado para direcionar a entrada de dados entrada padro
(teclado). Atravs do contexto, o compilador sabe que este operador no ser o operador para
deslocamento de bits mas sim o operador de leitura de dados.
varivel : o nome da varivel onde desejamos guardar os valores lidos.
Na tabela a seguir, apresentamos alguns exemplos da leitura de dados atravs de cin. Note
que em C++ no necessrio formatar o dado que est sendo lido. Cin faz isto automaticamente,
de acordo com a declarao da varivel.
Variveis

C++

int x;
cin >> x;
float f,g;
cin >> f >> g;
double dou; char ch; cin >> dou >> ch;

C
scanf(%d,&x);
scanf(%f %f, &f, &g);
scanf(%Lf %c, &dou, &ch);

O objeto cin faz com que o programa aguarde que voc digite o dado a ser adquirido e
pressione a tecla [ENTER] para finalizar a entrada. O operador >> pode apresentar-se diversas
vezes numa instruo com a finalidade de permitir a introduo de diversos valores ao mesmo
tempo. Mltiplas entradas so digitadas separadas por um espao em branco. O objeto cin entende
um espao em branco como trmino de uma entrada e o [ENTER] como finalizador geral.
Podemos ler nmeros em outras bases numricas, utilizando os manipuladores hex, dec e oct
apresentados anteriormente.
int n = 0;
cin >> hex >> n;

A biblioteca stream define outras funes para leitura e escrita de dados que no sero aqui
apresentadas. Todas as funes apresentadas na seco 3 podem ser aqui empregadas.

13.5 Funes
13.5.1 Valores Default Para Argumentos de uma Funo
C++ permite a definio de valores default para argumentos de funes. Isto significa que,
caso a chamada da funo omita algum parmetro, a funo pode usar o default previamente
definido. A forma de definir valores default explicit-los na declarao da funo, omitindo ou
no o nome das variveis. Uma vez definidos na declarao, os valores default no devem ser
repetidos na definio, pois o compilador reconhece nisto uma duplicidade de default. O exemplo a
seguir apresenta a declarao do default de uma funo e chamadas por ele viabilizadas:
unsigned int pares(int, int = 0);
int n1 = pares(20,3);
int n2 = pares(20);

// prottipo

Se o primeiro argumento foi omitido, todos os subsequentes devero ser omitidos. Se o


segundo argumento for omitido, todos os subsequentes devero ser omitidos e assim por diante.
Podemos escrever funes que tenham parmetros inicializados com um valor default e parmetros
no-inicializados, mas aps a primeira inicializao todos os parmetros seguintes devem ser
inicializados. Exemplo:
void linha( int n = 20, char ch, int cor);
// Declarao invlida
void linha(int n, char ch = *, int cor = 0); // Declarao vlida.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
95

Curso de Linguagem Computacional C/C++

13.5.2 Sobrecarga de Funes


Sobrecarregar funes significa criar uma famlia de funes com o mesmo nome, mas com
a lista de parmetros diferentes. Funes sobrecarregadas devem ter a lista de parmetros diferentes
ou em nmero ou em tipo. Quando a funo chamada, a lista de parmetros passada para ela que
permite ao sistema identificar qual o cdigo adequado. Por exemplo, podemos definir a famlia de
funes abaixo, lembrando que devemos definir cada funo como se fosse nica:
int cubo(int n);
float cubo(float n);
double cubo(double n);

13.5.3 Funes Inline


A palavra-chave inline, quando colocada como primeiro elemento do cabealho da definio
de uma funo, causa a insero de uma nova cpia da funo em todo lugar onde ela chamada.
inline

int cubo(int n);

A definio de uma funo inline deve preceder a primeira chamada a ela. Ou seja, se a
funo for chamada em main(), seu cdigo deve ser escrito antes de main(). Isto necessrio,
pois o compilador deve conhecer de antemo o cdigo da funo para poder inseri-la dentro do
programa.
Uma funo um cdigo presente uma nica vez no programa que pode ser executado
muitas vezes. Assim, um dos motivos para escrever funes o de poupar memria. Quando uma
funo pequena e queremos aumentar a velocidade de execuo de um programa, tranformamo-la
em inline.

13.5.4

Operador Unrio de Referncia: &

O operador de referncia cria outro nome para uma varivel j criada. As instrues:
int n;
int & n1 = n; // toda referncia deve ser inicializada

informam que n1 outro nome para n. Toda operao em qualquer dos nomes tem o mesmo
resultado. Uma referncia no uma cpia da varivel a quem se refere. a mesma varivel sob
nomes diferentes.
O uso mais importante para referncias ao passar argumentos para funes. Os exemplos
de argumentos de funes vistos at o momento so passados por valor ou por ponteiros.
Quando argumentos so passados por valor, a funo chamada cria novas variveis do
mesmo tipo dos argumentos e copia nelas o valor dos argumentos passados. Desta forma, a funo
no tem acesso s variveis originais da funo que chamou, portanto no as pode modificar.
A principal vantagem da passagem por referncia a de que a funo pode acessar as
variveis da funo que chamou. Alm desse benefcio, este mecanismo possibilita que uma funo
retorne mais de um valor para a funo que chama. Os valores a serem retornados so colocados em
referncias de variveis da funo chamadora.
A passagem por referncia possui as vantagens da passagem de parmetros por ponteiros,
i.e., acesso direto varivel fornecida como parmetro. No entanto, ponteiros exigem que tenhamos
cuidado ao manipular o endereo das variveis para no causar um erro fatal de acesso a memria.
Este tipo de preocupao j no existe com passagem por referncia, pois no lidamos com o
endereo da varivel mas sim com uma cpia do seu nome.
Funes que recebem argumentos por referncia utilizam o operador & somente na
definio do tipo do argumento e possuem chamadas idnticas a uma funo normal. Exemplo:
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
96

Curso de Linguagem Computacional C/C++

void reajusta( float& num, float& p =

15 ); // Prottipo

int main(int argc, char* argv[])


{
float preco = 10;
reajusta( preco, 5); // Chamada a funo
reajusta( preco);
// Chamada usando o argumento default
return 0;
}
void reajusta( float& num, float& p ) //Definio
{
num *= p;
}

13.6 Alocao Dinmica de Memria em C++


A alocao dinmica de memria em C++ feita com os operadores new (alocao) e
delete (liberao), anlogos s funes malloc() e free(). Em C++, o gerenciamento
dinmico de memria to relevante que as palavras new e delete foram incorporadas a
linguagem. A diferena bsica entre os operadores C++ e C est na confiabilidade e facilidade de
uso. Por exemplo, o tamanho do tipo para o qual se pede memria deve ser informado
malloc(), enquanto que new descobre esse tamanho automaticamente.
Declarao C:
Declarao C++
double *ptr;
prt = (double*)malloc(sizeof(double));

double *ptr;
ptr = new double;

C++ j fornece um ponteiro para o tipo de dado fornecido, no necessitando das converses
de tipo requeridas por malloc(). Outra vantagem que C++ define quanto de memria
necessrio, diminuindo o risco que o programador faa algum tipo de erro. Uma vantagem
importante que os operadores new e delete podem ser sobrecarregados (reimplementados) para
um tipo de dado criado pelo programador. Isto permite que o programador controle como ser
alocada memria para o seu tipo de dado.
Sempre que uma memria alocada para uma varivel no for mais necessria, devemos
liber-la utilizando o operador delete. As formas de utilizar o operador new (alocao de
memria) e delete (liberao de memria) so:
a) como operador ou funo
ptr_tipo = new tipo;
int * ptr1 = new int;
delete ptr1;

ptr_tipo = new(tipo);
int * ptr2 = new(int);
delete ptr2;

b) alocao e liberao de matrizes


ptr_tipo = new tipo[tamanho_matriz];
int * ptr3 = new int[10];
delete[] ptr3;
// ou, explicitamente:

delete[10] ptr3;

c) alocao e liberao de matrizes de ponteiros


ptr_ptr_tipo = new tipo * [tamanho_matriz];
int * * ptr4 = new int * [10];
delete[] ptr4;
// ou, explicitamente:
delete[10] ptr4;

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
97

Curso de Linguagem Computacional C/C++

Analogamente ao que ocorre a funo malloc() do C, o operador new retorna um


ponteiro nulo quando a memria disponvel insuficiente. Assim, devemos sempre verificar se a
alocao foi realizada com sucesso, ou seja, se o ponteiro contm um endereo diferente de zero.

13.7 Exerccios
13.1 Escreva um programa que desenhe na tela o grfico da funo y = cos(x) + x/2. Utilize
cout e cin para isto. Desenhe todos os elementos do grfico: ttulo, legenda, linhas horizontal e
vertical e numerao. Marque os pontos pertencentes ao grfico com o caracter (*).
13.2 Crie um programa para fazer cadastro de doentes em um hospital. Utilize estruturas e
funes, com passagem de parmetros por referncia. O programa deve apenas adquirir os dados e
quando o usurio terminar o cadastro, o programa deve imprimir na tela todas as fichas feitas.
13.3 Modifique o programa acima para utilizar agora a alocao dinmica em C++ e
organize agora as fichas por ordem alfabtica do nome do paciente.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
98

Curso de Linguagem Computacional C/C++

14 Classes e Objetos em C++


No captulo anterior comeamos a apresentar a idia da Orientao a Objetos em C++.
Agora vamos comear a explicar o que so classes e objetos.
Suponha que estamos criando um programa de computador que jogue xadrez contra o
usurio. Primeiramente, como no problema do arquiteto, temos um ambiente a modelar (no caso o
jogo de xadrez) e vamos utilizar os componentes deste ambiente para descrev-lo. Analisando-se
rapidamente um jogo de xadrez, apontamos vrios elementos que devem ser modelados.
Podemos modelar o tabuleiro definindo as suas dimenses, quantas posies livres existem,
a cor do tabuleiro, definir mtodos para desenhar este tabuleiro na tela e mtodos para controlar as
posies das peas no tabuleiro.
Podemos em seguida modelar todas as peas do jogo de xadrez. Cada uma destas peas ser
um objeto do nosso programa. Para cada pea, i.e. cada objeto pea, devemos definir algumas
propriedades desta como tipo (peo, rei, rainha, torre, bispo e cavalo), de que time pertence (se
pertence ao time do computador ou ao time do usurio), a cor desta pea e o seu desenho
geomtrico. Alguns mtodos tambm so necessrios como definir a maneira como esta pea pode
ser movimentada no tabuleiro, a posio inicial desta pea no tabuleiro, como esta pea pode ser
desenhada na tela, etc.
Aqui j fica bem clara a idia do que sejam os objetos no jogo. O tabuleiro e cada uma de
suas peas sero objetos no nosso programa. Desta forma, podemos modelar cada elemento isolado,
permitindo assim uma boa estrutura para o programa e capacidade de reutilizao.
Mas o que vem a ser as classes do nosso programa? Classes definem tipos de objetos.
Quando modelamos as peas do tipo peo, percebemos que temos vrios elementos no nosso
ambiente com estas caractersiticas, i.e., temos mltiplas instncias do objeto peo. Ento,
definimos uma classe chamada peo e definimos nesta classe todos as propriedades e mtodos para
o elemento peo. Adicionamos um ndice para podermos referenciar cada elemento peo
isoladamente. Assim, definida a classe peo, podemos criar quantas instncias (objetos) desta classe
desejarmos. Todo objeto deve ser modelo a partir da definio da classe que o representa. Desta
forma, temos que definir as classes para as demais peas do xadrex como o rei e a rainha.
Entretanto, podamos ter criado somente uma classe entitulada: peas do xadrez. Desta
forma no teremos uma classe para cada tipo de pea do xadrez mas uma classe que representa
todos os tipos de peas de xadrez. Definir esta classe ser uma atividade muito mais complexa e
insegura (no sentido de poder gerar erros) que definir cada tipo de pea isoladamente. Por
exemplo, nesta classe a dimenso da pea de xadrez e o mtodo com que esta deve ser
movimentada no tabuleiro vo ser diferentes para cada tipo de pea (peo, torre, bispo, ...). Isto nos
leva a ter definies complexas para as atributos e mtodos desta classe.
Devemos utilizar a primeira representao ou a segunda? Bom, depende do nvel de
abstrao que desejamos (nvel de detalhamento). Se o programador achar mais fcil tratar somente
um tipo genrico de pea de xadrez, no h motivos para refinar este modelo. Se o programador
desejar ter um controle diferenciado para cada tipo das peas, ento melhor refinar o modelo e
criar uma classe para cada tipo. O bom senso que define o quanto voc deve ou no refinar um
modelo, tome cuidado para no criar classes desnecessrias.
Voc pode estar achando que terminamos, ou seja, que o jogo de xadrez j est modelado
definindo-se o tabuleiro e as peas. Esta seria uma intuio normal, pois estes so os elementos que
vemos quando jogamos xadrez. Mas no podemos esquecer de definir alguns elementos abstratos
que esto inseridos no modelo. O primeiro o prprio jogador. Ns queremos que o computador
jogue contra o usurio, ento devemos ter que modelar o jogador, definindo as suas propriedades
como a cor da suas peas e os seus mtodos, que aqui incluem as suas estratgias de jogo. Outro
elemento necessrio uma espcie de juiz, que controlar as regras do jogo, saber quando a vez
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
99

Curso de Linguagem Computacional C/C++

do usurio ou do programadador, isto , devemos definir uma classe que controlar a execuo do
programa. Por fim, devemos ainda definir alguns elementos necessrios para a interface do
programa, como uma janela na tela onde desenharemos o tabuleiro, o mouse para que o usurio
possa mexer as suas peas e todos os demais elementos necessrios.
Para cada um destes elementos, deveremos definir as propriedades e mtodos que segundo
esta nossa aplicao podem modelar corretamente o nosso ambiente. Quando criamos as classes de
objetos, tambm definimos as relaes entre eles. Descrevendo os componentes do ambiente e a
relao entre eles, j teremos ento uma representao similar deste.
Neste captulo seguimos apresentando a sintaxe para defino de classes de objetos em C++.

14.1 Tipo Classe e o Encapsulamento de Dados


A idia fundamental de linguagens orientadas a objetos a possibilidade de combinar num
nico registro campos que contero dados e campos que so funes para operar os campos de
dados do registro. Uma unidade assim chamada classe.
Uma instncia (varivel) de uma classe chamada objeto e conter campos de dados e
funes. Definir uma classe no cria nenhum objeto, do mesmo modo que a existncia do tipo int
no cria nenhuma varivel inteira.
As funes de um objeto so chamadas funes-membro ou mtodos e, de modo geral, so o
nico meio de acesso aos campos de dados tambm chamados de variveis de instncia.
Se o programa necessita atribuir um valor a alguma varivel de instncia, deve chamar uma
funo-membro que recebe o valor como argumento e faz a alterao. Devemos evitar o acesso a
variveis de instncia diretamente.
Desta forma, os campos de dados estaro escondidos para ns, o que previne alteraes
acidentais ou invlidas. Dizemos ento que os campos de dados e suas funes esto encapsulados
(de cpsula) numa nica entidade. As palavras encapsular e esconder so termos tcnicos da
definio de linguagens orientadas a objetos.
O conceito de esconder dados significa que eles estaro confinados dentro da classe e no
podero ser alterados, por descuido, por funes que no perteam a classe.
Se alguma modificao ocorrer em variveis de instncia de um certo objeto, sabemos
exatamente quais funes interagiram com elas: so as funes-membro do objeto. Nenhuma outra
funo pode acessar esses dados. Isso simplifica a escrita, manuteno e alterao do programa. Um
programa em C++ consiste em um conjunto de objetos que se comunicam por meio de chamadas s
funes-membro.

14.2 Definindo Classes


Vamos comear com um exemplo que mostra os elementos bsicos na definio de classes e
criao de objetos. O exemplo cria uma classe para representar um retngulo.
// Exemplo de uma classe
#include <iostream>
using namespace std;
class Retangulo // Define a classe
{
private:
int bas, alt;
// atributos privados
public:
static int n;
// atributos publicos
// Construtores e Destrutores
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
100

Curso de Linguagem Computacional C/C++

Retangulo()

{ bas=0; alt=0; n++; }

Retangulo(int a, int b=0);


{ n--; }

~Retangulo()
// metodos da classe
void Init(int b, int h)

{ bas = b; alt = h; }

void PrintData();
};
Retangulo::Retangulo(int a, int b)
{
bas = a;
alt = b;
n++;
}
void Retangulo::PrintData() // Define funcao membro
{
cout << "\nBase = " << bas << " Altura = " << alt;
cout << "\nArea = " << (bas*alt);
}
// incializacao da variavel statica
int Retangulo::n = 0;
int main(int argc, char* argv[])
{
Retangulo X(2,3);
Retangulo Y[5]; // Declaracao de objetos
Retangulo C[2] = { Retangulo(2,3), Retangulo(5,1) };
Y[0].Init( 5, 3);

// Chama funcao membro de inicializacao

X.PrintData();
// Chama funcao membro
Y[1].PrintData();
(C + 1)->PrintData();
cout << "\n Quantidade de Objetos : " << C[1].n;
return 0;
}

A classe Retngulo possui trs atributos e 5 funes. Agrupar dados e funes numa mesma
entidade o fundamento da programao orientada a objetos.
A primeira tarefa na orientao a objetos definir as classes. Uma definio de classe
sempre comea pela palavra-chave class seguida do nome da classe (Retangulo, neste exemplo),
de seu corpo delimitado por chaves e finalizado com um ponto-e-vrgula.

14.3 Membros Privados e Pblicos


O corpo da definio da nossa classe contm as palavras private e public seguidas de doispontos. Elas especificam a visibilidade dos membros.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
101

Curso de Linguagem Computacional C/C++

Os membros definidos aps private: so chamados de parte privada da classe e podem


ser acessados pela classe inteira, mas no fora dela. Um membro privado no pode ser acessado por
meio de um objeto. Este conceito equivalente relao existente entre uma funo e as suas
variveis locais (auto), elas no so visveis fora da funo. Geralmente, na parte privada da classe
so colocados os membros que contero dados. No entanto, pode-se colocar tambm funes que s
podero ser chamadas por outras funes da prpria classe. Dizemos ento que esses dados e
funes estaro escondidos.
A seco pblica da classe formada pelos membros definidos aps public: e pode ser
acessada por qualquer funo-membro e por qualquer outra funo do programa onde um objeto foi
declarado. Os membros pblicos fazem a interface entre o programador e a classe. Geralmente, na
parte pblica de uma classe so colocadas as funes que iro operar os dados. Podemos, entretanto,
colocar dados na parte pblica da classe, entretanto estes dados podero ser acessados diretamente
pelos objetos desta classe. Ento, no poderemos controlar o acesso a este dado da classe.
No exemplo acima, os dados bas e alt tm acesso privado, enquanto que o dado n e todas
as funes tm acesso pblico.

14.4 Funes-Membro
Funes-membro, tambm chamadas mtodos, so as que esto dentro da classe. Na classe
Retangulo, definimos 5 funes-membro: Retangulo(), Retangulo(int, int),
~Retangulo(), Init(int, int) e PrintData().
Estas funes executam operaes comuns em classes: atribuem valores aos dados e
imprimem certos resultados.
Observe que a funo Init(int, int) recebe como parmetro dois nmeros inteiros e
tm seu cdigo definido dentro da definio da classe. Funes-membro de cdigo definido dentro
da classe so criadas como inline por default, tornando a execuo desta mais rpida mas
ocupando um espao maior de memria para armazenar o programa.
Podemos, entretanto, definir funes-membro em algum lugar do programa fora da classe,
contanto que o seu prottipo seja escrito dentro do corpo da definio da classe. Isto informa ao
compilador que elas fazem parte da classe, mas foram definidas fora dela.
No nosso exemplo, definimos a funo PrintData() fora da classe. Observe que na
definio destas funes membro, o nome da funo precedido pelo nome da classe (no caso:
Retangulo) e por um smbolo formado por dois caracteres de dois-pontos (::). Este smbolo
chamado operador de resoluo de escopo. Este operador o meio pelo qual informamos ao
compilador que a funo que est sendo definida est associada quela classe particular. No nosso
exemplo, o operador de resoluo escopo informa que a funo PrintData() membro da
classe Retangulo. Sendo assim, a definio completa fica:
void Retangulo::PrintData() // Define funcao membro
{
cout << "\nBase = " << bas << " Altura = " << alt;
cout << "\nArea = " << (bas*alt);
}

14.5 Construtores & Destrutores


Muitas vezes conveniente inicializar um objeto (instncia da classe) quando ele criado,
sem necessidade de efetuar uma chamada funo-membro para que os dados sejam inicializados.
A inicializao automtica de um objeto efetuada por meio da chamada a uma funo-membro
especial quando o objeto criado. Esta funo-membro conhecida como construtor.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
102

Curso de Linguagem Computacional C/C++

Um construtor uma funo-membro que tem o mesmo nome da classe e executada


automaticamente toda vez que um objeto criado. Quando um objeto da classe Retangulo
criado, chama-se automaticamente o construtor da classe para inicializar os dados desta.
Observe que um construtor no deve retornar valor nenhum. O motivo ele ser chamado
diretamente pelo sistema e portanto no h como recuperar um valor de retorno. Por isso, que
declaramos um construtor, sem nenhum tipo, nas instrues :
Retangulo() { bas=0; alt=0; n++; }
Retangulo(int a, int b=0);

No nosso exemplo, o construtor Retangulo() foi definido dentro da classe enquanto que
o construtor Retangulo(int, int) foi definido fora desta, ficando claro na definio que um
construtor no retorna nenhum tipo de dado.
Um construtor pode perfeitamente chamar uma funo-membro. O seu cdigo igual ao de
qualquer outra funo, exceto pela falta de tipo.
Podemos sobrecarregar construtores para podermos criar objetos de forma diferenciada. No
nosso exemplo fica clara esta aplicao. Podemos utilizar o construtor Retangulo() para
inicializar os objetos com dados default, ou utilizar o construtor Retangulo(int, int) para
explicitamente fornecer os valores iniciais para os dados da classe. Note que este segundo
construtor faz uso de valores default para os parmetros, permitindo assim que o usurio precise
fornecer somente o primeiro parmetro. O compilador decide qual construtor chamar de acordo com
os parmetros passados.
O construtor Retangulo() tem uma importncia imensa em C++, chamado de
construtor default. Sempre que um objeto for criado, se nenhum outro construtor puder se utilizado
(nenhum dado pode ser fornecido), ento com certeza o construtor default ser utilizado. Por
exemplo, quando criamos uma matriz de objetos de uma classe. No interessante termos que
inicializar cada objeto individualmente. Por isso, o programa utiliza o construtor default para criar
todos os objetos juntos e inicilizar todos com este construtor. Desta forma, podemos sempre garantir
uma inicializao dos dados com o construtror default.
Outro elemento importante o construtor de cpia, utilizado para iniciar um objeto como
sendo uma cpia fiel de um objeto j existente. Este operador, pode ser definido passando-se como
parmetro do construtor o objeto que desejamos copiar. Aplicando no nosso exemplo, teramos:
Retangulo(Retangulo Ret);

Uma funo destrutora chamada automaticamente toda vez que um objeto destrudo
(liberado da memria) e tem o mesmo nome da classe precedido de um til (~):
~Retangulo()

{ n--; }

Da mesma forma que um construtor, os destrutores no podem ter valor de retorno. O


destrutor tambm no pode receber argumentos (por isso, cada classe possui somente um
construtor) nem pode ser chamado explicitamente pelo programador.

14.6 Criando Objetos


Aps a definio da classe Retangulo, podemos declarar uma ou mais instncias desse
tipo. Uma instncia de uma classe chamada objeto, como j mencionamos anteriormente.
No nosso exemplo, criamos objetos da classe Retangulo atravs das instrues:
Retangulo X(2,3);
Retangulo Y[5]; // Declaracao de objetos
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
103

Curso de Linguagem Computacional C/C++

Retangulo C[2] = { Retangulo(2,3), Retangulo(5,1) };

A primeira instruo cria um objeto da classe Retangulo chamado X, inicializando-o


como o construtor Retangulo(int, int).
A segunda instruo cria uma matriz unidimensional de objetos da classe Retangulo.
Neste caso, o construtor default empregado para a inicializao dos objetos.
A terceira instruo cria uma matriz unidmensional de objetos da classe Retangulo. A
matriz inicializada com um conjunto de objetos Retangulo. Note que a inicializao de
matrizes de objetos mantm o formato anterior, ou seja, elementos delimitados por chaves,
separados por vrgulas e o fim da instruo definido pelo (;) ponto-e-vrgula.
Observe que a definio da classe no cria nenhum objeto, somente o descreve. Este
conceito idntico ao das estruturas que, quando definidas, no criam nenhuma varivel. Declarar
um objeto similar a declarar uma varivel de qualquer tipo; o espao de memria reservado.

14.7 Atributos do Tipo: Static


Cada objeto de uma classe possui a sua prpria cpia dos dados da classe. Entretanto, muitas
vezes desejamos que todos os objetos de uma classe tenham acesso um mesmo item de dado. Este
item faria o mesmo papel de uma varivel externa, porm ser visvel somente a todos os objetos
daquela classe.
Quando um dado membro declarado como static, criado um nico item para a classe
como um todo, no importando o nmero de objetos declarados. Isto significa que o programa
alocou somente um espao de memria onde todos os objetos desta classe iro acessar este dado. A
informao de um membro static compartilhada por todos os objetos da mesma classe.
Um membro static definido com um atributo qualquer da classe, tendo a mesma
visibilidade de um membro normal da classe. Abaixo, mostramos a declarao de um membro static
com visibilidade pblica da classe Retangulo.
static int n;

Dados static devem ser obrigatoriamente redefinidos fora da definio da classe. Voc pode
considerar que a definio de um atributo da classe como static, simplesmente notifica o compilador
que existe uma varivel global (extern) que ser utilizada por todos os objetos desta classe para
armazenar este atributo. A declarao desta varivel fora da classe que ir realmente criar esta
varivel, alocando memria para esta. Esta declarao feita em qualquer lugar fora da classe, da
seguinte forma:
int Retangulo::n = 0;

Note que a palavra chave static no foi empregada e que utilizamos Retangulo:: para
indicar que n pertence classe Retangulo, ou seja, s pode ser acessado atravs desta classe.
Nesta declarao, podemos efetuar a inicializao desta varivel, como apresentado acima.
Este tipo de varivel pode ser bem til. No programa exemplo, utilizamo-la para contar o
nmero de objetos criados. Note que cada vez que criamos um objeto, chamamos o seu construtor
que incrementar automaticamente n. Se destruirmos um objeto, chamamos o seu destrutor que
decrementar n. Desta forma, n conta automaticamente o nmero de objetos existentes de uma certa
classe.
Observao: um dado do tipo static no pode ser inicializado no construtor de uma classe
pois, se no, toda vez que criarmos um objeto desta classe, estaremos reinicializando o valor desta
varivel static para todos os demais objetos.
Funes podem ser definidas como static. Funes static tm caractersticas similares s
variveis static. So utilizadas para implementar recursos comuns a todos os objetos da classe.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
104

Curso de Linguagem Computacional C/C++

Funes-membro static agem independentemente de qualquer objeto declarado.


Conseqentemente, estas funes no podem acessar nenhum membro no-static da classe. Funes
membro static acessam somente membros static de classe. Funes static podem ser chamadas
usando a mesma sintaxe utilizada para acessar dados static.
class moeda
{
private:
static float US;
public:
static void usvalor()
{
cout << \nDigite o valor do dlar: ;
cin >> US;
}
};
moeda::usvalor();

14.8 Acessando Funes e Dados Pblicos


Os membros pblicos de um objeto so acessados por meio do operador ponto. A sintaxe
similar quela de acesso aos membros de estrutura.
As funes-membro s podem ser chamadas quando associadas ao objeto especfico pelo
operador ponto. Uma funo-membro age sobre um objeto particular e no sobre a classe como um
todo. Nosso programa fornece alguns exemplos deste tipo de acesso:
Primeiro, acessando a funo Init(int, int) do primeiro objeto da matriz Y:
Y[0].Init( 5, 3);

// Chama funcao membro de inicializacao

Aqui, acessando a funo PrintData():


X.PrintData();
Y[1].PrintData();

// Chama funcao membro

Note que podemos utilizar este operador para acessar dados pblicos:
cout << "\n Quantidade de Objetos : " << C[1].n;

Como n uma varivel global (static) associada classe Retangulo, podemos acessar
este dado sem associ-lo a nenhum objeto ou at mesmo, sem nunca ter criado um objeto desta
classe. Ao definir esta varivel fora da classe, nos j alocamos memria para que ela fosse
inicializada. Para acess-la, basta utilizar o operador (::) para referenciar a classe associada a esta
varivel. Portanto, no caso de variveis static, ambas instrues abaixo so equivalentes:
C[1].n

==

Retangulo::n

O operador (->) pode ser utilizado quando temos um ponteiro para um objeto e queremos
acessar um membro (dado ou funo) pblico desta classe. No nosso exemplo, empregamos este
operador na instruo abaixo:
(C + 1)->PrintData();

14.9 Objetos Const


O qualificador const na declarao de um objeto indica que o objeto uma constante e
nenhum de seus membros de dados podem ser alterados. Por exemplo, a instruo abaixo cria X
como um objeto constante, ou seja, os dados de X no podem ser alterados em tempo de execuo:
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
105

Curso de Linguagem Computacional C/C++

const Retangulo X(2,3);

Quando um objeto constante declarado, o compilador probe a ele o acesso a qualquer


funo membro, pois no consegue identificar quais funes alteram os seus dados. Entretanto, h
um modo de informar ao compilador que uma funo-membro no altera nenhum dado do objeto e
que poderemos cham-la por meio de um objeto constante.
Ao colocar a palavra const aps os parnteses que envolvem a lista de parmetros da
funo, estaremos indicando que a funo no modifica o objeto. A palavra const deve ser
adicionada tanto no prottipo da funo quanto na sua declaraao. Desta forma possvel acess-la
a partir de um objeto const.
Por exemplo, vamos transformar a funo PrintData() em const, para podermos utilizla junto com o objeto X:
class Retangulo
{
void PrintData() const;
};
void Retangulo::PrintData() const // Define funcao membro
{
cout << "\nBase = " << bas << " Altura = " << alt;
cout << "\nArea = " << (bas*alt);
}

14.10

Tipo Objeto

Objetos de classes podem ser usados normalmente como qualquer outro tipo de dado. Por
isso podemos utiliz-los para definir matrizes de objetos ou para passar como parmetro, da mesma
forma que fazemos com outros tipos de dados.
As funes membro so criadas e colocadas na memria somente uma vez para a classe
toda. As funes membro so compartilhadas por todos os objetos da classe. J para os dados, a
cada objeto que declarado, uma nova regio na memria alocada de forma que cada objeto
possui o seu conjunto de dados.

14.11

Exerccios

14.1 Crie um programa para calcular as mdias das notas dos alunos de uma turma. Crie
uma classe aluno e modele cada aluno com o seu conjunto de notas como sendo um objeto. Imprima
na tela usando cout.
14.2 Usando a idia da lista ligada apresentada captulo de estruturas, crie um programa para
representar restaurantes empregando uma lista ligada construda com classes.
14.3 Crie um programa que faa o controle de cadastro de usurios e controle de alocao
para uma locadora de fitas de vdeo. Utilize uma classe para os clientes e outra para as fitas, e
emprege o mtodo da lista ligada para gerenciar um vetor dinmico. O usurio deve poder
incluir/retirar um cliente ou uma fita, fazer uma pesquisa, pedir a lista de clientes e a lista de fitas ou
alterar algum parmetro destas.
14.4 Escreva um programa para controlar o acesso das vagas de um estacionamento.
Armazene dados importantes do carro como chapa do carro, a hora de entrada, a hora de sada.
Controle a lotao do estacionamento e verifique se existem vagas disponveis. O programa deve
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
106

Curso de Linguagem Computacional C/C++

gerar automaticamente o preo do estacionamento, quando o usurio retirar o carro. No esquea


que alguns clientes podem ficar mais tempo do que o tempo notificado.
14.5 Modele o problema do jogo do xadrex apresentado no incio do captulo. Mas no
jogue contra o computador mas contra um outro usurio usando o mesmo micro.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
107

Curso de Linguagem Computacional C/C++

15 Sobrecarga de Operadores
O sentido do polimorfismo o de um nico nome para definir vrias formas distintas. Em
C++, chamamos de polimorfismo a criao de uma famlia de funes que compartilham do mesmo
nome, mas cada uma tem cdigo independente. O resultado da ao de cada uma das funes da
famlia o mesmo. A maneira de atingir esse resultado distinta.
Como exemplo, suponhamos que desejamos calcular o salrio lquido de todos os
funcionrios de uma empresa. Nessa empresa, h horistas, mensalistas, os que ganham por
comisso, etc. Criamos um conjunto de funes em que cada uma tem um mtodo diferente de
calcular o salrio. Quando a funo chamada, C++ saber identificar qual a funo com o cdigo
adequado ao contexto.
A sobrecarga um tipo particular de polimorfismo. Como exemplo, tomemos operador
aritmtico (+). Em C++, usamos esse operador para somar nmeros inteiros ou para somar nmeros
reais:
5 + 4
3.7 + 12.5

O computador executa operaes completamente diferentes para somar nmeros inteiros e


nmeros reais. A utilizao de um mesmo smbolo para a execuo de operaes distintas
chamada sobrecarga. O polimorfismo e a sobrecarga so habilidades nicas em linguagens
orientadas a objetos.
Os operadores em C++ so definidos como funes normais onde o nome da funo o
smbolo do operador e os parmetros da funo so os operandos do operador. Por exemplo, o
operador de soma para nmeros inteiros possui uma declarao do tipo:
int operator +(int a, int b);

Ou seja, a operao (a+b), vista por C++ como uma chamada funo acima declarada.
Quando escrevermos em nosso cdigo esta operao, C++ utilizar a definio desta funo para
efetuar a operao. Note que a nica diferena na declarao ou definio de um operador que o
nome de um operador definido pela palavra chave operator seguida de espao mais o smbolo
que representa o operador, neste caso (+).
Assim, podemos tratar qualquer operador como sendo uma funo normal mas que possui
um nome especial e uma forma especial de chamada. Perceba, que quando escrevemos no cdigo
(a+b), C++ interpreta esta instruo como uma chamada a funo operator + e passa para esta os
parmetros a e b.
Se os operadores so tratados por C++ como uma funo qualquer, qual a razo da sua
existncia? Suponha, que tenhamos definido a seguinte funo que executa a operao (a + b) :
int soma(int a, int b);

Qual das duas formas abaixo mais clara e intuitiva para se escrever a soma de dois
nmeros:
int c = soma( a, b);
int c = a + b;
claro que ser segunda forma. Por isso, podemos tornar o nosso cdigo fonte muito mais
organizado e claro empregando-se os operadores ao invs de funes normais.
Assim como qualquer outra funo em C++, os operadores podem ser sobrecarregados para
outras aplicaes, i.e., podemos redefinir os operadores para serem empregados em outros tipos de
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
108

Curso de Linguagem Computacional C/C++

dados criados pelo programador. Suponha que tenhamos criado uma classe para representar os
nmeros complexos chamada complexo. Ento, com a sobrecarga do operador (+) poderemos
redefinir a seguinte funo para dois elementos da nossa classe:
complexo A, B;
A = A + B;

Note, que esta definio bem intuitiva e clara. Esta caracterstica muito importante para o
programador, permitindo que este possa definir como os operadores existentes em C++ atuaro com
relao aos tipos de dados definidos pelo programador.
Somente os operadores j existentes em C++ podem ser sobrecarregados (redefinidos) para
operar sobre novos tipos de dados definidos pelo programador. Por exemplo, no podemos definir o
smbolo (#) como um operador, pois este smbolo no declarado por C++ como sendo um
operador.
Sobrecarregar um operador significa redefinir o seu smbolo, de maneira que ele se aplique
tambm a tipos de dados definidos pelo usurio como classes e estruturas. Sobrecarregar uma
funo significa utilizar um mesmo nome para tarefas parecidas, mas de cdigos de programa
diferentes. Vrias funes com o mesmo nome podem apresentar diferentes implementaes
(trechos de programa). No instante em que voc encontrar uma limitao pelo modo como os
operadores C++ trabalham, pode mud-los conforme as suas necessidades, por meio de sobrecargas.

15.1 A Sobrecarga como uma Funo Global


A implementao de sobrecargas de operadores definida por meio de funes chamadas
operadoras. Estas funes podem ser criadas como membros de classes ou como funes globais,
acessveis a todo o programa.
A seguir vamos apresentar a sobrecarga do operador ++() incremento prefixado para a
classe Ponto, criada para representar um ponto localizado no espao bidimensional, por isso contm
as coordenadas x e y do ponto.
//Ponto2 - Mostra a sobrecarga de operadores
#include <iostream>
using namespace std;
class Ponto
{
public:
int X, Y;
Ponto(int aX = 0, int aY = 0)
{ X = aX; Y = aY; }
void PrintPt() const {cout << '(' << X << ','<< Y <<')';}
};
Ponto operator ++(Ponto ObjPonto) //incremento prefixado
{
++ObjPonto.X; ++ObjPonto.Y;
return ObjPonto;
}
int main(int argc, char* argv[])
{
Ponto P1(1,2);
cout << "\n p1 = ";
P1.PrintPt();
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
109

Curso de Linguagem Computacional C/C++

cout << "\n++p1 = ";


(++P1).PrintPt();
return 0;
}

A classe Ponto uma classe normal, possui dois atributos com acesso pblico, uma funo
construtora para incializar os atributos e uma funo para imprimir os dados na tela.
Sobrecarregamos o operador ++() para incrementar os dados contidos em um objeto desta
classe. Aps a declarao da classe, segue a declarao do operador. Note que o operador
declarado como qualquer funo global, a nica diferena a palavra-chave operator na frente
do smbolo ++. O operador recebe como parmetro um objeto da classe Ponto e retorna tambm um
objeto desta classe. O operador recebe somente um parmetro, pois no caso, este um operador
unrio e, por definio, s pode receber um nico parmetro. O operador acessa os dados pblicos
da classe Ponto e incrementa cada um deles, retornando o prprio objeto passado como parmetro
com o resultado da operao.
Em seguida, empregamos o novo operador incrementando o objeto P1 e imprimindo na tela
o resultado gerado por este operador.

15.2 Limitaes e Caractersticas


A sobrecarga de operadores permite uma nova implementao de maneira como um
operador funciona. Entretanto, necessrio respeitar a definio original do operador. Por exemplo,
no possvel mudar um operador binrio (que trabalha com dois operandos) para criar um
operador unrio (que trabalha com um nico operando).
No permitido tambm estender a linguagem inventando nossos operadores representados
com smbolos novos. Por exemplo, no se pode inventar uma operao usando o smbolo ##. Este
smbolo no um operador vlido em C++ e voc no poder torn-lo um operador. Devemos
limitar-nos aos operadores j existentes.
A definio de operadores deve obedecer precedncia original do operador. Por exemplo,
o operador de multiplicao (*) tem precedncia sobre o de adio (+). No possvel modificar
a precedncia de operadores por meio de sobrecargas.
Nem todos os operadores podem ser sobrecarregados. Os seguintes operadores no podem
ser sobrecarregados: o operador ponto de acesso a membros e o operador condicional ternrio
(?:).
Os operadores unrios operam sobre um nico operando. Exemplos de operadores unrios
so o de incremento (++), decremento (--) e menos unrio (-). Por outro lado; os operadores
binrios operam sobre dois operandos (+, -, *, /, >, +=, etc...). Por causa desta diferena, uma
ateno especial deve ser dada ao uso de cada tipo.
Quando definimos um operador como sendo uma funo-membro de uma classe, o primeiro
parmetro passado para a funo operadora ser considerado automaticamente como sendo um
objeto desta classe. Declarar um operador como sendo membro de uma classe, permite que este
tenha acesso a todos os dados desta classe, tenha as permies de acesso como qualquer outra
funo membro e possa desfrutar das vantagens fornecidas pela herana de classes, apresentadas no
prximo captulo.
Na declarao de operadores como funes globais, os operadores unrios recebero um
nico parmetro enquanto que os operadores binrios recebero dois parmetros. J na declarao
de operadores como funes-membro de uma dada classe, j que o primeiro operando sempre um
objeto da classe, os operadores binrios no recebero parmetros enquanto que os operadores
binrios recebero um nico parmetro.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
110

Curso de Linguagem Computacional C/C++

Uma funo operadora deve ter definido um tipo de retorno, para que o resultado da
operao com este tipo possa ser atribuidos a outras variveis. Por exemplo, ao definir o operador
(a+b), temos que definir que esta operao retorna algum valor do tipo da varivel c, para pode
executar a seguinte instruo:
c = a + b;

15.3 Sobrecarga de Operadores como Funo-Membro


No exemplo anterior, apresentamos a declarao do operador de incremento pr-fixado
redefinido globamente. Vamos agora, redefinir este operador com uma funo-membro da classe
Ponto.
#include <iostream>
using namespace std;
class Ponto
{
private:
int X, Y;
public:
Ponto(int aX = 0, int aY = 0)
{ X = aX; Y = aY; }
void PrintPt() const {cout << '(' << X << ','<< Y <<')';}
Ponto operator ++() //incremento prefixado
{
++X; ++Y;
Ponto Temp(X,Y);
return Temp;
}
};
int main(int argc, char* argv[])
{
Ponto P1, P2(2,3);
cout << "\n p1 = ";
P1.PrintPt();
cout << "\n++p1 = ";
(++P1).PrintPt();
cout << "\n++p2 = ";
(++P2).PrintPt();
P2 = ++P1;
cout << "\n p2 = ";
P2.PrintPt();
Return 0;
}

Neste exemplo, efetuamos algumas modificaes importantes. Os dados da classe Ponto,


passaram a ter acesso privado, no podendo mais ser acessados por nenhuma funo global.
Sobrecarregamos o operador incremento prefixado como sendo uma funo-membro da
classe Ponto, note que agora esta funo no recebe nenhum parmetro. A definio da funo
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
111

Curso de Linguagem Computacional C/C++

praticamente igual a anterior, retirando-se o parmetro. Esta funo uma funo inline da classe
Ponto, por esta definida dentro da definio da classe. A funo operadora ++() agora cria um
objeto temporrio da classe Ponto para conter o resultado da operao a ser utilizado como retorno
da funo. Veremos a seguir, formas diferentes de retornar o resultado de uma funo operadora.
Por fim, nada foi modificado no emprego do operador sobrecarregado. Note na funo
main(), que o emprego do operador no sofreu nenhuma modificao pelo fato deste ser
declarado como uma funo global ou uma funo membro.

15.4 Estudo de Casos


Agora apresentaremos a sobrecarga de um grupo importante de operadores em C++ que
serviro como exemplo para a sobrecarga de qualquer outro operador existente. Com este exemplo,
discutiremos outros aspectos da sobrecarga e voc perceber tambm a utilizade desta ferramenta.
O primeiro exemplo cria uma classe para armazenar as notas dos alunos. A sobrecarga de
dois operadores foi efetuada. C++ no faz a checagem de limites de matrizes. Por causa disto, a
manipulao de matrizes em C++ apresenta vrias falhas e permite erros acidentais de sobreposio
de dados de memria se forem usados ndices que ultrapassam o limite de dimenso da matriz. Por
isso, efetuamos a sobrecarga do operador [] para testar o limite da matriz. O outro operador,
converter um objeto da classe Matriz para um ponteiro float. Isto torna os objetos desta classe mais
genricos, podendo ser empregados facilmente para outras aplicaes.
//Notas : Sobrecarga do operador []
#include <iostream>
#include <iomanip>
using namespace std;
const MAX = 50;
class Matriz
{
private:
float n[MAX];
public:
Matriz();
float & operator [](int i); // sobrecarga []
float Media(int i);
operator float *() const // Funcao Conversora
{ return (float *)n; }
};
Matriz::Matriz()
{
for(int i = 0; i<MAX; i++)
n[i] = 0.0;
}
float & Matriz::operator [](int i)
{
static float x = -1;
if(i >= 0 && i < MAX)
return n[i];
else
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
112

Curso de Linguagem Computacional C/C++

{
cout << "\nFora de Limite!";
return x;
}
}
float Matriz::Media(int i)
{
float m = 0.0;
for(int j = 0; j < i; j++)
m += n[j];
return m/float(i);
}
int main(int argc, char* argv[])
{
Matriz Notas;
cout << setprecision(2);
int i = 0;
do
{
cout << "Digite a nota do aluno " << (i + 1) << " : ";
cin >> Notas[i];
}while (Notas[i++] >= 0);
i--;
float * Temp = Notas;
cout << "\nNota do Segundo Aluno " << *(Temp + 1);
cout << "\n\nMedia das notas : " << Notas.Media(i);
return 0;
}

O programa cria uma matriz fixa para armazenar as notas dos alunos, imprimindo a mdia
das notas no final. A novidade a funo operator[] que checa se o ndice especificado est
dentro do limite de dimensionamento da matriz. Se estiver, a funo retorna uma referncia ao
elemento correspondente da matriz privada. Se no estiver, a funo imprime uma mensagem de
erro e retorna uma referncia a uma varivel static float com valor 1. Isto previne a
sobreposio de outras regies da memria caso o limite da matriz seja ultrapassado.
A funo operator [] sobrecarrega o operador binrio [] e est definida dentro da
classe Matriz. Por isso, recebe um nico parmetro int i. A funo definida fora da classe, e
por isso que escrevemos Matriz:: antes do nome operator [] para indicar que se trata de uma
funo membro. Observe que a funo operator [] retorna uma referncia a um elemento da
matriz n. Dessa forma, a expresso notas[i] age como o prprio elemento da matriz privada,
podendo ser usado em instrues como :
cin >> notas[i];
notas[i] = 67.75;

Retornar uma referncia no simplesmente eficiente, mas sim necessrio. Caso contrrio,
no teremos acesso direto a um elemento da classe mas a uma cpia deste, no podendo assim
alterar o valor deste elemento com instrues de atribuio como as declaradas acima.
A funo operator [] cria uma varivel static, pois no podemos retorar uma referncia
para uma varivel local (automtica) j que esta ser destruda ao final da execuo da funo.
Aqui comeamos a discutir alguns aspectos sobre o operador de atribuio (=). Voc sabe
que o operador = pode atribuir o valor de uma varivel simples a outra do mesmo tipo. Podemos
tambm atribuir um objeto a outro da mesma classe usando instrues como:
Obj2 = Obj1;
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
113

Curso de Linguagem Computacional C/C++

Geralmente, quando o valor de um objeto atribudo a outro de mesma classe, o valor de


todos os seus membros de dados so simplesmente copiados no novo objeto. O compilador no
executa nenhuma instruo especial no uso de atribuies entre tipos definidos pelo usurio.
A complexidade surge quando a atribuio entre variveis de tipos diferentes. Podemos
converter um valor float para uma varivel inteira atravs de uma das seguintes intrues:
int i = int(3.141567);
int i = (int) 3.141567;

Assim como podemos converter um tipo bsico em outro tipo, podemos tambm converter
um objeto de uma classe em um tipo bsico ou em um objeto de outra classe.
Para converter um tipo definido pelo programador, como classes, num tipo bsico
necessrio sobrecarregar o operador de molde, criando uma funo chamada conversora. No
exemplo anterior, sobrecarregamos o operador float *() como sendo uma funo da classe
Matriz, para converter um objeto desta classe em um ponteiro para uma lista de valores float:
operator float *() const // Funcao Conversora
{ return (float *)n; }

Este operador foi chamado pela instruo:


float * Temp = Notas;

que poderia ter sido escrita na forma explcita:


float * Temp = float *(Notas);

As duas formas tm exatamente o mesmo efeito. Primeiro o compilador procura pela


sobrecarga da operao de atribuio =() para este tipo, se no encontra, ento o compilador
procura pela funo conversora para este tipo. Note que a funo conversora no declara um tipo de
retorno, o prprio nome da funo j define o tipo de retorno.
No prximo exemplo vamos adicionar um conjunto de operadores a classe Ponto definida
anteriormente, para apresentar outras caractersticas e exemplos da sobrecarga de operadores.
// Classe Ponto ... exemplo da sobrecarga de operadores
#include <iostream>
using namespace std;
enum bool { false, true };
class Ponto
{
public:
int X, Y;
Ponto(int aX = 0, int aY = 0)

{ X = aX; Y = aY; }

Ponto operator ++(); // prefixado


Ponto operator ++(int); // pos-fixado
Ponto operator +(Ponto const aP) const;
Ponto operator +=(int const aN);
bool operator ==(Ponto const aP) const;
Ponto operator =(int aN);
};
Ponto Ponto::operator ++() //prefixado
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
114

Curso de Linguagem Computacional C/C++

{
++X; ++Y;
return *this;
}
Ponto Ponto::operator ++(int) //pos-fixado
{
++X; ++Y;
return Ponto(X-1, Y-1);
}
Ponto Ponto::operator +(Ponto const aP) const
{
return Ponto(X + aP.X, Y + aP.Y);
}
Ponto Ponto::operator +=(int const aN)
{
X += aN; Y += aN;
return *this;
}
bool Ponto::operator ==(Ponto const aP) const
{
return ((X == aP.X)&&(Y == aP.Y));
}
Ponto Ponto::operator =(int aN)
{
X = aN;
return *this;
}
class PFloat
{
public:
float X, Y;
PFloat(float aX = 0, float aY = 0)
{ X = aX; Y = aY; }
operator Ponto() const // Converte tipo
{
return Ponto((int) X, (int) Y);
}
};

// Operadores para objetos Iostream


ostream & operator<<(ostream & OS, Ponto const aP)
{
OS << '(' << aP.X << ','<< aP.Y <<')';
}
int main(int argc, char* argv[])
{
Ponto P1, P2(2,3), P3;
P3 = 2;
PFloat Pf( 2.12, 3.14);
P1 = Pf;
cout << "\n p1 = " << P1;
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
115

Curso de Linguagem Computacional C/C++

cout
cout
cout
cout
cout
cout

<<
<<
<<
<<
<<
<<

"\n
"\n
"\n
"\n
"\n
"\n

++p1 = " << ++P1;


p2 == p1 ? -> " << (P1 == P2);
p2 = " << P2;
p2 + p1 = " << (P2+P1);
pf = " << Pf;
p3 = " << P3;

return 0;
}

Comeamos definindo um tipo enum, para representar os valores booleanos.


A classe Ponto possui agora os atributos X e Y como sendo dados pblicos, somente para
facilitar o acesso a estas variveis. Ponto possui tambm um construtor default para a inicializao
dos dados.
Os primeiros operados sobrecarregados no exemplo so os operadores unrios de
incremento pr-fixado e ps-fixado. Dentre os operadores unrios existentes em C++, a sobrecarga
dos operadores de incremento e decremento apresenta uma dificuldade maior pelo fato de eles
operarem de forma diferente quando prefixados ou ps-fixados.
A declarao :
Ponto operator ++(); // prefixado

notifica o compilador da sobrecarga do operador prefixado. A definio do operador


idntica definio apresentada anteriormente. A primeira diferena que agora o operador est
definido fora da definio da classe. A segunda diferena est na forma como retornamos o
resultado da operao. Podemos faz-la de trs formas:
a)

Ponto Temp( X, Y);


return Temp;

b)

return Temp( X, Y);

c)

return *this;

As duas primeiras formas criam um objeto temporrio, armazenam nele os valores obtidos
na operao e retornam este objeto temporrio. Neste caso, no podemos utilizar a passagem de
parmetros por referncia pois estes objetos temporrios sero destrudos ao trmino da funo.
O terceiro utiliza o ponterio especial this. O ponteiro this um ponteiro especial que
pode ser acessado por todas as funes-membro do objeto. Este ponteiro aponta para o prprio
objeto. Qualquer funo-membro pode acessar o endereo do objeto do qual membro por meio do
ponteiro this. Quando um objeto criado, o compilador atribui o endereo do objeto ao ponteiro
this. Usamos o ponteiro this quando queremos que uma funo-membro retorne o prprio
objeto do qual membro. Para retornar o prprio objeto, devemos utilizar *this.
Aps o operador de incremento pr-fixado, definimos o operador de incremento ps-fixado.
Mas como pode o compilador distinguir os dois, sendo que ambos utilizam o mesmo simbolo e
possuem o mesmo operando? Neste caso, C++ adicionou um parmetro inteiro ao operador de
incremento ps-fixado, para distingui-lo do pr-fixado. Este parmetro int no serve para nada, a
no ser para podermos distinguir a declarao dos dois tipos de operadores. Por isso, que
declaramos este operador da seguinte forma:
Ponto operator ++(int); // pos-fixado

Observe que esta funo operadora definida como a anterior. Entretanto, agora no
podemos utilizar o ponteiro this para retornar o prprio objeto mas temos que criar um objeto
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
116

Curso de Linguagem Computacional C/C++

temporrio que conter o valor a ser retornado. Isto ocorre por que no operador ps-fixado, primeiro
ns utilizamos a varivel para depois increment-la.
Em seguida, temos a definio dos operadores binrios aritmticos (+) e (+=). Um
operador binrio definido como uma funo-membro possuir somente um parmetro, como foi
dito anteriormente. Uma classe pode redefinir vrias vezes os operadores binrios, desde que em
cada definio tenha um tipo de dado diferente como operando. No exemplo, o operador (+)
implementa a soma de dois objetos da classe Ponto, enquanto que o operador (+=) implementa a
soma de um valor inteiro a um objeto da classe Ponto, armazenando o resultado no prprio objeto.
O operador (+) cria um objeto temporrio para conter o resultado enquanto que o operador (+=)
utiliza o ponteiro this para retornar o prprio objeto como resultado.
Depois, temos a sobrecarga do operador binrio lgico (==) . Como os operadores acima,
este recebe um nico parmetro, que no caso ser outro objeto da classe Ponto. O tipo de retorno
aqui um tipo booleano (inteiro), j que o operador do tipo lgico.
O programador tem liberdade em C++ para definir a aplicao que ser dada para um
operador. Por exemplo, um programador pode sobrecarregar um operador binrio de bis (^=) para
atuar como um operador lgico ente objetos de uma dada classe, retornando um valor do tipo
inteiro. No significa que um operador lgico, somente poder ser sobrecarregado para efetuar
operaes lgicas entre objetos. Podemos, por exemplo, redefinir um operador lgico para efetuar
uma operao aritmtica ou qualquer outra operao entre dois objetos. C++ no controla a maneira
como utilizamos os operadores com os novos tipos de dados. C++ somente no permite a criao de
novos operadores e solicita que o nmero de parmetros definido para cada operador seja
respeitado. O que o operador faz, de responsabilidade puramente do programador.
Seguindo com o nosso exemplo, o prximo operador definido um operador de atribuio
(=), utilizado para atribuir um inteiro a um objeto do tipo Ponto, possuindo a seguinte declarao:
Ponto operator =(int aN);

O operador atribui a dimenso X do objeto ponto o valor de aN. Note que a forma de
declarar e definir o operador a mesma utilizada nos exemplos acima. Este operador tambm utiliza
o ponteiro this para retornar o prprio objeto. A novidade aqui aparece quando utilizamos este
operador para converter um inteiro em um objeto do tipo Ponto. Esta uma das formas importantes
para converter um tipo em outro, e aparece quando executamos a seguinte instruo e atribumos 2
ao objeto Ponto P3:
P3 = 2;

Em seguinda, criamos a classe PFloat parecida com a classe Ponto, para exemplificar a
converso de objetos de uma classe em objetos de outra classe. Note que PFloat contm as
coordenadas de um ponto x e y com valores float. Esta classe, possui tambm um construtor default.
A novidade surge na declarao do operador de converso para objeto da classe Ponto:
operator Ponto() const // Converte tipo
{
return Ponto((int) X, (int) Y);
}

No exemplo anterior apresentamos a converso de um objeto da classe Matriz para um


ponteiro do tipo float. Aqui, mostramos como podemos criar uma funo conversora para
converter um objeto de uma classe em outra classe. A funo operator Ponto() const
converter um objeto da classe PFloat para um objeto da classe Ponto. A mesma sintaxe pode
ser aplicada para converter qualquer tipo de objeto em uma outra classe.
Poderamos tambm implementar esta converso de outras duas formas diferentes.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
117

Curso de Linguagem Computacional C/C++

1) Sobrecarregando o operador de atribuio da classe Ponto, para atribuir um objeto da


classe PFloat em um objeto da classe Ponto.
2) Criando um construtor na classe Ponto, que receba como nico parmetro um objeto da
classe PFloat:
Ponto::Ponto(PFloat P1) { X =(int)P.X; Y =(int)P.Y;}

O resultado desta converso aparece na execuo da seguinte instruo:


P1 = Pf;

Por fim, sobrecarregamos o operador global de insero de dados em objetos da classe


ostream. Como vimos nos captulos anteriores, as classes stream controlam o acesso a entradas
e sadas do computador. Em especial, a classe istream controla a entrada padro e a classe
ostream controla a sada padro. Lembrando, que o objeto cout pertence classe ostream e o
objeto cin a classe istream. As classes stream redefiniram os operadores << e >> para operar
sobre todos os tipos bsicos existentes em C++. Desta forma, podemos escrever instrues como:
cout << Bom Dia!
cin >> n;

chamando automaticamente as funes de leitura e escrita da classe stream atravs da


sobrecarga de operadores. Na verso anterior da classe Ponto, utilizvamos a funo PrintPt()
para imprimir o valor de um objeto desta classe na tela. Entretanto, podemos fazer isto de uma
forma muito mais elegante definindo o operador << para receber como operandos um objeto da
classe ostream e um objeto da classe Ponto.
// Operadores para objetos Iostream
ostream & operator<<(ostream & OS, Ponto const aP)
{
OS << '(' << aP.X << ','<< aP.Y <<')';
}

Na sobrecarga deste operador, definimos como o objeto da classe Ponto ser apresentado
na tela. Definida esta sobrecarga, podemos ento passar um objeto da classe Ponto para um objeto
cout, como fazemos com qualquer tipo bsico. O mesmo princpio pode ser utilizado para a
sobrecarga do operador >> associando um objeto da classe istream (cin) a um objeto da
classe Ponto.
Podemos verificar o emprego desta funo sobrecarregada atravs da instruo abaixo, que
imprime na tela uma string de caracteres e, em seguinda, os dados de um objeto Ponto:
cout << "\n p1 = " << P1;

Entretanto, uma dvida surge, o que acontece na linha de cdigo abaixo:


cout << "\n pf = " << Pf;

Onde Pf um objeto da classe PFloat mas no sobrecarregamos o operador << para


receber como segundo parmetro um objeto da classe PFloat. Neste caso, o programa utiliza a
funo de converso de objeto PFloat em objetos do tipo Ponto definida acima, para converter
este objeto e utilizar a funo operadora << definida para objetos do tipo Ponto. Este exemplo,
mostra a importncia e flexibilidade das converses de tipos.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
118

Curso de Linguagem Computacional C/C++

15.5 Exerccios
15.1 Acrescente a classe Ponto sobrecarga dos operadores: menos unrio (-), menos
binrio (-), multiplicao (*), diviso (/), mdulo (%), s operaes aritmticas de atribuio e s
operaes lgicas.
15.2 Crie uma classe que defina um nmero complexo (x + yi, onde x e y so do tipo float e
i a raiz quadrada de 1). Defina, todos os os operadores aritmticos, de bits e lgicos para esta
classe. Sobrecarrege os operadors << e >> da classe stream, para a leitura/escrita de objetos desta
classe. Crie uma outra classe para a representao de nmeros complexos no plano polar. Crie
funes de converso, para que os objetos das duas classes sejam equivalentes.
15.3 Crie uma classe para representar strings. Reimplemente os operadores aritmticos, de
atribuio e lgicos para o contexto desta classe. Crie funes conversoras dos tipos bsicos (int,
char, float, ...) para objetos desta classe. Sobrecarrrege o operador [] para controlar o acesso a
elementos individuais da classe string e crie uma funo que converta objetos da classe string em
um ponteiro do tipo char.
15.4 Inclua uma sobrecarga do operador de chamada funo () na classe string anterior. O
seu prottipo o seguinte:
void operator ()(int n, char ch);

Esta sobrecarga atribui o caracter ch ao n-simo caracter da cadeia. Escreva um programa de


teste.
15.5 Crie uma classe para representar as cores (class Cor). Sobrecarrege os operadores
aritmticos e relacionais para esta classe. Utilize o princpio, que a soma de duas cores uma cor
misturada com metade de cada uma das cores anteriores. Defina as outras funes aritmticas.
Utilize os operadores para os objetos cout e cin, para ler e escrever dados desta classe.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
119

Curso de Linguagem Computacional C/C++

16 Herana
Nos captulos anteriores definimos que classe representa um tipo de objeto. Ento, quando
modelamos um ambiente atravs da orientao a objetos, criamos uma classe para cada tipo de
objeto presente e modelado no ambiente. Entretanto, existem alguns tipos (classes) de objetos que
possuem caractersticas semelhantes com outros tipos (classes) de objetos.
Por exemplo, quando estamos modelando o funcionamento de um banco, podemos definir
como objetos do modelo o cliente que chega na agncia e os funcionrios do banco. Ao
modelarmos estas duas entidades, percebemos que ambas possuem determinadas caractersticas em
comum; ambas entidades so seres humanos. Por serem pessoas, ambas as entidades contero
necessariamente a descrio de uma pessoa mais os seus dados especficos. Para no representar
duas vezes o elemento pessoa, uma na entidade cliente e outra na entidade funcionrio, criamos
ento uma entidade separada chamada pessoa e descrevemos atravs desta a entidade pessoa. Aps
a definio desta nova entidade, dizemos que as classes funcionrios e clientes herdam da classebase pessoa todas as caractersiticas que definem um ser humano no nosso modelo. Na figura
abaixo apresentamos a diferena entre as duas modelagens.
Classe

Classe

Funcionrio

Cliente

Pessoa

Pessoa

Classe-Base
Pessoa
A

Herana
Funcionrio
C

Cliente
E

Classes Derivadas

Figura 3 : Modelagem aplicando-se o princpio da Herana.

O processo de hierarquia est presente quando dividimos classes em sub-classes, mantendose o princpio de que cada subclasse herda as caractersticas da classe da qual foi derivada. Alm
das caractersiticas herdadas, cada subclasse tem suas caractersticas particulares. Em programao
orientada a objetos, o conceito de subclasse ou classes derivadas chamado de herana.
Em C++, a classe de origem chamada classe-base e as classes que compartilham as
caractersticas de uma classe-base e tm outras caractersticas adicionais so chamadas de classes
derivadas (ver Figura 3). Em C++, definimos uma classe-base quando identificamos caractersticas
comuns em um grupo de classes.
Com o princpio da herana, alm de precisarmos modelar somente uma vez a entidade
pessoa, o nosso modelo ainda ganha em flexibilidade e em organizaao do projeto. Suponha que
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
120

Curso de Linguagem Computacional C/C++

neste modelo voc tenha que futuramente incluir a entidade acionista no modelo do banco. Bem,
considerando que todo acionista tambm um ser humano, basta definir que a classe acionista ser
derivada da classe-base pessoa, herdando todas as suas propriedades (mtodos e atributos), e
adicionar a classe acionista as suas propriedades particulares.
Podemos ainda refinar o modelo acima, criando diferentes classes para modelar diferentes
tipos de clientes. Podemos criar uma classe para modelar os clientes que so universitrios. Esta
classe seria um refinamento da classe cliente e, por isso, representamos esta entidade como uma
classe derivada da classe cliente. Neste sentido, somente precisamos adicionar as propriedades
particulares da classe cliente-universitrio como: o nmero de matrcula, o nome do curso e a data
prevista para a formatura. Uma classe que derivada de uma classe-base pode, por sua vez, ser a
classe-base de outra classe.
Outro aspecto importante a reutilizao do programa. Suponha que amanh aparea um
projeto para modelarmos uma clula de produo de uma fbrica. Neste modelo, precisamos
modelar pessoas com diferentes propriedades: engenheiros, gerentes e funcionrios. Neste caso,
podemos utilizar a nossa classe-base pessoa para definir estas trs novas classes, ganhando assim
em tempo de projeto. Se recebermos um outro novo projeto para representar uma padaria,
poderemos ento aproveitar diversas entidades do nosso modelo como as classes pessoa, cliente,
funcionrio e cliente-universitrio. Diminuindo, assim, consideravelmente o tempo deste projeto.
Voc pode ento criar uma biblioteca com todas as classes definidas que podero vir a ser o
ncleo de muitos programas. Desta forma, voc ter grandes vantagens em termos de reutilizao e
baixo custo de projeto.O uso de uma biblioteca de classes oferece uma grande vantagem sobre o uso
de uma biblioteca de funes: o programador pode criar classes derivadas de classes-base da
biblioteca. Isto significa que, sem alterar a classe-base, possvel adicionar a ela caractersticas
diferentes que a tornaro capaz de representar exatamente o que desejamos. A facilidade com que
classes existentes podem ser reutilizadas sem ser alteradas um dos maiores benefcios oferecidos
por linguagens orientadas a objetos.
O processo de herana vai alm da derivao simples. Uma classe derivada pode herdar
caractersticas de mais de uma classe-base. Classes derivadas no esto limitadas a herana nica.
Sempre que estivermos modelando um ambiente, seja este real ou abstrato, precisamos fazlo da forma mais genrica possvel. Quando mais genrico for o modelo, mais flexvel ser o nosso
sistema e maior ser a reusabilidade e expandabilidade do nosso sistema. Modelar um sistema
significa representar todas as propriedades importantes deste e no descrever este da maneira mais
detalhada possvel. No exagere no nvel de detalhe do seu modelo. Isto diminuir a flexibilidade
do seu modelo, aumentar o tempo de projeto, aumentar a quantidade de erros, diminuir a
velocidade do programa e aumentar o tamanho deste.
A orientao a objetos realmente muito poderosa, permitindo-nos a construo de projetos
flexveis, permitindo a reutilizao de partes do modelo e do cdigo bem como a fcil expanso do
sistema. Entretanto, a eficincia do seu programa orientado a objetos depende diretamente da
qualidade do seu modelo. Modelos enxutos e bem definidos, geram programas velozes e flexveis.
Modelos enormes e obscuros, geram programas gordos e complexos, cheios de erros, ilegveis e
que no podem ser reaproveitados. Tenha concincia ao modelar um sistema e bom-senso para
definir as classes e as suas relaes. O bom entendimento da metodologia orientada a objetos,
permitir que voc modele adequadamente um sistema qualquer.

16.1 Derivando uma Classe


Agora mostraremos como podemos implementar em C++ a criao de uma classe-base e a
sua derivao criando uma nova classe. Aqui, apresentaremos na forma de um exemplo a sintaxe
empregada em C++. Como exemplo, vamos modelar a classe Pessoa apresentada como exemplo
acima e a classe cliente, derivada da classe Pessoa.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
121

Curso de Linguagem Computacional C/C++

// Exemplo de classes derivadas ...


#include <iostream>
#include <string>
using namespace std;
#define Nome_Size
80
class Pessoa
{
protected:
char *
int
long int

Nome;
Idade;
RG;

public:
Pessoa();
Pessoa(char * aNome, int aId = 0, long int aRG = 0);
Pessoa(Pessoa const & aP);
~Pessoa();
char const * GetNome()
const { return Nome; }
int
GetIdade() const { return Idade; }
long int
GetRG()
const { return RG;

void
GetData();
};
Pessoa::Pessoa()
{
Nome = new char[Nome_Size];
Idade = 0;
RG = 0;
}
Pessoa::Pessoa( char * aNome, int aId, long int aRG)
{
Nome = new char[Nome_Size];
strcpy( Nome, aNome);
Idade = aId;
RG = aRG;
}
Pessoa::Pessoa(Pessoa const & aP)
{
Nome = new char[Nome_Size];
strcpy( Nome, aP.GetNome());
Idade = aP.GetIdade();
RG = aP.GetRG();
}
Pessoa::~Pessoa()
{
if(Nome != 0)
{
delete Nome;
Nome = 0;
}
}
void Pessoa::GetData()
{
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
122

Curso de Linguagem Computacional C/C++

cout << "\nNome : ";


cin.getline( (char *)Nome, Nome_Size);
cout << "Idade : ";
cin >> Idade;
cout << "RG : ";
cin >> RG;
}
ostream & operator <<(ostream & OS, Pessoa & const P)
{
OS << "\n\n Dados Pessoais ---------------"
<< "\n Nome : " << P.GetNome()
<< "\n Idade : " << P.GetIdade()
<< "\n RG
: " << P.GetRG();
return OS;
}
class Cliente : public Pessoa
{
protected:
int Conta;
int Saldo;
public:
Cliente();
Cliente(char * aNome, int aConta = 0, int aId = 0, long int aRG =
0, int aSaldo = 0);
int GetConta() const { return Conta; }
int GetSaldo() const { return Saldo; }
void
GetData();
};
Cliente::Cliente() : Pessoa()
{
Conta = 0;
Saldo = 0;
}
Cliente::Cliente(char * aNome, int aConta, int aId, long int aRG, int
aSaldo) : Pessoa(aNome, aId, aRG)
{
Conta = aConta;
Saldo = aSaldo;
}
void Cliente::GetData()
{
Pessoa::GetData();
cout << "Conta : ";
cin >> Conta;
cout << "Saldo : ";
cin >> Saldo;
}
ostream & operator <<(ostream & OS, Cliente & const C)
{
OS << Pessoa(C);
OS << "\n Conta : " << C.GetConta()
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
123

Curso de Linguagem Computacional C/C++

<< "\n Saldo : " << C.GetSaldo();


return OS;
}
int main(int argc, char* argv[])
{
Pessoa P1("Carlos", 18, 1315678);
Cliente C1, C2("Pedro", 1234, 17, 123432);
C2.GetData();
C1.Pessoa::GetData();
Pessoa P2 = P1;
Pessoa P3 = C1;
cout << P1 << P2 << P3;
cout << C1 << C2;
return 0;
}

Para derivar uma nova classe de uma classe j existente, basta indicar o nome da classe-base
aps o nome da nova classe, separado por dois-pontos (:). O nome da classe-base pode ser
precedido da palavra public ou da palavra private.
class Cliente : public Pessoa

Esta declarao indica que a classe Cliente derivada da classe Pessoa. A classe
Cliente incorpora todos os membros da classe Pessoa, alm de seus prprios membros.
Nem sempre queremos criar objetos da classe-base. Muitas vezes declaramos classes
somente para que estas sirvam como uma classe-base para um conjunto de classes derivadas.
Classes usadas somente para derivar outras classes so geralmente chamadas classes abstratas, o
que indica que nenhuma instncia (objeto) delas criado. Entretanto, o termo abstrato tem uma
definio mais precisa quando usado com funes virtuais, apresentado no prximo captulo.

16.2 Dados Protected


Observe que a parte pblica da classe-base est disponvel classe derivada e a qualquer
objeto dessa classe. Qualquer membro pblico da classe-base automaticamente um membro da
classe derivada. Entretanto, nenhum membro privado da classe-base pode ser acessado pela classe
derivada. Por isso, criaram-se os membros protected. Membros protected so semelhantes a
membros private, exceto pelo fato de que so visveis a todos os membros de uma classe derivada.
Observe que membros protected no podem ser acessados por nenhum objeto declarado fora dessas
classes. Sempre que voc escrever uma classe que pode vir a ser uma classe-base de outras classes,
declare como protected os membros privados necessrios s classes derivadas.
Segundo este princpio, os dados definidos na classe-base Pessoa estaro disponveis a
funes-membro da classe Cliente, porque foram definidas como protected. Entretanto, tero
restries do tipo private para acessos fora da classe-base ou fora da classe derivada.

16.3 Construtores & Destrutores


Se nenhum construtor for especificado na classe derivada, o construtor da classe-base ser
usado automaticamente. Observe os construtores da classe Cliente:
Cliente::Cliente() : Pessoa()
{
Conta = 0;
Saldo = 0;
}
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
124

Curso de Linguagem Computacional C/C++

Cliente::Cliente(char * aNome, int aConta, int aId, long int aRG,


int aSaldo) : Pessoa(aNome, aId, aRG)
{
Conta = aConta;
Saldo = aSaldo;
}

Estes construtores tm uma sintaxe no familiar: os dois-pontos seguidos do nome da funo


construtora da classe-base. Isto causa a chamada ao construtor sem argumentos da classe Pessoa,
quando um objeto criado sem valores de inicializao, e a chamada ao construtor com argumentos
da classe Cliente, quando fornecemos valores para a inicializao do objeto. A instruo:
Cliente C2("Pedro", 1234, 17, 123432);

usa o construtor com argumentos da classe Cliente. Este construtor chama o construtor
correspondende da classe-base, enviando os argumentos recebidos para o construtor da classe-base
Pessoa que, por sua vez, inicializa o objeto. Note, que o construtor da classe derivada chama o
construtor da classe-base e depois executa algumas rotinas para inicializar somente os dados
especficos da classe-derivada.
No nosso programa exemplo, a classe Pessoa tem um atributo do tipo ponteiro que
alocado dinamicamente quando criamos um objeto e destrudo (liberado) quando destrumos este
objeto. Para tal, inclumos a seguinte instruo nos construtores da classe:
Nome = new char[Nome_Size];

Ento, definimos um destrutor para a classe para liberar a memria alocada antes de destruir
o objeto. Observe, que antes de liberarmos a memria vamos testar se o ponteiro atual vlido. Mas
a classe Cliente no define nenhum destrutor. Isto implica que quando destruirmos um objeto da
classe Cliente, o compilador ir utilizar o destrutor da classe-base, liberando assim a memria
alocada.

16.4 Construtor de Cpia & Alocao Dinmica


O programa cria o objeto P2 e ento atribui a ele o contedo do objeto P1. O seguinte
problema acontecer: quando voc atribui um objeto a outro, o compilador copia, byte a byte, todo
o contedo de memria de um objeto no outro. Em outras palavras, ao membro Nome de P2 ser
atribudo o contedo do membro Nome de P1. Entretanto, o membro Nome um ponteiro e, como
resultado, P2.Nome e P1.Nome apontaro para a mesma localizao na memria.
Desta forma, qualquer modificao na cadeia de caracteres de um dos objetos afetar
diretamente o outro. Um problema mais srio ocorre quando os objetos envolvidos tm escopos
diferentes. Quando o destrutor de P1 chamado, destruir a memria alocada e apontada por P1,
destruindo portanto a mesma memria apontada por P2. Se P2 tentar acessar o contedo deste
ponteiro, um erro fatal ser gerado.
Para evitar que este erro acontea, implementamos o construtor de cpia para os objetos da
classe Pessoa:
Pessoa(Pessoa const & aP);

Este construtor aloca um espao de memria para armazenar os seus dados e depois copia os
valores contidos do objeto passado como argumento. Note que esta funo no copia o endereo
contido em Nome, mas sim o valor apontado por este ponteiro. Evitando assim o problema descrito
acima. Este construtor de cpia muito importante, geralmente utilizado na converso de outros
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
125

Curso de Linguagem Computacional C/C++

objetos para este tipo ou na atribuio de objetos. Reimplemente este operador sempre que a sua
classe contiver ponteiros com alocao dinmica como atributos.

16.5 Chamadas a Funes


O objeto C1 da classe Cliente usa a funo GetData() membro da classe Cliente,
na instruo:
C1.GetData();

O compilador sempre procurar primeiro pela funo na classe que define o objeto (no caso,
Cliente). Se o compilador no encontrar esta funo ento ele ir procurar nas classes-bases da
classe do objeto. Se ele encontrar em uma classe-base, o compilador executar a funo encontrada
seno ocorrer um erro.
Podemos criar funes-membro de uma classe derivada que tenham o mesmo nome de
funes-membro da classe-base. Isto faz com que a sintaxe da chamada a elas, por meio de um
objeto, seja a mesma, independentemente de tratar-se de um objeto da classe-base ou da classe
derivada.
A funo GetData() est definida com o mesmo prottipo tanto na classe-derivada
quanto na classe-base, ento qual das verses da funo ser utilizada pelo compilador? A regra a
seguinte: se duas funes de mesmo nome existem, uma na classe-base e outra na classe derivada, a
funo da classe derivada ser executada se for chamada por meio de um objeto da classe
derivada.Se um objeto da classe base criado, usar sempre funes da prpria classe-base pois no
conhece nada sobre a classe derivada.
Para que uma funo da classe derivada, com mesmo nome de uma funo da classe-base,
possa acessar a que est na classe-base, necessrio o uso do operador de resoluo de escopo
(::):
Pessoa::GetData();
Esta instruo executa a funo GetData() da classe-base dentro da definio desta
funo na classe-derivada. Sem o uso do operador de resoluo de escopo, o compilador executar a
funo GetData() da classe-derivada e o resultado ser uma seqncia infinita de chamadas
recursivas. O operador de resoluo de escopo permite que se especifique exatamente qual a
classe da funo que queremos executar.
C2.GetData();
C1.Pessoa::GetData();

A diferena das instrues acima que para o primeiro objeto, estaremos utilizando a verso
da funao GetData() definida na classe derivada e para o segundo objeto estaremos utilizando a
verso da funo definida na classe-base. A distino entre as duas chamadas feita pelo operador
de resoluo de escopo (::).

16.6 Herana Pblica e Privada


Declaramos a classe derivada Cliente especificando a palavra public:
class Cliente : public Pessoa

A declarao public indica que os membros pblicos da classe-base sero membros pblicos
da classe derivada e os membros protected da classe base sero tambm membros protected da
classe derivada. Os membros pblicos da classe-base podem ser acessados por um objeto da classe
derivada.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
126

Curso de Linguagem Computacional C/C++

A declarao private pode ser usada no lugar de public e indica que tanto os membros
pblicos quanto os protegidos da classe-base sero membros privados da classe derivada. Estes
membros so acessveis aos membros da classe derivada, mas no aos seus objetos. Portanto, um
objeto da classe derivada no ter acesso a nenhum membro da classe-base.
Os membros privados da classe-base sero sempre inacessveis fora da classe-base.
Nenhuma classe derivada pode acessar um membro privado de uma classe base.
Geralmente, a derivao privada raramente usada. Mas h momentos em que a derivao
privada desejvel. Por exemplo, imagine que voc tenha uma funo da classe-base que trabalha
perfeitamente com objetos da classe base, mas gera resultados errados quando usado com objetos da
classe derivada. A derivao privada neste caso uma soluo bem elegante.

16.7 Converses de Tipos entre Classe-Base e Derivada


Visto que Cliente um tipo de Pessoa, faz sentido pensar em converter um objeto da classe
Cliente num objeto da classe Pessoa. C++ permite a converso implcita de um objeto da
classe derivada num objeto da classe-base. Por exemplo:
Pessoa P3 = C1; // C1 um objeto da classe Cliente

Todos os membros da classe-base P3 recebem os valores dos membros correspondentes do


objeto C1 da classe derivada. Aqui, o construtor de cpia da classe Pessoa evitar que um erro
ocorra devido a um ponteiro presente na classe. Este construtor utilizado para converter o objeto
da classe derivada em um objeto da classe base sem que ambos objetos contenham o mesmo
endereo no ponteiro e venham a causar um erro de acesso memria.
Entretanto a atribuio inversa no vlida, no podemos atribuir um objeto da classe-base
a um objeto da classe derivada.
Sobrecarregamos os operadores << associados a objetos da classe ostream, para facilitar a
apresentao dos dados dos objetos de ambas as classes na tela. Perceba que na implementao da
sobrecarga do operador << para o objeto da classe ostream e um objeto da classe Cliente, que
utilizamos uma converso na instruo abaixo:
OS << Pessoa(C);

Esta converso converte temporariamente o objeto C da classe Cliente para um objeto da


classe Pessoa. Isto causar a chamada do operador << definido para a classe Pessoa,
imprimindo na tela os dados da classe Pessoa presentes no objeto da classe Cliente. Esta
instruo opera como se estivssemos chamando uma funo da classe-base utilizando o operador
de resoluo de escopo. Aqui no utilizamos o operador, mas convertemos o objeto da classe
derivada, para um objeto da classe base antes de chamarmos a funo, o que tem o mesmo
resultado.

16.8 Nveis de Herana


Uma classe por ser derivada de outra classe , que , por sua vez tambm uma classe
derivada.
class X {};
class Y : public X {};
class Z : public Y {};

Neste exemplo, Y derivada de X, e Z derivada de Y. Este processo pode ser estendido


para qualquer nmero de nveis, K pode ser derivada de Z, e assim por diante.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
127

Curso de Linguagem Computacional C/C++

16.9 Herana Mltipla


Uma classe pode herdar as caractersticas de mais de uma classe. Este processo chamado
de herana mltipla. A construo de hierarquias de herana mltipla envolve mais complexidade
do que as hierarquias de herana simples. Esta complexidade diz respeito ao desenho da construo
das classes e no sintaxe de uso. A sintaxe de mltiplas heranas similar quela de uma nica
herana. Eis um exemplo que representa os imveis venda de uma imobiliria :
// Heranca Multipla
#include <iostream>
#include <cstdio>
#include <iomanip>
#include <string>
using namespace std;
class Cadastro
{
private:
char nome[30], fone[20];
public:
Cadastro() { nome[0] = fone[0] = '\0'; }
Cadastro(char n[], char f[])
{
strcpy(nome, n);
strcpy(fone, f);
}
void GetData()
{
cout << "\n\tNome: ";
cin.getline(nome, 30);
cout << "\tFone: ";
cin.getline(fone, 20);
}
void PutData()
{
cout << "\n\tNome: " << nome;
cout << "\n\tFone: " << fone;
}
};
class Imovel
{
private:
char end[30], bairro[20];
float AreaUtil, AreaTotal;
int quartos;
public:
Imovel()
{
end[0] = bairro[0] = '\0';
AreaUtil = AreaTotal = 0;
quartos = 0;
}
Imovel(char e[], char b[], float au, float at, int q)
{
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
128

Curso de Linguagem Computacional C/C++

strcpy(end, e);
strcpy(bairro,b);
AreaUtil = au;
AreaTotal = at;
quartos = q;
}
void GetData()
{
cout << "\n\tEnd: "; cin.getline(end, 30);
cout << "\tBairro: "; cin.getline(bairro, 20);
cout << "\tArea Util: "; cin >> AreaUtil;
cout << "\tArea Total: "; cin >> AreaTotal;
cout << "\tNo. Quartos: "; cin >> quartos;
}
void PutData()
{
cout << "\n\tEnd : " << end;
cout << "\n\tBairro : " << bairro;
cout << "\n\tArea Util : " << setiosflags(ios::fixed)
<< setprecision(2) << AreaUtil
<< "\n\tArea Total : " << AreaTotal
<< "\n\tQuartos : " << quartos;
}
};
class Tipo
{
private:
char tipo[20]; // Residencial, Loja, Galpao
public:
Tipo() { tipo[0] = '\0'; }
Tipo(char t[]) {
strcpy(tipo, t); }
void GetData()
{
cout << "\n\tTipo : ";
cin.getline(tipo, 20);
}
void PutData()
{
cout << "\n\tTipo: " << tipo;
}
};
class Venda : private Cadastro, public Imovel, public Tipo
{
private:
float valor;
public:
Venda() : Cadastro(), Imovel(), Tipo() {valor = 0;}
Venda(char n[], char f[], char e[], char b[],
float au, float at, int q, char t[], float v)
: Cadastro(n,f), Imovel(e,b,au,at,q), Tipo(t)
{ valor = v; }
void GetData()
{
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
129

Curso de Linguagem Computacional C/C++

cout << "\n ...Proprietarios: ";


Cadastro::GetData();
cout << "\n ...Imovel: ";
Imovel::GetData();
Tipo::GetData();
cout << "\tValor R$ : "; cin >> valor;
}
void PutData()
{
cout << "\n ...Proprietario: ";
Cadastro::PutData();
cout << "\n ...Imovel: ";
Imovel::PutData();
Tipo::PutData();
cout << "\n\tValor R$ : " << valor;
}
};
int main(int argc, char* argv[])
{
Venda C,V("Eduardo Mattos", "3203322", "Rua Rocha, 33", "Coqueiros",
50.0, 75.0, 2, "Comercial", 80000.0 );
cout << "\n\n* Imovel Para Venda : ";
V.PutData();
cout << "\n\n Digite um Imovel para Vender!\n";
C.GetData();
C.PutData();
return 0;
}

Atravs da declarao:
class Venda : private Cadastro, public Imovel, public Tipo { ... };

notificamos o compilador que a classe Venda derivada das classes Cadastro, Imovel e
Tipo. Cadastro tem derivao do tipo privada enquanto que as demais classes tm derivaes do
tipo pblicas. Muitas vezes podemos substituir uma herana por um objeto da classe-base. A
escolha de qual mtodo devemos aplicar depende muito do modelo adotado e do desempenho
esperado. Uma boa modelagem pode definir claramente quais sero as classes criadas e como elas
devero iteragir.
Os construtores da classe Venda so os seguintes:
Venda() : Cadastro(), Imovel(), Tipo() {valor = 0;}
Venda(char n[], char f[], char e[], char b[],
float au, float at, int q, char t[], float v)
: Cadastro(n,f), Imovel(e,b,au,at,q), Tipo(t)
{ valor = v; }

Note que a definio de um construtor de uma classe com herana mltipla muito similar
ao construtor de uma classe com herana simples. Ao chamar os construtores das classes-bases,
devemos lembrar que os nomes dos construtores so colocados aps os dois-pontos e separados por
vrgulas. A ordem de chamada a mesma da ordem em que eles aparecem escritos. Parmetros
podem ser passados assim como em qualquer outro construtor.
As funes GetData() e PutData() da classe Venda incorporam a chamada s
funes correspondentes das classes Cadastro, Imovel e Tipo empregando o operador de
resoluo de escopo (::) para efetuar a chamada das funes das classes base:
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
130

Curso de Linguagem Computacional C/C++

Cadastro::GetData();
Cadastro::PutData();

Imovel::GetData();
Imovel::PutData();

Tipo::GetData();
Tipo::PutData();

Alguns tipos de problemas podem aparecer em certas situaes envolvendo herana


mltipla. O mais comum quando duas classes-base tm, cada uma delas, uma funo de mesmo
nome (prottipo), enquanto a classe derivada destas duas no tem nenhuma funo com este nome.
Quando a funo acessada por meio de um objeto da classe derivada, o compilador no
reconhecer qual das duas estar sendo chamada. Para informar ao compilador qual das duas
funes est sendo solicitada, devemos utilizar o operador de resoluo de escopo (::). Por
exemplo, podemos chamar a funo PutData() da classe Imovel com um objeto da classe
Venda atravs da instruo:
C.Imovel::PutData();

Caso a classe derivada no contivesse esta funo, este seria o nico mtodo de acesso a esta
funo sem causar um erro de ambiguidade.

16.10

Exerccios

16.1 No incio comeamos discutindo a modelagem de um banco orientado a objetos.


Termine o programa que modela as pessoas que compem o ambiente banco : acionista, cliente,
funcionrio, cliente-universitrio, pessoa-fsica, pessoa-jurdica, etc.
16.2 Crie uma classe Empresa capaz de armazenar os dados
Cidade, Estado, CEP, CGC, Fone e E-mail). Use a classe Empresa
Restaurante. Inclua o tipo de comida, o preo mdio de um prato,
dados e para imprim-los na tela. Sobrecarrega o operador ostream

de uma empresa (Nome, End,


como base para criar a classe
funes para adquirir os seus
<<.

16.3 Imagine que voc deva escrever um programa para armazenar veculos. Primeiramente,
crie a classe Motor que contm NumCilindro e Potencia. Inclua um construtor com argumentos com
valores default que inicialize os dados com zeros e um construtor de cpia. Escreva a classe Veculo
contendo peso, velocidade mxima e preo. Crie a classe CarroPasseio usando as classes Motor e
Veculo como base. Inclua cor e modelo. Crie a classe caminho derivada das classes Motor e
Veculo. Inclua a carga mxima, altura mxima e comprimento. Crie um programa para o controle
de um estacionamento que tenha uma rea fixa e controle o acesso de veculos no estacionamento.
Verifique se um veculo pode ou no estacionar antes de permitir a entrada. Se puder, indique onde
este deve estacionar. Reflita sobre o problema, crie um modelo e decida quais propriedades dos
veculos devem ser descritas. Aceite as propriedades propostas como sugestes mas crie o seu
prprio programa.
16.4 Um rob pode ser composto por trs tipos de motores : motor de corrente contnua,
motor de passo e motor assncrono. Um rob pode conter juntas com movimento angular (geram
uma variao no ngulo entre dois elos), transversal (geram um deslocamento linear dos elos) ou
juntas que no geram movimento nenhum, simplesmente ligam dois elos. Cada el pode ser uma
barra reta ou uma curva suave de 90 graus. Um rob pode ter uma garra para pegar objetos, uma
garra para fazer operaes de soldagem e uma garra para fazer operaes de pintura. Modele um
rob segundo as consideraes acima, definindo a geometria do rob e como ser o movimento
deste. Crie um rob que seja capaz de pintar a parte superior de uma mesa, soldar em cima desta
uma caixa. A mesa esta a 50 cm na frente do rob e a caixa est a 50 cm direita do rob.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
131

Curso de Linguagem Computacional C/C++

17 Funes Virtuais e Amigas


Neste captulo discutiremos tpicos avanados sobre classes. Cobriremos a definio e o uso
de funes virtuais e funes amigas.

17.1 Funes Virtuais


Muitas vezes, quando derivamos um grupo de classes a partir de uma classe-base, certas
funes-membro precisam ser redefinidas em cada uma das classes derivadas. Suponha o seguinte
exemplo, onde temos uma classe base e duas classes derivadas. A funo print() est definida
na classe base e redefinida nas classes derivadas. As nossas classes definem os tipos de clientes em
um banco. Temos os clientes normais (classe-base) e clientes universitrios ou especiais.
// Testando funcoes Virtuais
#include <iostream>
using namespace std;
class Cliente {
public:
virtual void print() { cout << "\nCliente"; }
};
class Universitario : public Cliente {
public:
void print() { cout << "\nCliente Universitario"; }
};
class Especial : public Cliente {
public:
void print() { cout << "\nCliente Especial";}
};
int main(int argc, char* argv[])
{
Cliente * p[3]; // matriz de ponteiros da classe-base
Cliente
B;
Universitario D1;
Especial D2;
p[0] = &B;
p[1] = &D1;
p[2] = &D2;
p[0]->print();
p[1]->print();
p[2]->print();
return 0;
}

Planejamos agrupar um conjunto de objetos destas classes em uma lista nica. Isto , o
nosso objetivo ter uma lista nica de clientes e diferenci-los pelos tipos de objetos que os
definem. Um dos meios criar uma matriz de ponteiros para os diferentes objetos envolvidos. Qual
seria o tipo da matriz tendo em vista que ela deve armazenar ponteiros para objetos de classes
diferentes? A resposta est em como o compilador opera ponteiros em situaes deste tipo. Um
ponteiro para um objeto de uma classe derivada de tipo compatvel com um ponteiro para um
objeto da classe-base. Segundo este princpio, criamos um vetor de ponteiros da classe-base e
atribumos a ele endereos das classes derivadas, como voc pode observar acima.
Podemos imprimir os dados da lista, atravs da chamada da funo print() :
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
132

Curso de Linguagem Computacional C/C++

for(int i = 0; i<10; i++) p[i]->print();

Observe que desejamos que funes completamente diferentes sejam executadas por meio
da mesma instruo de chamada. Se o ponteiro p[i] apontar para um cliente normal, a funo da
classe base dever ser executada; se p[i] apontar para um cliente especial, a funo da classe de
clientes especiais dever ser executada.
A caracterstica de chamar funes membros de um objeto sem especificar o tipo exato do
objeto conhecida como polimorfismo. A palavra polimorfismo significa assumir vrias formas.
Em C++ indica a habilidade de uma nica instruo chamar diferentes funes e portanto assumir
diferentes formas.
Para que o exemplo anterior funcionasse corretamente, duas condies tiveram que ser
introduzidas. Em primeiro lugar, todas as diferentes classes de clientes devem ser derivadas da
mesma classe-base. Em segundo lugar, a funo print() deve ser declarada como virtual na
classe-base.
Apesar de termos fornecidos os endereos de objetos de classes derivadas, o compilador
trata todos os endereos da lista de ponteiros como endereos da classe-base, ou seja, considera que
os ponteiros apontam para objetos da classe-base. Quando executamos uma funo utilizando este
ponteiro,
p[i]->print();

a funo ser executada como se o objeto referenciado fosse da classe base.


p[i]->Cliente::print();

o compilador ignora o contedo do ponteiro p[i] e usa o seu tipo para identificar a funomembro a ser chamada. Para acessar objetos de diferentes classes usando a mesma instruo,
devemos declarar as funes da classe-base que sero reescritas em classes derivadas usando a
palavra-chave virtual.
As instrues de chamada a funes no-virtuais so resolvidas em tempo de compilao e
so traduzidas em chamadas a funes de endereos fixos. Isto faz com que a instruo seja
vinculada funo antes da execuo. Quando uma instruo de chamada a uma funo virtual
encontrada pelo compilador, ele no tem como identificar qual a funo associada em tempo de
compilao. Em instrues como a escrita acima, o compilador no conhece qual classe p[i] contm
antes de o programa ser executado. Ento, a instruo avaliada em tempo de execuo, quando
possvel identificar qual o tipo de objeto apontado por p[i]. Isto chamado de resoluo dinmica.
A resoluo dinmica permite que uma instruo seja associada a uma funo no momento
de sua execuo.O programador especifica que uma determinada ao deve ser tomada em um
objeto por meio de uma instruo. O programa, na hora da execuo, interpreta a ao e vincula a
ao funo apropriada. A resoluo dinmica envolve mais memria e tempo de execuo,
entretanto aumenta a flexibilidade no projeto do software e permite criar bibliotecas de classes que
outros programadores podem estender no tendo o arquivo-fonte.
Uma funo virtual pura uma funo virtual sem bloco de cdigo ou o bloco de cdigo no
contm nenhuma instruo. O propsito de uso de uma funo virtual pura em situaes em que a
funo nunca ser executada e est presente somente para que seja redefinida em todas as classes
derivadas. A funo serve somente para prover uma interface polimrfica para as classes derivadas.
A funo print() pode ser definida como virtual pura da seguinte forma:
virtual void print() =0;

O sinal de igual (=) e o valor 0 no tm nenhum efeito aqui. A sintaxe (=0) usada somente
para indicar ao compilador que esta uma funo virtual pura, e no tem corpo.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
133

Curso de Linguagem Computacional C/C++

Uma classe que no pode ser utilizada para criar objetos dita classe abstrata e existe
somente para ser usada como base para outras classes. A classe que define uma funo virtual pura
uma classe abstrata pois no se pode declarar nenhum objeto dela. Entretanto, um ponteiro para
uma classe abstrata pode ser declarado para manipular objetos de classes derivadas. Toda classe que
contm pelo menos uma funo virtual pura ou uma classe derivada que no redefine a funo
virtual pura de sua classe-base abstrata.

17.2 Destrutores Virtuais


Se destrutores so definidos na classe-base e na classe derivada, eles so executados na
ordem reversa qual o construtor executado. Quando um objeto da classe derivada destrudo, o
destrutor da classe derivada chamado e em seguida o destrutor da classe-base chamado.
Esta ordem no mantida quando um ponteiro para a classe-base contm um objeto de uma
classe derivada. Se o operador delete aplicado a um ponteiro da classe-base, o compilador chama
somente o destrutor da classe-base, mesmo que o ponteiro aponte para um objeto da classe
derivada.
A soluo declarar o destrutor da classe-base virtual. Isto faz com que os destrutores de
todas as classes derivadas sejam virtuais, mesmo que no compartilhem o mesmo nome do destrutor
da classe-base. Ento, se delete aplicado a um ponteiro para a classe-base, os destrutores
apropriados so chamados, independentemente de qual tipo de objeto apontado pelo ponteiro.
class Base
{
public:
};

virtual ~Base(); // destrutor virtual

A classe Base tem um destrutor virtual, mesmo sendo um destrutor que no faz nada.
Sempre que voc escrever uma classe que tem uma funo virtual, ela deve ter um destrutor virtual
mesmo que no necessite dele. A razo disto que uam classe derivada pode necessitar de um
destrutor. Se um destrutor virtual est definido na classe-base, voc assegura que destrutores de
classes derivadas so chamados na ordem necessria. Observe que, enquanto os destrutores podem
ser virtuais, os construtores no devem ser.

17.3 Classe-Base Virtual


Alm de declarar funes virtuais, podemos usar a palavra virtual para declarar uma classe
inteira. A necessidade de declarar uma classe virtual quando esta foi usada como classe-base para
mais de uma clase derivada e dessas classes derivadas foi derivada outra por meio de herana
mltipla. Uma classe-base no pode ser usada mais de uma vez numa mesma classe derivada.
Entretanto, uma classe-base pode ser indiretamente usada mais de uma vez em classes derivadas.
Observe a classe Super do exemplo abaixo:
#include <iostream>
using namespace std;
class Base {
protected: int valor;
public:
Base(int n = 0) {valor = n;}
virtual void Print() { cout <<
valor; }
};
class Deriv1 : virtual public Base {
public:
Deriv1(int n = 0) : Base(n)
{ }

"\nValor

"

<<

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
134

Curso de Linguagem Computacional C/C++

};
class Deriv2 : virtual public Base {
public:
Deriv2(int n = 0) : Base(n)
{ }
};
class Super : public Deriv1, public Deriv2
{
public:
Super(int n = 0) : Base(n) { }
int RetValor() { return valor; }
void Print()
{ cout << "\nValor do Super-Objeto : " << valor; }
};
int main(int argc, char* argv[])
{
Base
B(5);
Deriv1 D1(10);
Super S(343);
B.Print();
D1.Print();
S.Print();
return 0;
}

Neste caso, cada objeto da class Super poderia ter dois sub-objetos da classe Base. Se um
objeto da classe Super tentasse acessar dados ou funes da classe Base, ocorreria um erro de
ambiguidade. A declarao virtual nas classes Deriv1 e Deriv2 faz com que estas classes
compartilhem uma nica classe-base. A classe Super s ter um subobjeto da classe Base e no ter
mais nenhum problema de ambigidade.
Os construtores de classes-base so sempre executados antes do construtor da classe
derivada. Os construtores de classes-base virtuais so chamados antes de qualquer construtor de
classes-bases no-virtuais.

17.4 Funes Amigas


O conceito de isolamento interno dos itens de uma classe, onde funes no-membros no
teriam o privilgio de acesso aos dados privados ou protegidos desta classe, violado por um
mecanismo oferecido por C++ que permite que funes no-membro, s quais foi dada uma
permisso especial, tenham acesso parte interna da classe. Declarando uma funo como amiga,
ela tem os mesmos privilgios de uma funo-membro, mas no est associada a um objeto da
classe. No programa abaixo apresentamos a sintaxe das funes amigas:
// Uso de funcoes amigas
#include <iostream>
#include <strstrea>
using namespace std;
class Data; // Declara que existe esta classe
class Tempo
{
private:
long h, min, s;
public:
Tempo(long hh = 0, long mm = 0, long ss = 0)
{ h = hh; min = mm; s = ss; }
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
135

Curso de Linguagem Computacional C/C++

friend char * PrintTime( Tempo &, Data &);


};
class Data
{
private:
int d, m, a;
public:
Data(int dd = 0, int mm = 0, int aa = 0)
{ d = dd; m = mm; a = aa; }
friend char * PrintTime( Tempo &, Data &);
};
char * PrintTime( Tempo & Tm, Data & Dt) // Funo global e amiga
{
char * temp = new char[50];
memset(temp, '\0', 50);
strstream sIO(temp, 50, ios::out);
sIO << "\n Relogio-> \t" << Tm.h << ":" << Tm.min << ":" << Tm.s;
sIO << "\n Data->
\t" << Dt.d << "/" << Dt.m
<< "/" << Dt.a;
return temp;
}
int main(int argc, char* argv[])
{
Tempo Tm( 15, 56, 4);
Data Dt( 9, 5, 2000);
char * str = PrintTime( Tm, Dt);
cout << "\n" << str;
delete str;
return 0;
}

Neste exemplo, queremos que a funo PrintTime() tenha acesso aos dados privados da
classe Tempo e Data. Desta forma, usamos a palavra-chave friend na declarao da funo
friend char * PrintTime( Tempo &, Data &);

Esta declarao pode ser colocada em qualquer posio da classe. No h diferena se for
colocada na parte pblica ou na parte privada da classe. Um objeto Tempo passado como
argumento funo PrintTime(). Este argumento necessrio pois, mesmo quando se d a uma
funo amiga o privilgio de acesso aos dados privados da classe, ela no parte daquela classe,
devendo ser informada sobre qual objeto agir.
A funo PrintTime() cria um objeto da classe strstream. Este objeto atua como se
fosse um objeto cout, entretanto em vez de enviar os dados para a sada padro (tela), ele
armazena estes dados no buffer de caracteres fornecidos ao seu construtor. Esta uma das formas
mais fceis para converter dados de uma classe para texto (ASCII) e armazenar estes dados em um
buffer de caracteres. Note que operamos sob o objeto criado assim como operamos com o objeto
cout. O mesmo princpio pode ser empregado para a leitura de dados armazenados em um buffer
de caracteres, operando-se como se estivssemo utilizando o operador cin.
Funes amigas so muito empregadas quando sobrecarregamos os operadores << e >>
associados aos objetos cout e cin respectivamente. Desta forma definimos o operador << para
imprimir os dados da classe e o operador >> para adquirir os dados da classe. Como, muitas vezes
desejamos que estes operadores tenham acesso aos membros privados da classe, ento devemos
defini-los como funes amigas.
friend ostream & operator <<(ostream & OS, Tempo const & T);
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
136

Curso de Linguagem Computacional C/C++

friend istream & operator >>(istream

& IS, Tempo & T;

Todo e qualquer operador que queremos sobrecarregar como sendo uma funo global (i.e.,
recebe um parmetro se for unrio e dois se for binrio) e queremos permitir que este operador
tenha acesso a membros privados e protegidos de uma dada classe, devemos definir este operador
como sendo uma funo amiga.
No nosso programa exemplo acima, definimos que a funo PrintTime() amiga das
classes Data e Tempo. Para tal, precisamos declarar nas duas classes que esta funo amiga da
classe. Quando declaramos a funo na classe Tempo, estaremos declarando uma funo que
recebe como parmetro um objeto da classe Data desconhecida at ento pelo compilador. Para
evitar que o compilador gere um erro indicando que a classe no existe, devemos declarar no incio
do arquivo que existe a classe Data, e que esta ser definida posteriormente. Fazemos isto atravs
da instruo:
class Data;

17.5 Classes Amigas


Alm de ser possvel declarar funes independentes como amigas, podemos declarar uma
classe toda como amiga de outra. Neste caso, as funes-membro da classe sero todas amigas da
outra classe. A diferena que estas funes-membro tm tambm acesso parte privada ou
protegida da sua prpria classe.
Para modificar o programa anterior e declarar que a classe Data amiga da classe Tempo,
basta retirarmos a declarao da funo amiga PrintTime() da classe Tempo e adicionarmos a
declarao:
friend class Data;
Agora, se definirmos que a funao PrintTime() passa a ser uma funo da classe Data,
ela automaticamente passar a ser amiga da classe Tempo e ter acesso a todos os membros desta
classe.
Uma funo ou classe amiga deve ser declarada como tal dentro da classe em que os dados
sero acessados. Em outras palavras, quem escreve uma classe deve especificar quais funes ou
classes iro acessar a sua parte privada ou protegida. Desta forma, um programador que no tem
acesso ao cdigo-fonte da classe no poder criar uma funo amiga para esta classe. As funes
amigas devem ser declaradas pelo autor da classe. Observe que a palavra chave friend oferece
acesso em uma s direo. Se a classe A amiga da classe B, o inverso no verdadeiro.
Uma funo operadora amiga deve receber no mnimo um argumento objeto. Em outras
palavras, voc no pode criar uma funo operadora binria como operator +() que receba dois
inteiros como argumentos. Esta restrio previne a redefinio de operadores internos da
linguagem. Alguns operadores no podem ser defindos como funes amigas; devem ser definidos
como funes-membro de classe. So eles: atribuio (=), acesso de membros de ponteiros (->),
() e conversores de tipo.

17.6 Exerccios
17.1 Escreva as classes Animal, Vaca, Bufalo e Bezerro, sendo Vaca e Bufalo derivadas de
Animal e Bezerro derivada de Vaca e de Bufalo.
17.2 Modele os elementos Veculos, Moto, Carro Esportivo, Carro de Luxo, Carro Popular,
Perua, Carro Mil, Jipe, Caminho, Onibus e Caminhonete. Utilize a idia do exerccio 16.3. Crie um
programa que controle uma revenda de carros. Tenha uma lista nica contendo todos os veculos a
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
137

Curso de Linguagem Computacional C/C++

venda. Utilize o princpio de um vetor de ponteiros para a classe base e emprege exaustivamente os
conceitos da derivao e de funes virtuais e amigas. Permita que o usurio insira algum veculo
na lista, faa consultas, liste todos os veculos disponveis e retire um veculo da lista.
17.3 Defina uma classe String que sobrecarrega os seguintes operadores para as mais
variadas funes: (+), (==), (!=), (<), (>), (<=), (>=), (<<) e (>>).
17.4 Refaa os exerccos 16.1 e 16.2 empregando o princpios das funes amigas e virtuais.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
138

Curso de Linguagem Computacional C/C++

18 Operaes com Arquivos Iostream


Neste captulo, veremos brevemente as facilidades de C++ para operaes de leitura e
gravao em discos. Comearemos com uma breve descrio das classes usadas para executar esta
tarefa, conhecidas como classes iostream.
Em C++, os objetos stream so o ponto central das classes iostream. Um objeto stream pode
ser pensado como um buffer para o recebimento ou envio de bytes. Desta forma, um arquivo em
disco um objeto stream. O conceito de arquivo ampliado no sentido de considerar arquivos no
somente os que existem em discos mas tambm o teclado, o vdeo, a impressora e as portas de
comunicao. Por exemplo, o objeto cout representa o vdeo (recebimento de bytes) e o objeto cin
representa o teclado (envio de bytes). As classes iostream interagem com esses arquivos.
Diferentes objetos stream so usados para representar diferentes interaes com perifricos
de entrada e sada. Cada stream associado a uma classe particular, caracterizada pelas suas
funes de interface e pelos seu operadores de insero e extrao.
Na Figura 4 apresentamos a hierarquia das classes iostream. Por exemplo, cout um objeto
da classe ostream_withassign que derivada da classe ostream. Similarmente, cin um objeto da
classe istream_withassign que derivada da classe istream. Objetos de destino de bytes usam o
operador de insero <<, membro da classe ostream. Os objetos de origem de bytes usam o
operador de extrao <<, membro da classe istream. Estas duas classes so derivadas da classe ios.
Para descobrir os arquivos que definem estas classes, utilize o help do seu compilador pois a nova
norma ANSI C++ definiu novos nomes para estes headers.

Figura 4 : Hieraquia das Classes Iostream do ANSI C++ obtidas pelo Help do Visual C++ 6.0.

A classe ios a base para todas as outras classes. Ela contm vrias constantes e funesmembro para as operaes de leitura e impresso a todas as outras classes.
As classes iostream e ostream so derivadas de ios e so dedicadas a leitura e impresso,
respectivamente. Suas funes-membro implementam operaes formatadas ou no-formatadas em
objetos stream. A classe istream contm funes como get(), getline(), read(), alm de outras.
Contm ainda a sobrecarga do operador de extrao >>. J a classe ostream contm funes como
put(), write(), alm de outras. Contm ainda a sobrecarga do operador de insero <<. Todo objeto
istream ou ostream contm um objeto streambuf derivado. As classes istream e ostream trabalham
em conjunto com a classe streambuf.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
139

Curso de Linguagem Computacional C/C++

A classe iostream derivada das classes istream e ostream por meio de herana mltipla.
Desta forma, esta classe herda as capacidades tanto de leitura como de impresso. Outras classes
podem ser criadas pelo usurio tendo como base istream e ostream.
As classes istream_withassign e ostream_withassign so usadas para a entrada e a sada
padro. Os objetos cin e cout so objetos destas classes.
As classes istrstream, ostrstream e strstream so usadas na manipulao de buffers de dados:
para leitura, para gravao e para leitura/gravao respectivamente.
As classes ifstream, ofstream e fstream so usadas na manipulao de arquivos em disco
para leitura, para gravao e para leitura e gravao respectivamente.

18.1 Estudo de Caso


Vamos apresentar a leitura e escrita de arquivos a partir de um exemplo. O exemplo tratado
a classe Pessoa definida nos captulos anteirores. A classe em si no apresenta nada de novo,
somente sobrecarregamos os operadores de insero << e extrao >> de dados definidos para
objetos da classe iostream. A sobrecarga destes operadores nos permite o escrita e a leitura
automtica de dados da classe, utilizando-se estes operadores. O header fstream.h foi adicionado
por causa das classes de manipulao de arquivos. Veja o exemplo abaixo.
// Exemplo da class fostream
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
#define

Nome_Size

class Pessoa
{
protected:
char *
int
long int

80

Nome;
Idade;
RG;

public:
Pessoa();
Pessoa(char * aNome, int aId = 0, long int aRG = 0);
Pessoa(Pessoa const & aP);
~Pessoa();
char const * GetNome()
const { return Nome; }
int
GetIdade() const { return Idade; }
long int
GetRG()
const { return RG;
void

GetData();

friend ostream & operator <<(ostream & OS, Pessoa const & P);
friend istream & operator >>(istream & IS, Pessoa & P);
};
Pessoa::Pessoa()
{
Nome = new char[Nome_Size];
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
140

Curso de Linguagem Computacional C/C++

Idade = 0;
RG = 0;
}
Pessoa::Pessoa( char * aNome, int aId, long int aRG)
{
Nome = new char[Nome_Size];
strcpy( Nome, aNome);
Idade = aId;
RG = aRG;
}
Pessoa::Pessoa(Pessoa const & aP)
{
Nome = new char[Nome_Size];
strcpy( Nome, aP.GetNome());
Idade = aP.GetIdade();
RG = aP.GetRG();
}
Pessoa::~Pessoa()
{
if(Nome != 0)
{
delete Nome;
Nome = 0;
}
}
void Pessoa::GetData()
{
cout << "\nNome : ";
cin.getline( (char *)Nome, Nome_Size);
cout << "Idade : ";
cin >> Idade;
cout << "RG : ";
cin >> RG;
}
ostream & operator <<(ostream & OS, Pessoa const & P)
{
OS
<< P.GetNome()
<< "\n" << P.GetIdade()
<< "\n" << P.GetRG();
return OS;
}
istream & operator >>(istream & IS, Pessoa & P)
{
IS.getline( (char *)P.Nome, Nome_Size);
IS >> P.Idade;
IS >> P.RG;
return IS;
}
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
141

Curso de Linguagem Computacional C/C++

int main(int argc, char* argv[])


{
Pessoa Eu("Rodrigo", 20, 231123);
// Escrevendo
ofstream FOut("Teste.TXT", ios::out);
FOut << Eu << "\n Um dia a casa cai! \n "
<< setw(12) << setprecision(3) << 12.2345;
FOut.close();
// Lendo
ifstream FIn;
Fin.open("Teste.TXT", ios::in)
Pessoa Vc;
char Buffer[Nome_Size];
FIn >> Vc;
cout << "\nVoce: \n" << Vc;
while(FIn) //Enquanto nao acabar o arquivo
{
FIn.getline( Buffer, Nome_Size);
cout << "\nBuffer : " << Buffer;
}
FIn.close();
Return 0;
}

Na funao main( ) que aparecem as novidades. Primeiro criamos um objeto Pessoa. Depois
escrevemos este objeto e outros dados em um arquivo e depois prosseguimos com a leitura deste.
Neste programa definimos um objeto chamado Fout da classe ofstream. Inicializamos este
objeto com o nome do arquivo TESTE.TXT. Esta inicializao associa o objeto Fout ao arquivo
em disco TESTE.TXT para gravao e j abre o arquivo. O segundo parmetro indica que o
arquivo ser aberto para a escrita.
Note que escrevemos os dados no arquivo da mesma forma que escrevemos os dados na tela
com cout. Toda formatao e funo vlida para cout tambm pode ser aplicada a FOut. Desta
forma, utilizamos o mesmo operador definido para escrever os dados da classe Pessoa na tela como
em um arquivo. Esta facilidade advm do fato de cout e FOut serem ambos objetos de classes
derivadas da classe ostream.
Aps a escrita dos dados, devemos fechar o arquivo com a funo close(). neste momento
que os dados sero salvos no arquivo. Se voc no fechar o arquivo, os dados somente sero salvos
quando o objeto for destrudo e o arquivo, ento, ser fechado pelo destrutor do objeto.
Para ler o arquivo, criamos um objeto da classe ifstream de nome Fin e associamos este
objeto ao arquivo Teste.TXT atravs da funo open(). O segundo parmetro indica que este
arquivo ser aberto para a leitura. Note que o construtor no abrir nenhum arquivo aqui, somente
aps a chamada a funo open() que o arquivo estar aberto.
Depois utilizamos a sobrecarga do operador >> para fazer a aquisio dos dados da classe
Pessoa contido no referido arquivo e imprimir na tela. Aps termos lidos o dado da classe,
prosseguimos lendo linha por linha do arquivo e escrevendo-a na tela at terminar o arquivo. Note
que fazemos uso da funo getline(), que recebe um buffer como parmetro e adquire uma linha
inteira do arquivo.
Os objetos da classe ifstream tem um valor que pode ser testado para a verificao do fimde-arquivo. O objeto FIn ter o valor zero se o sistema operacional enviar ao program o sinal de

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
142

Curso de Linguagem Computacional C/C++

fim-de-arquivo e um valor no-zero caso contrrio. O programa verifica o trmino do arquivo no


lao while. A funo eof() desta classe poderia ser empregada com o mesmo propsito.
Aps lermos o arquivos, fechamos este atravs da funo close().
Todas as funes definidas para a leitura e escrita em C podem ser empregadas em C++.
Estas funes foram incorporadas nas classes iostream. Verifique com o help do seu compilador as
funes disponveis e verificar esta observao. Por exemplo, o funo put() foi adicionada a
classe ostream, e pode ser acessada da forma:
cout.put(c);

ou

FOut.put(c);

O controle do formato da impresso e leitura pode ser executado por meio dos
manipuladores e flags da classe ios. Estes mecanismos foram apresentados em 13.4 e se aplicam
para todos os objetos streams.

18.2 A funo Open()


Quando usamos um objeto da classe ofstream ou ifstream, necessrio associ-lo a um
arquivo. Esta associao pode ser feita pelo construtor da classe ou usando a funo open(),
membro da classe fstream, numa instruo aps a criao do objeto com o construtor default.
Tanto o construtor como a funo open() aceitam a incluso de um segundo argumento
indicando o modo de abertura do arquivo. Este modo definido por bits de um byte, onde cada um
especifica um certo aspecto de abertura do arquivo. A lista de modos definida na classe ios por
meio de enum open_mode:
Modos
ios::in
ios::out
ios::ate
ios::app
ios::trunc
ios::nocreate
ios::noreplace
ios::binary

Descrio
Abre para leitura (default de ifstream)
Abre para gravao (default de ofstream)
Abre e posiciona no final do arquivo leitura e gravao
Grava a partir do fim do arquivo
Abre e apaga todo o contedo do arquivo
Erro de abertura se o arquivo no existir
Erro de abertura se o arquivo existir.
Abre em binrio (default texto).

Podemos trabalhar com arquivos no modo texto ou no modo binrio, assim como em C.
Lembre-se que o fim de linha em modo texto representado por um nico caractere, enquanto em
modo binrio representado por dois caracteres.
Exemplos:
ifstream fin(Teste.txt, ios::in|ios::binary);
fstream fio; \\ Arquivo para leitura e gravaao!!!!
fio.open(Lista.dat, ios::in|ios::out|ios::ate);

18.3 Testando Erros


Situaes de erros na manipulao de arquivos podem ser previstas verificando-se a palavra
(int) de status da classe ios. A palavra de status pode ser obtida pela funo rdstate(), membro da
classe ios. Os bits individuais do valor retornado podem ser testados pelo operador AND bit-a-bit
(&) e os seguintes valores enumerados:
Bits
ios::goodbit

Funo Comentrio
good() Nenhum bit setado. Sem erros

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
143

Curso de Linguagem Computacional C/C++

ios::eofbit
ios::failbit
ios::badbit

eof()
fail()
bad()

Encontrado o fim-de-arquivo
Erro de leitura ou gravao
Erro irrecupervel

A funo clear(int status) modifica a palavra de status. Se usada sem argumento, todos os
bits de erros so limpos. Do contrrio, os bits setados de acordo com os valores enumerados
escolhidos e combinados pelo operador OR (|):
clear(ios::eofbit | ios::failbit);

18.4 Escrevendo e Lendo em Buffers de Caracteres


As classes iostream interagem com a memria pela mesma sintaxe com a qual interagem
com arquivos de disco. Podemos ler e grava de e para buffers de caracteres na memria do
computador. Veja o exemplo abaixo, onde criamos um objeto ostrstream para criar um buffer e
adicionar dados neste buffer. Depois armazenamos o ponteiro deste buffer em uma varivel. Em
seguida, criamos um objeto istrstream para ler dados do mesmo, passando para o seu construtor o
ponteiro do buffer. Por fim, imprimimos os dados na tela.
// StrStream
#include <iostream>
#include <strstrea>
using namespace std;
int main(int argc, char* argv[])
{
ostrstream OS; // Cria buffer para a escrita
OS << "123.45 \t" << 555.55 << "\t" << 333;
OS << "\n\n Sorte = Estar_Preparado + Oportunidade!";
OS << ends;
char * ptr = OS.str();
double x, y;
int i;
istrstream IS(ptr);
IS >> x >> y >> i;
cout << x << '\t' << y << '\t' << i << '\n' << ptr;
return 0;
}

Note a semelhana da metodologia. O manipulador ends, usando neste exemplo, adiciona o


terminador \0 cadeia de caracteres.
Estas classes podem ser usadas para aproveitarmos os operadores << e >> para converter
qualquer tipo de dado no formato texto ASCII e armazenar em um buffer de caracteres. Este buffer
pode ser utilizado para transmitir estes dados para a tela do micro, ou para uma porta COM ou at
para um outro processo via conexes TCP/IP da internet. Definindo o operador << e >> para toda
classe, definimos um modo padro para a escrita/leitura dos dados de uma classe para um arquivo,
um buffer, ou um canal de I/O qualquer. Esta uma ferramenta muito poderosa que no pode ser
desprezada e, quando bem aproveitada, gera cdigo velozes, simples e com alta flexibilidade.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
144

Curso de Linguagem Computacional C/C++

18.5 Imprimindo em Perifricos


Imprimir dados na impressora exatamente a mesma coisa que gravar dados num arquivo
de disco. O DOS define o nome de alguns perifricos ligados ao computador. Qualquer um deles
pode ser usado em nossos programa como nomes de arquivos. Basta criar um objeto do tipo fstream
(ifstream, ofstream, fstream) e passar como nome do arquivo o nome do perifrico. Depois, toda
operao feita sob este objeto, ir acessar diretamente o perifrico. A tabela seguinte descreve estes
nomes:
Nome
CON
AUX ou COM1
COM2
PRN ou LPT1
LPT2
LPT3
NUL

Descriao
Console (teclado e vdeo)
Primeira porta serial
Segunda porta serial
Primeira porta paralela
Segunda porta paralela
Terceira porta paralela
Perifrico Inexistente

Exemplo:
ofstream oprn(PRN);
ofstream ocom1(COM1);
ifstream ilpt2(LPT2);

18.6 Exerccios
18.1 Refaa os exerccios 14.1, 14.2 e 14.3, salvando os dados em um arquivo. Utilize todos
os conceitos apresentados neste captulo.
18.2 Escreva um programa para banco de dados de uma biblioteca, que tenha uma lista
ligada de livros e estes dados sejam armazenados em um arquivo. Crie uma funo para retirar um
livro do cadastro e apag-lo do arquivo.
18.3 Escreva um programa que continue o anterior e pegue os dados de um livro deste
cadastro, escreva estes dados em um buffer da memria e depois envie este buffer para ser impresso
na impressora.
18.4 Escreva um programa que imprima os dados de um arquivo na tela, 20 linhas por 20
linhas.
18.5 Escreva um programa que converta arquivos criados no modo binrio em arquivos
criados no modo ASCII. Crie outro programa que faa o contrrio.
18.6 Escreva um programa que imprima o tamanho de um arquivo em bytes. O nome do
arquivo deve ser fornecido na linha de comando.
18.7 Escreva um programa que criptografa um arquivo usando o operador complemento bita-bit (~). Quando o programa executado para um arquivo j criptografado, o arquivo recomposto
e volta ao original.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
145

Curso de Linguagem Computacional C/C++

19 Namespaces
Namespace um mecanismo para definir grupos lgicos. Se alguma declarao possuir algo
em comum com um outra dada declarao, ns podemos coloc-las juntas em grupo lgico, ou
namespace. Estes grupos lgicos so criados para evitar que em um software apaream duas classes,
vriaveis ou quaisquer tipos e funes com o mesmo nome. Assim, este grupos so tratados como
um escopo, onde todas as vriaveis, tipos e funes definidas neste escopo, so somente conhecidas
no seu interior. Se, em outra parte do programa aparecer uma outra varivel com o mesmo nome,
estas sero diferencidas por seu escopo, ou seja, pelo namespace (grupo lgico).

19.1 Examplo e Sintaxe


Um namespace um escopo e deve ser usado para criar separaes lgicas em grandes
programas. Como este um escopo, as regras bsicas de escopo so estendidas para o seu caso.
Veja o exemplo:
namespace RobotControler
{
class RobotSensor
{
//declarations and some implementation
};
class RobotDCMotors
{
//declarations and some implementation
};
class RobotMovimentAlgorithm
{
//declarations and some implementation
};
}
namespace RobotVision
{
class RobotEye
{
//declarations and some implementation
};
class RobotImageProcessing
{
//declarations and some implementation
};
}

Para tornar o cdigo claro, ns usualmente declaramos os namespaces e o seu contedo,


entretanto, a implementao deste realizada em outro lugar (arquivo cpp). No podemos esquecer
de qualificar os nomes declarados no namespace com o nome do namespace que o contm:
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
146

Curso de Linguagem Computacional C/C++

Function_type Namespace_Name::function_name(arguments)
{
//declarations and some implementation
}

A sintaxe para a declarao de um namespace :


namespace Namespace_Name
{
//declarations and some implementation
}

19.2 Qualified Names, Using Declarations and Directives


Quando estamos trabalhando em um especfico namespace, podemos usar um nome
declarado em outro namespace atravs da sua qualificao. Veja o exemplo abaixo:
double RobotControler::GetPiece(piece*)
{
//...
for(//...)
switch(RobotEye::SquarePiece)//using RobotEyes qualification
//...
}

Se ns estamos trabalhando em um escopo especfico, e dentro deste utilizamos


constantemente variveis/funes declarados em outro namespace, ns podemos avisar o
compilador que desejamos criar um sinnimo local destas variveis/funes:
double RobotControler::GetPiece(piece*)
{
using RobotEye::SquarePiece;
//...
for(//...)
switch(SquarePiece) // RobotEyes SquarePiece
//...
}

A expresso using-directive nos permite usar as variveis como se estas fossem definidas no
escopo local.
Melhor que isto, se utilizamos constantemente diversas variveis e funes de um dado
namespace, ns podemos empregar uma expresso using-directive para criar um sinnimo local de
todas as variveis/funes deste namespace, facilitando o nosso trabalho:
double RobotControler::GetPiece(piece*)
{
using namespace RobotEye; // make all names from RobotEye
// available in scope
//...
for(//...)
switch(SquarePiece)// RobotEyes SquarePiece
//...
}
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
147

Curso de Linguagem Computacional C/C++

19.3 Prevenindo Conflitos de Nomes


Como os namespaces foram criados para expressas estruturas lgicas, ns devemos tambm
utiliz-los quando pretendemos distinguir diferentes partes do programa, desta forma evitaremos
conflitos com os nomes declarados nestas partes.
Somebody_NeuralNetwork.h
namespace Somebody_NeuralNetwork
{
//declarations and some implementation
}

AnotherOne_NeuralNetwork.h
namespace AnotherOne_NeuralNetwork
{
//declarations and some implementation
}

SomeSourceCode.cpp
{
// some code
//...
AnotherOne_NeuralNetwork::sigmoid_neuron = other_neuron;
/* using qualification to identify variable */
//...
}

Ns poderimos usar tanto o sigmoid_neuron da Somebody_NeuralNetworks ou da


AnotherOne_NeuralNetworks,
mas
optamos
por
usar
a
declarada
em
AnotherOne_NeuralNetworks.

19.4 Namespaces sem Nome


Podemos tambm criar namespaces sem nomes, somente para criar uma relao de escopo:
namespace
{
class RobotControler{//...};
//...
}

esta declarao igual a:


namespace $$$
{
class RobotControler{//...};
//...
}
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
148

Curso de Linguagem Computacional C/C++

e ns podemos acessar os seus termos da seguinte maneira:


using namespace $$$;

note que isto funciona somente para escopos locais.

19.5 Apelidos para Namespace


Nomes de namespace longos podem ser tediantes e chatos para usar:
namespace My_new_and_reviewed_NeuralNetwork {//...}
//...
My_new_and_reviewed_NeuralNetwork::sigmoid_neuron = otherneuron;

Ns podemos manipular isto criando apelidos para os namespaces:


namespace MNR_NeuralNet = My_new_and_reviewed_NeuralNetwork;
//...
MNR_NeuralNet::sigmoid_neuron = otherneuron;

19.6 Declarando Nomes


Ns no podemos nuncar usar uma varivel qualificada que no existe na declarao de um
namespace ou tentar declarar um nome fora do escopo do namespace e tentar us-lo no seu interior.
namespace RobotControler {//...}
int RobotControler::new_name(arguments); //error: new_name doesnt
//exist in RobotControler

19.7 Atualizando Cdigos Antigos


Namespaces so uma maneira fcil de migrar de cdigos antigos para cdigos mais
atualizados sem ter que modificar demasiadamente os programas:
Old_program.h
void funtion(int){//...}
//...

passa para:
New_program.h
namespace newprogram
{
void funtion(int){//...}
//...
}

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
149

Curso de Linguagem Computacional C/C++

19.8 Namespaces so Abertos


Isto significa que ns podemos adicionar nomes para este em diversas declaraes, em
partes distintas do programa:
Arq1.h
namespace NeuralNetwork
{
Neuron* SigmoidNeuron;
}

Arq2.h
namespace NeuralNetwork
{
Neuron* NewNeuron; //now the NeuralNetwork namespace has two
//members SigmoidNeuron and NewNeuron.
}

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
150

Curso de Linguagem Computacional C/C++

20 Templates
Templates fornecem suporte direto para a programao genrica, isto , programao onde
no se conhece a priore o tipo empregado e utiliza-se este como parmetro. O mecanismo de
template permite que um tipo se torne um parmetro na definio de uma classe ou funo.

20.1 ClasseTemplates
Por exemplo, se ns queremos criar uma classe string que fornea operaes bsicas com
caracteres, porm queremos que esta sirva para qualquer tipo de caracter, com sinal ou sem sinal,
caracteres Japoneses, Chineses ou qualquer outro. Assim, ns queremos que esta classe dependa
minimamente de um tipo especfico de caracter. Assim sendo, devemos implement-la de forma
genrica:
template<class Anyone> class String
{
struct Srep;
Srep* rep;
public:
String();
String(const Anyone*);
String(const String&);
Anyone read(int i) const;
//...
};

o prefixo template<class Anyone> usado para expressar que a classe String uma
classe template (genrica) e que o tipo Anyone pertence a sua declarao e implementao, e ser
definido em tempo de compilao.

20.1.1

Especificao

Agora, para a instanciao de um objeto da classe String, especificao, ns podemos


escolher qual o tipo de caracter que ns desejamos utilizar:
String<char> sentence;
String<unsigned char> contents;
String<Japanese_char> cannotunderstand;

20.1.2

Membros da Classe Template

Membros de uma classe template so declarados e definidos exatamente como eles iguais as
definies em classes normais. Se eles so implementados fora da classe template, estes precisam
ser declarados explicitamente com o parmetro da classe template:
template<class Anyone> struct String<Anyone>::Srep
{
Anyone* s; // pointer to elements
int size;
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
151

Curso de Linguagem Computacional C/C++

//...
};
template<class Anyone> Anyone String<Anyone>::read(int i) const
{
return rep->s[i];
}
template<class Anyone> String<Anyone>::String
{
rep = new Srep;
}

20.1.3

ParmetrosTemplate

Uma classe template pode receber tipos de parmetros, tipos ordinrios (int, char, long, etc.)
ou tambm tipos template. As templates podem naturalmente receber diversos tipos de parmetros:
template<class AClass, AClass def_val, String<char> ch> class Cont
{
//...
};

Com visto, podemos usar argumentos template na definio de parmetros template


subsequentes e em suas implementaes:
template<class That, int x> class Buffer
{
That stack[x];
int size;
public:
Buffer():size(x){}
//...
};
Buffer<char,100> char_buff;
Buffer<AClass,12> aclass_buff;

20.2 Funes Templates


Para muitas pessoas, o mais bvio uso de templates na definio de classes containers
como a vector, map ou a list. Logo aps, surge a necessidade das funes templates, caracterizadas
por manipularem tipos genricos de dados:
template<class ThisOne> void sort(Vector<ThisOne>&); //declaration
void f(Vector<int>& vi, Vector<string>& vs)
{
sort(vi); // sort(Vector<int>&)
sort(vs); // sort(Vector<String>&)
}

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
152

Curso de Linguagem Computacional C/C++

20.2.1 Function Template Arguments


Funes templates so essenciais para escrever algoritmos genricos. A habilidade para
deduzir os argumentos template atravs dos parmetros passados na chamada da funo de crucial
importncia. Atravs da chamada, que o compilador conhece qual o tipo de dado que esta sendo
empregado:
template<class T, int i> T& lookup(Buffer<T,i>& b, const char* p);
class Record
{
const char[12];
//...
};
Record& f(Buffer<Record,128>& buf, const char* pointer)
{
return lookup(buf, pointer);
}

Implicitamente, o compilador pode deduzir que T um Record e que i 128 devido aos
argumentos da funo.
Algumas vezes, deduo implcita no to simples e, muitas vezes, faz-se necessrio uma
definio explcita.
Template<class T, class U> T implicit_cast(U u){return u;}
Void g(int i)
{
implicit_cast(i); //error: cant deduce T
implicit_cast<double>(i); //ok: T is double and U is int
implicit_cast<char,double>(i); //ok: T is chat and U is double
}

20.2.2 Sobreescrevendo Funes Templates


Funes templates tambm podem ser sobreescritas:
template<class T> T sqrt(T);
template<class T> complex<T> sqrt(complex<T>);
double sqrt(double);
void f(complex<double> z)
{
sqrt(2);
// sqrt<int>(int)
sqrt(2.0);
// sqrt(double)
sqrt(z);
// sqrt<double>(complex<double>)
}

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
153

Curso de Linguagem Computacional C/C++

20.3 Especializao
Por default, uma template fornece uma definio singular para ser usada para todos os
argumentos templates que o usurio possa pensar. Porm, algumas vezes, ns podemos querer tratar
diferenciadamente de acordo com o tipo, como: se o argumento template um ponteiro, faa isso,
se um double, faa aquilo, ou ainda mais, se for um tipo especfico, realize tal tarefa.
template<class T> class Vector
{
T* v;
int size;
public:
Vector();
T& element(int i){return v[i];}
T& operator[](int i);
//...
};

Ns poderamos tornar isto mais especfico para um vetor de ponteiros:


template<class T> class Vector<T*> {//...}; //specialized for pointers

Ns poderamos ir alm e tornar especfico para ponteiros do tipo void:


template<> class Vector<void*> {//...}; //specialized for void pointers

O prefixo Template<> diz que esta uma especializao que pode ser especificada sem o
parmetro template, por que o parmetro especfico j esta inserido nos <> aps o nome da classe.
As declaraes de especializao tm preferncia em relao as demais.
Ns tambm podemos especializar funes template:
template<class T> bool less(T a, T b) {return a<b;} //generic
template<> bool less<const char*>(const char* a, const char* b)
{return strcmp(a,b)<0;} //for const char*
template<> bool less<>(const char* a, const char* b)
{return strcmp(a,b)<0;} //for const char*, blank brackets(redundant)
//because of implicit recognition of types
//from function arguments
template<> bool less<>(const char* a, const char* b)
{return strcmp(a,b)<0;} //for const char*,best declaration

20.4 Derivao e Templates


Templates e derivaes so mecanismos para construode novos tipos, e para escrita de
cdigos uteis que empregam vrias formas com as mesmas funcionalidades.
Podemos derivar uma classe template da seguinte maneira:
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
154

Curso de Linguagem Computacional C/C++

template<class T> class Vector<T*>:private Vector<void*>{//...};

20.5 Polimorfismo
Polimorfismo est presente em ambas classes abstratas e templates. A implementao de
cdigos de templates idntica para todos os tipos de parmetros. Por outro lado, as classes
abstratas definem uma interface comum para todas as classes derivadas.
Como ambas permitem que um algoritmo possa ser definido uma vez e aplicado para
diferentes tipos, ns podemos defini-las como polimrficas. Para distingui-las, o que funes
virtuais realizam chamado polimorfismo em tempo de execuo, e o que as templates realizam
chamado de polimorfismo em tempo de compilao ou polimorfismo paramtrico.
Para escolher entre as duas opes, ns precisamos analisar o seguinte:
se nenhuma relao hierrquica entre os objetos necessrio, melhor usar templates;
se os tipos de dados dos objetos no so conhecidos em tempo de compilao, ento
melhor represent-los por classes derivadas de uma classe abstrata.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
155

Curso de Linguagem Computacional C/C++

21 Conteiner
Um container um objeto que contm outros objetos. Exemplos so listas, vetores e arrays
associativos. Em geral, voc pode adicionar objetos a um container e remover objetos dele.
Estes elementos podem ser de qualquer tipo de objeto que tenha um construtor default, um
destruidor e um operador de atribuio.

21.1 Iteradores
Para ter acesso ao contedo dos containeres da mesma maneira com que se acessa arrays
convencionais, necessrio o uso de iteradores. Eles nos possibilitam navegar no contedo dos
containeres sem nos preocupar com seu contedo. A STL inclui vrios tipos de iteradores, incluindo
iteradores de acesso aleatrio, reversos e iteradores iostream.

21.2 Tipos de Conteineres


21.2.1 Conteineres Seqenciais
So objetos que armazenam outros objetos num arranjo estritamente linear.
vector<T> : Permite o acesso aos dados como se fosse um array para uma seqncia
de dados de tamanho varivel, com inseres e destruies no final com tempo
constante;
deque<T> : Permite o acesso aleatrio uma seqncia de dados de tamanho
varivel, com inseres e destruies com tempo constante no incio e no final;
list<T> : Permite o acesso aos dados em tempo linear para uma seqncia de dados de
tamanho varivel, com inseres e destruies de tempo constante em qualquer ponto da
seqncia.

21.2.2 Contineres Associativos:


Possibilitam uma rpida recuperao de objetos da coleo baseado em chaves. O tamanho
da coleo pode variar em tempo de execuo. A coleo mantida em ordem baseado em um
objeto funo de comparao do tipo Compare :
set<T, Compare> : Suporta chaves nicas (contm no mximo uma chave com cada
valor) e d acesso rpido para recuperas as chaves;
multiset<T, Compare> : Suporta chaves duplicadas (pode conter mltiplas
cpias do mesmo valor de chave) e d acesso rpido para recuperas as chaves;
map<T, Compare> : Suporta chaves nicas (contm no mximo uma chave com
cada valor) e d acesso rpido a outro tipo T baseado nas chaves;
multmap<T, Compare> :Suporta chaves duplicadas (pode conter mltiplas cpias
do mesmo valor de chave) e d acesso rpido a outro tipo T baseado nas chaves.

21.3 Exemplo de Conteiner


No seguinte exemplo, um vetor v construdo e algumas operaes so feitas com ele.
#include <iostream>
#include <vector>
using namespace std;
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
156

Curso de Linguagem Computacional C/C++

void pause()
{
char lixo;
cout << "\nPress any key to continue";
cin >> lixo;
}
void printvector(vector<int> v)
{
int i=0;
cout << "Vector: ";
for (i=0; i < v.size(); i++)
cout << v[i] << " ";
cout << "\n";
}
int main(int argc, char* argv[])
{
cout << "Programa exemplo de contaneres\n\nvector<int> v(3,2)\n";
vector< int > v(3,2);
// Declara v como container vector do tipo int
printvector(v);
pause();
cout << "\nv.push_back(5);
// Insere o elemento 5 no final da sequencia\n";
v.push_back(5);
// Insere o elemento 5 no final da sequencia
printvector(v);
pause();
cout << "\nInserindo mais elementos...\n";
v.push_back(3);
v.push_back(7);
v.push_back(15);
v.push_back(1);
printvector(v);
pause();
cout << "\nv.pop_back(5);
// Apaga o elemento do final da sequencia\n";
v.pop_back();
// Apaga o elemento do final da sequencia
printvector(v);
pause();
return 0;
}

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
157

Curso de Linguagem Computacional C/C++

22 Exceptions Handling
Mesmo aps o esforo de depurao da lgica e do cdigo do software, situaes
excepcionais no previstas podem ocorrer durante a execuo do programa e fazerem com que o
programa incorra em erros ou at mesmo termine abruptamente.
Embora de tais situaes, como falta de memria, entrada de dados incorretos, perda de
linha do modem, disco fora da unidade, arquivo inexistente, entre outras, no possam ser evitadas
pelo programador, ele deve se preparar para trat-las da melhor maneira possvel se por ventura
vierem a ocorrer.
As opes existentes quando da ocorrncia de algum evento como esse so:
Derrubar o programa;
Informar a ocorrncia ao usurio e finalizar o programa;
Informar a ocorrncia ao usurio e permitir que ele tente reparar o erro e continuar a
execuo do programa;
Executar uma ao corretiva automtica e prosseguir sem avisar o usurio.
Derrubar o programa o que acontece por default quando uma exceo no chamada
entretanto, para a maioria dos erros possvel fazer melhor que isto.
No caso de chamadas de funes que retornam algo, no se pode checar os valores a cada
chamada, pois isso pode facilmente dobrar o tamanho do programa.
O Tratamento de Excees do C++ possibilita ao programador combater e tratar da melhor
forma essas ocorrncias, que apesar de inslitas, podem, na maioria das vezes, serem previstas
durante a fase de projeto do software.

22.1 Exceo
Em C++ uma exceo um objeto que passado da rea de cdigo onde ocorre um erro
(geralmente em um nvel muito baixo do programa) para a parte do cdigo que ir tratar o problema
(normalmente um nvel mais alto do programa, com cdigo para interao com o usurio).

22.2 Como as excees so usadas


Blocos try so criados para cercar reas de cdigo que podem conter um problema, da
seguinte maneira:
try
{
Funo_Perigosa();
}

Blocos catch tratam as excees aplicadas ao bloco-try:


try
{

// como feito anteriormente


Funo_Perigosa();

}
catch(SemMemoria)
{
//Aes a serem tomadas
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
158

Curso de Linguagem Computacional C/C++

}
catch(ArquivoNaoEncontrado)
{
//Outras aes
}

Os passos bsicos da utilizao de excees so:


1. Identificar aquelas reas do programa nas quais existe uma operao que pode levantar
uma exceo e inser-las em um bloco try. interessante ressaltar que essa tarefa pode
ser uma das mais trabalhosas do processo de tratamento do excees.
2. Criar tantos blocos catch quanto necessrios para apanhar as excees que forem
aplicadas, limpar a memria alocada e passar as informaes apropriadas ao usurio.
Os blocos try cercam as reas do cdigo onde podem ocorrer problemas, entretanto
preciso que as funes ou sub funes chamadas nessas reas estejam aptas a requisitar a exceo
caso acontea algum evento inesperado. A exceo e aplicada utilizando a instruo throw, que
pode passar qualquer tipo C++, inclusive objetos, para serem tratados por catch.
O tratador chamado somente se o tipo passado por throw o mesmo tipo aceito por catch.
Quando da chamada de um catch por um throw , feita uma cpia do objeto passado para o
tratador.
O exemplo de cdigo a seguir demonstra o uso do tratamento de excees:
#include <iostream>
usind namespace std;
void S2iFunc( void );
class S2iTest
{
public:
S2iTest(){};
~S2iTest(){};
const char* ShowReason() const { return "Exceo na classe S2iTest!";}
};
class S2iDemo
{
public:
S2iDemo();
~S2iDemo();
};
S2iDemo:: S2iDemo()
{
cout << "Construindo S2iDemo." << endl;
}
S2iDemo::~ S2iDemo()
{
cout << "Destruindo S2iDemo." << endl;
}

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
159

Curso de Linguagem Computacional C/C++

void S2iFunc()
{
S2iDemo D;
// cria um objeto da classe S2iDemo
cout<< "Em S2iFunc(). Throwing a exceo S2iTest." << endl;
throw S2iTest(); //Envia um objeto da classe S2iTest para o tratador
}
int main(int argc, char* argv[])
{
cout << "Estamos em main." << endl;
try
{
cout << "No bloco try, chamando S2iFunc()." << endl;
S2iFunc();
}
catch( S2iTest E )
//Recebe um objeto da classe S2iTest
{
cout << "Estamos no tratador catch." << endl;
cout << "Tratando exceo do tipo S2iTest: ";
cout << E.ShowReason() << endl;
}
catch( char *str )
{
cout << "Trata outra exceo " << str << endl;
}
cout << "De volta a main. Execucao termina aqui." << endl;
return 0;
}

Sada do programa:
Estamos em main.
No bloco try, chamando S2iFunc().
Construindo S2iDemo.
Em S2iFunc(). Throwing a exceo S2iTest.
Destruindo S2iDemo.
Estamos no tratador catch.
Tratando exceo do tipo S2iTest:
Exceo na classe S2iTest !
De volta a main. Execucao termina aqui.

22.3 Biblioteca Except <except.h>


Esta biblioteca d suporte para excees em ANSI C++. Algumas funes dessa classe so
descritas a seguir.

22.3.1 Terminate()
void terminate();

A funo terminate() pode ser chamada por outra funo (como unexpected) ou pelo
programa quando um tratador para uma exceo no for encontrado. A ao default para terminate
chamar abort, causando imediatamente o trmino do programa.
O modo de trmino pode ser modificado utilizando-se de set_terminate.
terminate() no retorna valor pois uma funo void.
________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
160

Curso de Linguagem Computacional C/C++

22.3.2 Set_terminate()
typedef void (*terminate_function)();
terminate_function set_terminate(terminate_function t_func);

Permite criar uma funo que define o comportamento do trmino do programa se um


tratador de exceo no for encontrado.
As aes a serem realizadas em tal situao so definidas em t_func, que declarada como
uma funo do tipo terminate_function. O tipo terminate_function definido em <except.h> e
uma funo que no recebe argumentos e retorna void.
Se nenhum tratamento de exceo for encontrado, por default o programa chama a funo
terminate, resultando normalmente numa chamada para abort. Se o programador desejar uma outra
ao, deve defini-la na funo t_fun, que ser instalada por set_terminate como a funo de termino.

22.3.3 Unexpected()
void unexpected();

Se uma funo envia uma exceo que no esta definida o programa chama unexpected. Se
nenhuma ao especifica e definida por set_unexpected, a funo unexpected chama terminate.

22.3.4 Set_unexpected()
typedef void ( * unexpected_function )();
unexpected_function set_unexpected(unexpected_function unexpected_func)

Essa funo permite criar uma funo que define o comportamento do programa se uma
funo envia (throw) uma exceo no especificada. As aes so definidas em
unexpected_function.
O tipo unexpected_function est definido em <except.h> e no recebe argumentos e
retorna void.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
161

Curso de Linguagem Computacional C/C++

Trabalho 1
Crie um programa que desenhe na tela o seu quadro de horrios deste semestre.

Trabalho 2
A decomposio LDU uma decomposio famosa de matrizes aplicada para calcular
inversas de matrizes e resolver problemas de equaes lineares. Utilize o programa 9.1 e crie um
programa que calcule a decomposio LDU de uma matriz, preferencialmente, com pivotamento.

Trabalho 3
Crie um programa que faa o controle de cadastro de usurios e controle de alocao para
uma locadora de fitas de vdeo. Utilize uma classe para os clientes e outra para as fitas, e emprege o
mtodo da lista ligada para gerenciar um vetor dinmico. O usurio de poder incluir/retirar um
cliente ou uma fita, fazer uma pesquisa, pedir a lista de clientes e a lista de fitas ou alterar algum
parmetro destas.

Trabalho 4
Este problema foi retirado do livro Fundamentos da Automao Industrial Pneutrnica
de Arno Bollmann (Professor da UFSC, Ed. ABHP So Paulo). O objetivo aqui utilizar uma
ferramenta orientada a objetos para modelar, analisar e controlar um sistema pneumtico
automatizado. Enfocando a aplicao desta ferramenta na anlise e desenvolvimento de sistemas
automatizados. A ferramenta aplicada ser a programao orientada a objetos em C++ juntamente
com a tcnica de modelagem UML.

Manipulao de peas: alimentao de uma forja a partir de trs fornos.


Figura 5

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
162

Curso de Linguagem Computacional C/C++

Figura 5 : O problema de manipulao de peas.

Figura 5

Figura 5

Atuador Funo do Manipulador


________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
163

Curso de Linguagem Computacional C/C++

A
B
C
D

E
G

Como o programa deve funcionar:

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
164

Curso de Linguagem Computacional C/C++

Este um desafio para aqueles que querem efetivamente aprender a programar e criar
sistemas orientados a objetos e no serem meros digitadores de cdigos em C. Trabalhe com
profissionalismos e dedicao, faa deste trabalho o seu produto. Dedique a ele o respeito e o
esforo que a tua profisso merece.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
165

Curso de Linguagem Computacional C/C++

Referncias Bibliogrficas
[1] Booch, G.; Jacobson, I. e Rumbaugh, J.: The Unified Modelling Language User Guide,
Ed. Addison Wesley-Logman, 1999.
[2] Booch, G.; Jacobson, I. e Rumbaugh, J.: The Unified Software Development Process, ed.
Addison Wesley Longman, January of 1999.
[3] Borland C++: Programmers Guide, Borland International, USA, 1994.
[4] Borland C++: Users Guide, Borland International, USA, 1994.
[5] Chapman, D.: Teach Yourself Visual C++ 6 in 21 Days, SamsPublishing, 1998.
[6] Douglass, B. P.: Real-Time UML : Developing Efficient Objects for Embedded Systems,
ed. Addison Wesley Longman, August of 1998.
[7] Meyer, Bertrand .: Object-Oriented Software Construction. Ed. Prentice Hall.
[8] Microsoft: MSDN - Microsoft Visual Studio 6.0 Development System Microsoft,
1999.
[9] Mizrahi, Victorine Viviane.: Treinamento em Linguagem C Curso Completo, Mdulo
1, Ed. Makron Books do Brasil, So Paulo,1990.
[10] Mizrahi, Victorine Viviane.: Treinamento em Linguagem C++ - Mdulo 1 e 2, Ed.
Makron Books do Brasil, So Paulo, 1994.
[11] Montenegro, Fernando; Pacheco, Roberto: Orientao a Objetos em C++, Ed. Cincia
Moderna, Rio de Janeiro, 1994.
[12] Petzold, Charles: Programming Windows 95, Microsoft Press, Washington, 1996.
[13] Reidorph, Kent: Teach Yourself Borland C++ Builder 3 in 21 Days, Sams Publishing,
Indianapolis, USA, 1998.
[14] Rumbaugh, J.; Blaha, M.; Premerlan, W.: Eddy, F. e Lorensen, W.: Object-Oriented
Modelling and Design . Ed. Prentice Hall.
[15] Stevens, W. R..: Programmieren von Unix-Netzen Grundlagen, Programmierung,
Anwendung, Ed. Hanser and Ed. Prentice-Hall, 1992.
[16] Stroustrup, B.: C++ Programming Language 3rd Edition, Addison Wesley, 1997.
[17] Swan, Tom: Programao Avanada em Borland C++ 4 Para Windows, Ed. Berkeley
Brasil, So Paulo, 1994.

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
166

Curso de Linguagem Computacional C/C++

Hot Sites

http://www.developer.com/

http://www.borland.com/

http://msdn.microsoft.com/resources/devcenters.asp

http://search.microsoft.com/us/dev/

http://www.rational.com/uml/

http://www.togethersoft.com/together/togetherC.html

http://world.isg.de/world/

http://www.popkin.com/services/enterprise/uml/uml.htm

http://www.ee.cooper.edu/resource/docs/linux/LDP/lpg/node1.html

http://www.geog.leeds.ac.uk/staff/i.turton/unix/course.html

http://www.geog.leeds.ac.uk/staff/i.turton/unix/course.html

http://www.codeguru.com/

http://sf.net/

http://www.bloodshed.net/

http://www.sun.com/staroffice/

http://www.cvshome.org/

http://www.proxysource.com/

http://www.doxygen.org/download.html

http://members.tripod.com/~SoftechSoftware/index.html

http://www.sgi.com/tech/stl/index.html

http://www.wxwindows.org/

http://argouml.tigris.org

http://www.gentleware.com/products/download.php3.

http://www.planetpdf.com/mainpage.asp?webpageid=315

http://doc.lcmi.ufsc.br/bookshelf/

http://www.computer.org/publications/dlib/

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
167

Curso de Linguagem Computacional C/C++

Anexo 1 Metodologia para o Desenvolvimento de


Softwares

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
168

Curso de Linguagem Computacional C/C++

Anexo 2 Sumrio da Modelagem UML

________________________________________________________________________________________________
Sistemas Industriais Inteligentes DAS CTC UFSC
169

This document was created with Win2PDF available at http://www.daneprairie.com.


The unregistered version of Win2PDF is for evaluation or non-commercial use only.

Você também pode gostar