Escolar Documentos
Profissional Documentos
Cultura Documentos
Material de apoio
Curso de C/C++
DINTER
21 a 25 de fevereiro de 2011
Propriedades do documento
Categoria: Apostila
Assunto : Linguagem de programao C/C++
Verso : 1.0
elaborado por
data
27.01.2011
06.02.2011
revisado por
Sumrio
Captulo 1: O bsico de C++ ............................................................................................. 6
1.1.
1.1.1
1.2
Comentrios ................................................................................................... 9
1.2.1
Identificadores.............................................................................................. 10
1.2.2
1.2.3
1.2.4
1.2.5
1.2.6
1.3
Constantes.......................................................................................................... 16
1.3.1
Literais ........................................................................................................ 16
1.3.3
1.4
Operadores ......................................................................................................... 20
1.4.1
Atribuio (=)............................................................................................... 21
1.4.2
1.4.3
Atribuio composta (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=) .................. 23
1.4.4
1.4.5
Operadores relacionais e de igualdade ( ==, !=, >, <, >=, <= ) ........................ 24
1.4.6
1.4.7
1.4.8
1.4.9
1.4.10
1.4.11
sizeof() ........................................................................................................ 27
1.4.12
1.4.13
2.1.1
2.1.2
2.1.3
2.2.1
2.2.2
2.3
2.3.1
2.3.2
2.3.3
2.3.4
Recursividade ............................................................................................... 46
2.3.5
Matrizes ............................................................................................................. 50
3.1.1
3.1.2
3.1.3
3.1.4
3.2
3.2.1
3.2.2
3.3
3.4
Ponteiros ............................................................................................................ 59
3.3.1
3.3.2
3.3.3
3.3.4
3.3.5
Inicializao de ponteiros............................................................................ 65
3.3.6
3.3.7
3.3.8
3.3.9
3.3.10
3.4.1
3.4.2
3.5
3.5.1
3.5.2
3.5.3
3.6
3.6.1
3.6.2
3.6.3
Unies annimas........................................................................................... 82
3.6.4
Algorithms ....................................................................................................... 84
A.2
complex .......................................................................................................... 86
A.3
cmath (math.h)................................................................................................ 87
A.4
cstdio (stdio.h)................................................................................................. 88
A.5
A.6
ctime (time.h).................................................................................................. 92
1
2
3
4
5
6
7
8
9
Hello World!
#include <iostream>
using namespace std;
int main (){
cout << "Hello World!";
return 0;
}
O primeiro quadro (em azul) mostra o cdigo fonte para o nosso primeiro programa. O segundo
(em cinza claro) mostra o resultado do programa quando compilado e executado. esquerda, os
nmeros em cinza representam os nmeros de linha - estas no fazem parte do programa, e so
mostrados aqui apenas para fins informativos.
A maneira de editar e compilar um programa depende do compilador usado pelo programador.
Se ele tem uma interface de desenvolvimento, ou no, e a sua verso. Consulte o manual ou a
ajuda que acompanha o seu compilador caso voc tenha dvidas sobre como compilar um
programa em C ++.
O programa mostrado nos quadros anteriores o tpico programa que os programadores
iniciantes aprendem a escrever pela primeira vez, e seu resultado imprimir na tela a sentena
Hello World!. Este um dos programas mais simples escritos em C++, mas contm os
componentes fundamentais de qualquer programa escrito nesta linguagem. Vamos olhar linha
por linha o cdigo que escrevemos:
#include <iostream>
Linhas comeando com um Cerquilho (#) so diretivas para o
pr-processador. Elas so indicaes para o pr-processador
do compilador e no linhas de cdigo regular. No caso, a
diretiva #include <iostream> diz ao pr-processador para
incluir o arquivo iostream. Este arquivo contm declaraes
da biblioteca bsica de entrada e sada em C++ e includo
pela funcionalidade que ser utilizada em linhas posteriores do
programa.
Pgina | 6 de 93
int main ()
Esta linha corresponde ao incio da definio da funo main.
A funo main o ponto onde todo programa escrito em C++
inicia sua execuo. No importa qual o nmero de funes
que um programa contenha antes, ou depois da funo main,
ou ainda seus nomes, um programa sempre inicia sua
execuo pela funo main.
A palavra main seguida por um par de parnteses (()).
Neste caso trata-se de uma declarao de funo: em C++, o
que diferencia uma declarao de funo de outro tipo de
expresso so os parnteses aps seu nome. Opcionalmente,
estes parnteses podem conter uma lista de parmetros.
Logo aps os parnteses encontramos o corpo do programa. O
corpo do programa apresentado entre duas chaves ({}). O
contedo includo dentro das chaves o que ser executado e
onde ns iremos escrever o cdigo do programa.
return 0;
A instruo return faz com que a funo main termine.
return pode ser seguido por um cdigo de retorno (no nosso
exemplo seguido pelo cdigo de retorno com um valor de
zero). Um cdigo de retorno de 0 para a funo main
geralmente interpretado como um correto e esperado
funcionamento do programa, sem quaisquer erros durante sua
Pgina | 7 de 93
Tudo isso em apenas uma linha tem exatamente o mesmo significado que o cdigo anterior.
Em C++, a separao entre as afirmaes especificada com um ponto e vrgula (;) no final de
cada sentena. Portanto a separao em diferentes linhas de cdigo no importa para essa
finalidade. Podemos escrever muitas declaraes por linha ou escrever uma nica instruo que
tenha muitas linhas de cdigo. A diviso do cdigo em linhas diferentes um recurso para tornar
mais legvel o cdigo para os seres humanos.
Vamos adicionar uma instruo para o nosso primeiro programa:
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;
int main (){
cout << "Hello World! ";
cout << "I'm a C++ program";
return 0;
}
Neste caso, so realizadas duas declaraes do comando cout em duas linhas diferentes. Mais
uma vez, a separao em diferentes linhas de cdigo feita apenas para dar maior legibilidade
ao programa. A funo main poderia ter sido escrita perfeitamente desta maneira:
int main () { cout << " Hello World! "; cout << " I'm a C++ program ";
return 0; }
Pgina | 8 de 93
1.1.1
Comentrios
1 // line comment
2 /* block comment */
O primeiro deles, conhecido como linha de comentrio, descarta tudo, desde a declarao do par
de barras (/ /) at o final dessa mesma linha. O segundo, conhecido como bloco de comentrio,
descarta tudo entre os caracteres /* e a primeira declarao dos caracteres * /, com a
possibilidade de incluir mais de uma linha.
Agora adicionaremos comentrios ao nosso segundo programa:
1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;
Pgina | 9 de 93
1
2
3
4
a = 5;
b = 2;
a = a + 1;
result = a - b;
Obviamente, este um exemplo muito simples, uma vez que s tenho usado dois valores
inteiros pequenos, mas considere que o computador pode armazenar milhes de nmeros como
estes, ao mesmo tempo sofisticado e realizar operaes matemticas com elas.
Portanto, podemos definir uma varivel como uma parte da memria do computador destinada a
armazenar um determinado valor.
Cada varivel precisa de um identificador que o distingue dos demais. Por exemplo, no cdigo
anterior os identificadores de variveis eram a, b e result. No entanto, poderamos ter
atribudo qualquer nome s variveis, desde que sejam identificadores vlidos.
1.2.1
Identificadores
Um identificador vlido em C++ uma sequncia de uma ou mais letras, dgitos ou caracteres
de sublinhado (_). Nem espaos nem sinais de pontuao ou smbolos pode ser parte de um
identificador. Somente letras, nmeros e caracteres de sublinhado simples so vlidos. Alm
disso, os identificadores de varivel sempre tem que comear com uma letra ou caractere
sublinhado (_), mas em alguns casos, estes podem ser reservados para determinadas palavraschave do compilador ou identificadores externos, bem como identificadores contendo dois
sucessivos caracteres de sublinhado em qualquer lugar. Em nenhum caso, um identificador pode
comear com um dgito.
Outra regra que voc deve considerar ao inventar seus prprios identificadores que eles no
podem corresponder a qualquer palavra-chave da linguagem C + + ou do compilador, que so
palavras reservadas consideradas especiais. As palavras-chave reservadas padro so:
asm, auto, bool, break, case, catch, char, class, const, const_cast,
continue, default, delete, do, double, dynamic_cast, else, enum,
explicit, export, extern, false, float, for, friend, goto, if, inline,
Pgina | 10 de 93
and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq
Seu compilador pode tambm incluir algumas palavras-chave especficas adicionais.
MUITO IMPORTANTE: A linguagem C++ "case sensitive". Isso significa que um identificador
escrito em letras maisculas no equivalente a outro com o mesmo nome mas escrito em
letras minsculas. Assim, por exemplo, a varivel RESULT no a mesma que a varivel
result ou a varivel Result. So trs identificadores de variveis diferentes.
1.2.2
Description
Size*
char
1byte
short int
Short Integer.
(short)
int
Integer.
signed:
-2147483648
to
2147483647
unsigned: 0 to 4294967295
signed:
-2147483648
to
2147483647
unsigned: 0 to 4294967295
4bytes
4bytes
float
double
8bytes
long
double
Long double
number.
8bytes
wchar_t
Wide character.
precision
floating
point
2 or
bytes
127
2bytes
long
int
Long integer.
(long)
bool
Range*
signed:
-128
to
unsigned: 0 to 255
true or false
+/- 3.4e +/- 38 (~7 digits)
+/- 1.7e +/- 308 (~15
digits)
+/- 1.7e
digits)
4
+/-
308
(~15
1 wide character
Pgina | 11 de 93
* Os valores das colunas Size e Range dependem do sistema em que o programa compilado.
Os valores apresentados acima so os encontrados na maioria dos sistemas de 32 bits. Mas para
outros sistemas, a especificao geral que int tem o tamanho natural sugerido pela
arquitetura do sistema (uma "palavra") e os quatro tipos de inteiros char, short, int e long
devem ser de cada um, pelo menos, to grande quanto o anterior. No entanto, o char ser
sempre de um byte de tamanho. O mesmo se aplica aos tipos de ponto flutuante float,
double e long double, onde cada um deve fornecer pelo menos tanta preciso como o
anterior.
NOTA: Para variveis do tipo complexo veja o anexo A.2.
1.2.3
A fim de usar uma varivel em C++, devemos primeiro declar-la especificando que tipo de
dados que queremos armazenar. A sintaxe para declarar uma nova varivel escrever o
especificador do tipo de dados desejado (como, bool int, float ...) seguido por um identificador
de varivel vlido. Por exemplo:
1 int a;
2 float mynumber;
Estas so duas declaraes vlidas de variveis. O primeiro declara uma varivel do tipo int
com o identificador a. O segundo declara uma varivel do tipo float com o identificador
mynumber. Uma vez declaradas, as variveis a e mynumber podem ser usadas no resto do
programa.
Se voc deseja declarar mais de uma varivel do mesmo tipo, voc pode declarar todas elas em
uma nica instruo, separando seus identificadores com vrgulas. Por exemplo:
int a, b, c;
Este cdigo declara trs variveis (a, b e c), todas do tipo int, e tem exatamente o mesmo
significado que:
1 int a;
2 int b;
3 int c;
Aos tipos de dados inteiros char, short, long e int podem ser atribudos os especificadores
signed (com sinal) ou unsigned (sem sinal). Se atribuirmos o especificador signed, a uma
determinada varivel, esta poder representar tanto valores positivos quanto negativos. Se
atribuirmos o especificador unsigned somente valores positivos (e zero) sero permitidos.
Ambos os especificadores (signed ou unsigned) devem ser declarados antes do nome do tipo
da varivel. Por exemplo:
Pgina | 12 de 93
int MyAccountBalance;
short e long podem ser usados sozinhos como especificadores de tipo. Neste caso, eles se
referem a seus respectivos tipos inteiros: short equivalente a short int e long
equivalente a long int. As duas seguintes declaraes de variveis so equivalentes:
1 short Year;
2 short int Year;
Finalmente, signed e unsigned tambm podem ser usados como especificadores de tipo, e
possuem o mesmo significado que signed int e unsigned int, respectivamente. As duas seguintes
declaraes so equivalentes:
1 unsigned NextYear;
2 unsigned int NextYear;
Para ver como as declaraes de variveis aparecem dentro de um programa, vamos observar o
cdigo C++ a seguir, sobre o exemplo da memria proposto no incio desta seo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
int main (){
// declaring variables:
int a, b;
int result;
// process:
a = 5;
b = 2;
a = a + 1;
result = a - b;
// print out the result:
cout << result;
// terminate the program:
return 0;
}
Pgina | 13 de 93
No se preocupe se algumas das declaraes, alm das variveis, parecem um pouco estranhas
para voc. Voc vai ver o restante das definies em detalhes nas prximas sees.
1.2.4
Todas as variveis que pretendemos usar em um programa devem ter sido declaradas com um
especificador de tipo em algum ponto anterior no cdigo, como fizemos no cdigo anterior, no
incio do corpo da funo main, quando declaramos a, b, e result do tipo int.
Uma varivel pode ser local ou global. Uma varivel global uma varivel declarada no corpo
principal do cdigo-fonte, fora de todas as funes, enquanto uma varivel local declarada
dentro do corpo de uma funo especfica ou um bloco.
As variveis globais podem ser referidas em qualquer lugar do cdigo (dentro de funes)
sempre aps a sua declarao.
O escopo das variveis locais limitado ao bloco entre chaves ({}) onde elas so declaradas.
Por exemplo, se elas so declaradas no incio do corpo de uma funo (como na funo main),
seu alcance entre a sua declarao e final dessa funo. No exemplo acima, isto significa que,
se existisse outra funo alm da main, as variveis locais declaradas dentro da funo main
no poderiam ser acessadas dentro da outra funo e vice-versa.
1.2.5
Quando declaramos uma varivel, seu valor , por padro, indeterminado. Mas voc pode querer
uma varivel para armazenar um valor no mesmo momento em que declarada. Para fazer
isso, voc pode inicializar a varivel. H duas maneiras de fazer isso em C++:
O primeiro, conhecido como c- inicializao, realizada acrescentando um sinal de igual seguido
do valor para o qual a varivel ser inicializada:
Pgina | 14 de 93
Por exemplo, se quisermos declarar uma varivel do tipo int, denominada a, e inicializada com
um valor de 0, no momento em que for declarada, podemos escrever:
int a = 0;
int a (0);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// initialization of variables
#include <iostream>
using namespace std;
int main (){
int a=5;
// initial value = 5
int b(2);
// initial value = 2
int result; // initial value undetermined
a = a + 3;
result = a - b;
cout << result;
return 0;
}
1.2.6
Variveis que podem armazenar valores no-numricos que so mais do que um caractere nico
so conhecidos como cadeias de caracteres.
A biblioteca da linguagem C++ oferece suporte para a utilizao de cadeias de caracteres
atravs da classe padro string (veja o anexo A.7). Este no um tipo fundamental, mas ele
se comporta de forma semelhante aos tipos fundamentais, o que simplifica sua utilizao.
A primeira diferena com tipos de dados fundamentais que, a fim de declarar e utilizar objetos
(variveis) desse tipo preciso incluir um arquivo de cabealho adicional em nosso cdigo fonte:
<string> e ter acesso ao espao de nomes std (que j tnhamos em todos os nossos
programas anteriores graas ao uso do using namespace std).
1
2
3
4
// my first string
#include <iostream>
#include <string>
using namespace std;
This is a string
Pgina | 15 de 93
5
6
7
"This
is
Como voc pode ver no exemplo anterior, strings podem ser inicializados com qualquer cadeia
de caracteres vlida, como varivel do tipo numrica pode ser inicializada com qualquer valor
numrico vlido. Ambos os formatos so vlidos de inicializao em strings:
Strings tambm podem executar todas as operaes bsicas de outros tipos de dados
fundamentais como ser declarada sem um valor inicial e atribuir valores durante a execuo:
1
2
3
4
5
6
7
8
// my first string
#include <iostream>
#include <string>
using namespace std;
9
10
11
12
13
1.3 Constantes
Constantes so expresses que possuem um valor fixo.
1.3.1
Literais
Literais so os tipos mais bvios de constantes. Eles so usados para expressar valores
especficos dentro do cdigo fonte do programa. Ns j usamos os literais anteriormente para
dar valores s variveis ou para expressar as mensagens que queramos que nosso programa
imprimisse, por exemplo, quando escrevemos:
a = 5;
Pgina | 16 de 93
Numerais inteiros
1 1776
2 707
3 -273
Eles so constantes numricas que identificam valores decimais inteiros. Repare que para
expressar uma constante numrica no temos que escrever aspas (") nem qualquer caractere
especial. No h dvida de que representamos uma constante ao escrever 1776 em um
programa, estaremos nos referindo ao valor 1776.
Alm de nmeros decimais (aqueles que todos ns estamos acostumados a usar todos os dias),
C++ permite o uso de nmeros octais (base 8) e nmeros hexadecimais (base 16) como
constantes literais. Se quisermos expressar um nmero octal temos de preced-lo com um 0
(um caractere zero). E a fim de expressar um nmero hexadecimal temos de preced-lo com os
caracteres 0x (zero, x). Por exemplo, as seguintes constantes literais so todas equivalentes
entre si:
1 75
2 0113
3 0x4b
// decimal
// octal
// hexadecimal
Todos estes representam o nmero 75 (setenta e cinco), expresso como uma base-10, octal e
hexadecimal, respectivamente.
Constantes literais, como as variveis, so considerados como um tipo de dado especfico. Por
padro, literais inteiros so do tipo int. No entanto, pode forar o sistema a ser signed,
anexando o carter u a ele, ou long, acrescentando l:
1
2
3
4
75
75u
75l
75ul
//
//
//
//
int
unsigned int
long
unsigned long
Em ambos os casos, o sufixo pode ser especificado usando tanto letras maisculas quanto
minsculas.
1
2
3
4
3.14159
6.02e23
1.6e-19
3.0
//
//
//
//
3.14159
6.02 x 10^23
1.6 x 10^-19
3.0
Pgina | 17 de 93
Na figura acima so expressos quatro nmeros decimais vlidos em C++. O primeiro nmero
PI, o segundo o nmero de Avogadro, o terceiro a carga eltrica de um eltron (um nmero
extremamente pequeno) todos valores aproximados e o ltimo o nmero trs, expresso
como um ponto flutuante literal numrico. OBS: a constante PI pode ser facilmente calculada
por meio da seguinte expresso PI = 4 * atan( 1.0 ), em que atan o arco tangente.
O tipo padro para literais de ponto flutuante o dobro. Se voc quer expressar explicitamente
um nmero como float ou long double, voc pode usar os sufixos f ou l, respectivamente:
1 3.14159L
2 6.02e23f
// long double
// float
Qualquer das letras que podem ser parte de uma constante de ponto flutuante (e, f, l) pode ser
escrito usando letras maisculas ou minsculas, quer sem qualquer diferena em seus
significados e/ou interpretao pelo compilador.
1
2
3
4
'z'
'p'
"Hello world"
"How do you do?"
1x
2 'x'
Na primeira linha x (sem aspas) remete para uma varivel cujo identificador x, enquanto que
'x' (entre aspas simples) remete para o carcter constante 'x'.
Caracteres e strings tm certas peculiaridades, como os cdigos de escape. Estes so
caracteres especiais que so difceis ou impossveis de expressar de outra forma no cdigo fonte
de um programa, como nova linha (\ n) ou tabulao (\ t). Todos eles so precedidos por uma
barra invertida (\) ao cdigo. Aqui voc tem uma lista de alguns:
\n newline
\r carriage return
\t Tab
\v vertical tab
\b backspace
Pgina | 18 de 93
Por exemplo:
1
2
3
4
'\n'
'\t'
"Left \t Right"
"one\ntwo\nthree"
Alm disso, voc pode expressar qualquer caractere atravs de seu cdigo ASCII, escrito por
meio de uma barra invertida (\) seguido do cdigo ASCII expresso como um octal (base 8) ou
hexadecimal (base 16). No primeiro caso (octal) os dgitos devem seguir imediatamente a barra
invertida (por exemplo, \ 23 ou \ 40), no segundo caso (hexadecimal), um caractere X deve ser
escrito antes dos dgitos (por exemplo, \ x20 ou \ x4A ).
Strings podem ser entendidas como mais de uma linha de cdigo ao se colocar uma barra
invertida (\) no final de cada linha que se deseja continuar.
1 "string expressed in \
2 two lines"
Voc pode tambm concatenar vrias cadeias de caracteres separando-as por um ou vrios
espaos em branco, tabulaes, quebra de linha ou de qualquer outro caractere branco vlido:
Literais booleanas
H apenas dois valores booleanos vlidos: o verdadeiro e o falso. Estes podem ser expressos em
C++ como valores do tipo bool, utilizando os literais booleanos true e false.
1.3.2
Voc pode definir seus prprios nomes para constantes que voc usa muito frequentemente sem
ter que recorrer a variveis, e, consequentemente, consumo de memria, simplesmente usando
a diretiva de pr-processamento # define. Seu formato :
#define PI 3.14159
Pgina | 19 de 93
Isso define duas novas constantes: PI e NEWLINE. Uma vez definidas, voc pode us-las no
restante do cdigo como se fosse qualquer outra constante, por exemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//
defined
constants:
circumference
calculate 31.4159
#include <iostream>
using namespace std;
#define PI 3.14159
#define NEWLINE '\n'
int main (){
double r=5.0;
double circle;
// radius
circle = 2 * PI * r;
cout << circle;
cout << NEWLINE;
return 0;
}
Na verdade a nica coisa que o pr-processador do compilador faz quando encontra a diretriz #
define , literalmente, substituir qualquer ocorrncia de seu identificador (no exemplo anterior,
estes eram PI e NEWLINE) pelo cdigo para o qual foram pr-definidos (3,14159 e ' \ n ',
respectivamente).
A diretiva #define no uma diretiva do C++, mas uma diretiva para o pr-processador, desta
forma, como uma diretiva, no necessita de ponto e vrgula (;) ao final da linha. Se voc
acrescentar um caractere vrgula (;) no final, ele tambm ser anexado em todas as ocorrncias
do identificador no corpo do programa que o pr-processador substituir.
1.3.3
Com o prefixo const voc pode declarar constantes com um tipo especfico da mesma forma
como voc faria com uma varivel:
1.4 Operadores
Uma vez que sabemos da existncia de variveis e constantes, podemos comear a realizar
operaes com eles. Para isto, a linguagem C++ integra alguns operadores. Diferente de outras
Pgina | 20 de 93
1.4.1
Atribuio (=)
a = 5;
Esta afirmao atribui o valor inteiro 5 varivel a. A parte do lado esquerdo do operador de
atribuio (=) conhecida como o lvalue (valor esquerda) e o da direita como rvalue(valor
direita). O lvalue tem que ser uma varivel enquanto o rvalue pode ser uma constante, uma
varivel, o resultado de uma operao ou qualquer combinao destes. A informao mais
importante nesta etapa a regra de atribuio: A operao de atribuio ocorre sempre da
direita para a esquerda e nunca de outra maneira:
a = b;
Este cdigo atribui a varivel a (o lvalue) o valor contido na varivel b (o rvalue). O valor
que foi armazenado, at este momento na varivel a no considerado na operao, e, na
verdade, o possvel valor armazenado em a aps a operao perdido.
Considere tambm que estamos atribuindo o valor de b para a somente no momento da
operao de atribuio. Portanto, uma mudana posterior em b no afetar o valor de a.
Por exemplo, vamos olhar o cdigo a seguir foi includo o contedo armazenado nas variveis
assim como comentrios:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// assignment operator
a:4 b:7
#include <iostream>
using namespace std;
int main (){
int a, b;
a = 10;
b = 4;
a = b;
b = 7;
cout
cout
cout
cout
<<
<<
<<
<<
//
//
//
//
//
a:?,
a:10,
a:10,
a:4,
a:4,
b:?
b:?
b:4
b:4
b:7
"a:";
a;
" b:";
b;
return 0;
}
Pgina | 21 de 93
Esse cdigo nos dar como resultado que o valor contido em a 4 e em b 7. Observe como a
no foi afetado pela modificao final de b, uma vez que a atribuio (a = b) foi declarada
anteriormente.
Uma propriedade que C++ tem sobre outras linguagens de programao que a operao de
atribuio pode ser utilizada como rvalue (ou parte de um rvalue) de outra operao de
atribuio. Por exemplo:
a = 2 + (b = 5);
equivalente a:
1 b = 5;
2 a = 2 + b;
que significa: primeiro atribuir 5 a varivel b e depois atribuir a a o valor 2, mais o resultado da
atribuio de b (ou seja, 5), deixando a com um valor final de 7.
A expresso a seguir tambm vlida em C ++:
a = b = c = 5;
1.4.2
Operadores aritmticos ( +, -, *, /, % )
a = 11 % 3;
Pgina | 22 de 93
1.4.3
Atribuio composta (+=, -=, *=, /=, %=, >>=,
<<=, &=, ^=, |=)
Quando queremos modificar o valor de uma varivel realizando uma operao no valor
atualmente armazenado nessa varivel, podemos usar os operadores de atribuio composta:
expression
is equivalent to
=
/
=
value + increase;
5;
b;
price * (units + 1);
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
int main (){
int a, b=3;
a = b;
a+=2;
// equivalent to a=a+2
cout << a;
return 0;
}
1.4.4
1 c++;
2 c+=1;
3 c=c+1;
Pgina | 23 de 93
Example 1
Example 2
B=3;
B=3;
A=++B;
A=B++;
// A contains 4, B contains 4 // A contains 3, B contains 4
No Exemplo 1, B aumentado antes que seu valor seja copiado para A. Enquanto no Exemplo 2,
o valor de B copiado para A e, em seguida, B aumentado.
1.4.5
Operadores relacionais e de igualdade ( ==, !=,
>, <, >=, <= )
Para realizar uma comparao entre duas expresses devemos utilizar os operadores relacionais
ou de igualdade. O resultado de uma operao relacional um valor booleano que s pode ser
verdadeiro ou falso, de acordo com seu resultado booleano.
Se quisermos comparar duas expresses, por exemplo, para saber se elas so iguais, ou se uma
maior do que outra, devemos utilizar estes operadores. Aqui est uma lista dos operadores
relacionais e de igualdade que podem ser usados em C++:
== Equal to
!= Not equal to
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to
1
2
3
4
5
(7
(5
(3
(6
(5
== 5)
> 4)
!= 2)
>= 6)
< 5)
//
//
//
//
//
evaluates
evaluates
evaluates
evaluates
evaluates
to
to
to
to
to
false.
true.
true.
true.
false.
claro que, em vez de usar somente constantes numricas, podemos usar qualquer expresso
vlida, incluindo variveis. Suponha que a=2, b=3 e c=6,
1
2
3
4
(a == 5)
(a*b >= c)
(b+4 > a*c)
((b=2) == a)
//
//
//
//
evaluates
evaluates
evaluates
evaluates
to
to
to
to
Pgina | 24 de 93
1.4.6
O operador ! o operador C++ que realiza a operao booleana NOT. Ele tem apenas um
operando, localizado a sua direita, e a nica coisa que ele faz retornar o inverso dele,
produzindo false se seu operando true e true se seu operando false. Basicamente, ele
retorna o valor booleano oposto de seu operando. Por exemplo:
1 !(5 == 5)
// evaluates to false because the expression at its right
(5 == 5) is true.
2 !(6 <= 4)
// evaluates to true because (6 <= 4) would be false.
3 !true
// evaluates to false
4 !false
// evaluates to true.
Os operadores lgicos && e || so usados na avaliao de duas expresses para obter um nico
resultado relacional. O operador && corresponde operao lgica booleana AND. Esta operao
resulta true se ambos os seus dois operandos so verdadeiros e false caso contrrio. O quadro a
seguir mostra o resultado do operador &&, resultado da avaliao da expresso a && b:
&& OPERATOR
a
b
a && b
true true True
true false False
false true False
false false False
O operador || corresponde operao lgica OR. Esta operao resulta true se qualquer um de
seus dois operandos verdadeiro, sendo false somente quando ambos os operandos so falsos.
Aqui esto os resultados possveis de a || b:
|| OPERATOR
a
b
a || b
true true true
true false true
false true true
false false false
Por exemplo:
1 ( (5 == 5) && (3 > 6) )
2 ( (5 == 5) || (3 > 6) )
1.4.7
Operador condicional ( ? )
Pgina | 25 de 93
1
2
3
4
7==5 ? 4 : 3
7==5+2 ? 4 : 3
5>3 ? a : b
a>b ? a : b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//
//
//
//
returns
returns
returns
returns
// conditional operator
#include <iostream>
using namespace std;
int main (){
int a,b,c;
a=2;
b=7;
c = (a>b) ? a : b;
cout << c;
return 0;
}
Neste exemplo, a igual a 2 e b igual a 7. A expresso a ser avaliada era (a>b) e o resultado
foi verdadeiro, desta forma, o valor especificado aps o ponto de interrogao foi descartado em
favor do segundo valor (depois dos dois pontos), que era b, e possua valor igual a 7.
1.4.8
Operador virgula ( , )
O operador vrgula (,) usado para separar duas ou mais expresses que so includas onde
somente uma expresso esperada. Quando o conjunto de expresses tem que ser avaliado
para um valor, apenas a expresso mais direita considerada.
Por exemplo, o seguinte cdigo:
a = (b=3, b+2);
Em primeiro lugar, atribui-se o valor 3 a b, e depois b+2 varivel a. Assim, no final, a varivel
a contm o valor 5, enquanto b varivel contm o valor 3.
1.4.9
Os operadores bit a bit modificam as variveis (inteiras) considerando os valores que elas
representam no sistema binrio.
Pgina | 26 de 93
|
^
~
<<
>>
OR
Bitwise Inclusive OR
XOR
Bitwise Exclusive OR
NOT
SHL
Shift Left
SHR
Shift Right
1.4.10
1 int i;
2 float f = 3.14;
3 i = (int) f;
O cdigo anterior converte o nmero float 3.14 para um valor inteiro (3), o restante perdido.
Aqui, o operador de converso o (int). Outra maneira de fazer a mesma coisa em C++
usando a notao funcional: precedendo a expresso a ser convertida pelo tipo e colocando a
expresso entre parnteses:
i = int ( f );
1.4.11
sizeof()
Esse operador aceita um parmetro que pode ser tanto um tipo ou uma varivel em si e retorna
o tamanho em bytes desse tipo ou objeto:
a = sizeof (char);
Este cdigo vai atribuir o valor 1 a, porque char um tipo de varivel com tamanho de um
byte. O valor retornado por sizeof uma constante, por isso sempre determinado antes da
execuo do programa.
1.4.12
Outros operadores
Mais tarde, nesta apostila, vamos ver mais alguns operadores, referentes a ponteiros ou
especficos programao orientada a objeto. Cada um tratado em sua respectiva seo.
Pgina | 27 de 93
1.4.13
Ao escrever expresses complexas com vrios operandos, podemos ter algumas dvidas sobre
qual operando avaliado primeiro e qual posteriormente. Por exemplo, nesta expresso:
a = 5 + 7 % 2
1 a = 5 + (7 % 2)
2 a = (5 + 7) % 2
// with a result of 6, or
// with a result of 0
A resposta correta a primeira das duas expresses, com um resultado de 6. H uma ordem
estabelecida com a prioridade de cada operador, e no apenas os aritmticos (aqueles cuja
preferncia vem da matemtica), mas para todos os operadores que podem aparecer em C++.
Da maior para a menor prioridade, a ordem a seguinte:
Nvel Operador
::
1
Descrio
scope
Grouping
Left-to-right
* &
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+ (type)
.* ->*
* / %
+ << >>
< > <= >=
== !=
&
^
|
&&
||
?:
= *= /= %= += -= >>= <<= &= ^= |=
,
Left-to-right
indirection
and
Right-to-left
reference (pointers)
unary sign operator
type casting
Right-to-left
pointer-to-member
Left-to-right
multiplicative
Left-to-right
additive
Left-to-right
shift
Left-to-right
relational
Left-to-right
equality
Left-to-right
bitwise AND
Left-to-right
bitwise XOR
Left-to-right
bitwise OR
Left-to-right
logical AND
Left-to-right
logical OR
Left-to-right
conditional
Right-to-left
assignment
Right-to-left
comma
Left-to-right
a = 5 + 7 % 2;
Pgina | 28 de 93
a = 5 + (7 % 2);
ou
a = (5 + 7) % 2;
dependendo da operao que deseja executar.
Ento, se voc quiser escrever expresses complicadas e voc no est completamente certo
dos nveis de prioridade, sempre inclua parnteses. Ele tambm far seu cdigo mais fcil de ler.
Pgina | 29 de 93
Captulo
controle
2:
Estruturas
de
2.1.1
A palavra-chave if usada para executar uma instruo (ou bloco) se uma condio
satisfeita. Sua forma :
if (condition) statement
Onde condition a expresso que est sendo avaliada. Se esta condio for verdadeira, a
declarao statement executada. Se for falsa, sua execuo ignorada (no executada) e o
programa continua logo aps esta estrutura condicional. Por exemplo, o seguinte fragmento de
cdigo imprime x is 100 somente se o valor armazenado na varivel x for 100:
1 if (x == 100)
2
cout << "x is 100";
Se ns queremos mais do que uma simples instruo executada caso a condio seja
verdadeira, podemos especificar um bloco de cdigos usando chaves {}:
1 if (x == 100){
2
cout << "x is ";
3
cout << x;
4}
Pgina | 30 de 93
1 if (x == 100)
2
cout << "x is 100";
3 else
4
cout << "x is not 100";
imprime na tela x is 100 se x, de fato, possui valor igual a 100, seno imprime x is not
100.
O if + else pode ser concatenado com o intuito de verificar um intervalo de valores. O
exemplo a seguir mostra a sua utilizao imprimindo na tela dizer se o valor atualmente
armazenado em x positivo, negativo ou nenhum deles (ou seja, zero):
1 if (x > 0)
2
cout << "x
3 else if (x <
4
cout << "x
5 else
6
cout << "x
is positive";
0)
is negative";
is 0";
Lembre-se que no caso em que queremos mais do que uma simples instruo executada
devemos agrup-las em um bloco, colocando-as entre chaves {}.
2.1.2
Os loops tm como finalidade repetir uma afirmao um certo nmero de vezes ou enquanto
uma condio for satisfeita.
1
2
3
#include <iostream>
Pgina | 31 de 93
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
the
starting
while (n>0) {
cout << n << ", ";
--n;
}
cout << "FIRE!\n";
return 0;
}
Ao criar um lao while devemos sempre considerar que ele deve terminar em algum momento,
portanto, temos de fornecer, dentro deste bloco, algum mtodo para forar a condio (n>0) se
tornar falsa em algum momento, caso contrrio, o loop continuar sendo executado para
sempre. Neste caso, ns inclumos o cdigo -- n; que diminui o valor da varivel que est
sendo avaliado na condio (n) em um - isso acabar por tornar a condio (n> 0) falsa depois
de certo nmero de iteraes, para ser mais especfico, quando n for 0.
Sua funcionalidade exatamente a mesma que a do loop while, exceto que a condio do loop
do while avaliada aps a execuo do bloco de cdigo, em vez de antes, garantindo, pelo
Pgina | 32 de 93
menos, uma execuo das instrues, mesmo se a condio no for cumprida. Por exemplo, o
programa echoes a seguir imprime qualquer nmero que voc inserir at que voc digite 0.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// number echoes
#include <iostream>
using namespace std;
int main (){
unsigned long n;
do {
cout << "Enter number (0 to
end): ";
cin >> n;
cout << "You entered: " << n
<< "\n";
} while (n != 0);
return 0;
}
Enter number
You entered:
Enter number
You entered:
Enter number
You entered:
(0 to end): 12345
12345
(0 to end): 160277
160277
(0 to end): 0
0
O do-while normalmente utilizado quando a condio que tem de determinar o fim do ciclo
determinada dentro das instrues do loop, como no caso anterior, onde a entrada do usurio
que dentro do bloco, usada para determinar se o loop tem que acabar. De fato, se voc no
entra o valor 0 no exemplo anterior, voc ser solicitado para inserir nmeros indefinidamente.
10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
FIRE!
Pgina | 33 de 93
n comea com um valor 0 e i com 100, a condio n!=i (n diferente de i). Porque n
incrementado de um e i decrementado de um, a condio do loop se tornar falsa depois do ciclo
50, quando ambos N e i sero iguais a 50.
2.1.3
Instrues de salto
O comando break
Usando break podemos deixar um loop mesmo que sua condio para o fim no cumprida.
Ele pode ser usado para terminar um loop infinito, ou for-lo a terminar antes de seu fim
natural. Por exemplo, vamos parar a contagem regressiva antes de seu fim natural:
1
2
3
10, 9, 8, 7, 6, 5, 4, 3, countdown
aborted!
#include <iostream>
Pgina | 34 de 93
O comando continue
O comando continue faz com que o programa no execute o resto do lao na iterao atual,
como se o fim do bloco fosse alcanado, fazendo com que ele salte para o incio da iterao
seguinte. Por exemplo, vamos pular o nmero 5 em nossa contagem regressiva:
1
2
3
4
5
6
7
8
9
10
11
12
10, 9, 8, 7, 6, 4, 3, 2, 1, FIRE!
O comando goto
O comando goto permite fazer um salto arbitrrio para outro ponto do programa. Voc deve
usar esse recurso com cautela, pois sua execuo realiza um salto incondicional ignorando
qualquer tipo de limitaes de aninhamento.
O ponto de destino identificado por um rtulo, que depois usado como um argumento para a
instruo goto. Um rtulo feito de um identificador vlido seguido por dois pontos (:)
De um modo geral, esta instruo no tem nenhum uso concreto estruturado ou programao
orientada a objeto (com exceo daqueles fs de programao de baixo nvel). Por exemplo,
aqui o nosso lao de contagem regressiva usando goto:
1
2
3
4
5
6
10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
FIRE!
#include <iostream>
using namespace std;
int main (){
Pgina | 35 de 93
7
8
9
10
11
12
13
14 }
int n=10;
loop:
cout << n << ", ";
n--;
if (n>0) goto loop;
cout << "FIRE!\n";
return 0;
A funo exit
exit uma funo definida na biblioteca cstdlib. O objetivo da funo exit terminar o
programa com um cdigo de sada especfico. Seu prottipo :
exitcode utilizado por alguns sistemas operacionais e pode ser utilizado para chamar
programas. Por conveno, um cdigo de sada de 0 significa que o programa terminou
normalmente, e qualquer outro valor significa que alguns resultados inesperados ou erros
aconteceram.
2.1.4
A sintaxe da instruo switch um pouco peculiar. Seu objetivo verificar possveis diversos
valores constantes de uma expresso. Algo semelhante ao que fizemos no incio desta seo,
com a concatenao de vrias instrues de if and else if. Sua forma a seguinte:
switch (expression){
case constant1:
group of statements 1;
break;
case constant2:
group of statements 2;
break;
.
.
.
default:
default group of statements
}
Ele funciona da seguinte maneira: switch avalia expresso (expression) e verifica se ele
equivalente a constant1, se for, ele executa um grupo de comandos at encontrar o comando
break. Quando ele encontra break o programa pula para o fim da estrutura switch.
Se a expresso no era igual a constant1 ser verificado constant2. Se for igual a este, ele
ir executar grupo de comandos 2 at uma palavra-chave break for encontrada, e em seguida,
ir saltar para o final da estrutura switch.
Pgina | 36 de 93
if-else equivalent
switch (x) {
if (x == 1) {
case 1:
cout << "x is 1";
cout << "x is 1";
}
break;
else if (x == 2) {
case 2:
cout << "x is 2";
cout << "x is 2";
}
break;
else {
default:
cout << "value of x unknown";
cout << "value of x unknown";
}
}
O switch um pouco peculiar dentro da linguagem C++, pois ele usa etiquetas em vez de
blocos. Isto nos obriga a colocar instrues break aps o grupo de instrues que queremos que
seja executada para uma determinada condio. Caso contrrio, as declaraes restantes,
incluindo os correspondentes a outros rtulos, tambm sero executadas, at o final do bloco
switch, ou uma instruo break seja atingida.
Por exemplo, se no incluir uma declarao break aps o primeiro grupo case, o programa no
saltar automaticamente para o final do bloco switch, e ele iria continuar a executar o restante
das declaraes at que ele atinja um break ou uma instruo do final do bloco switch. Isso
torna desnecessrio incluir chaves {} em torno das declaraes de cada um dos casos, e pode
tambm ser til para executar o mesmo bloco de instrues para diferentes valores possveis
para a expresso ser avaliada. Por exemplo:
1 switch (x) {
2
case 1:
3
case 2:
4
case 3:
5
cout << "x is 1, 2 or 3";
6
break;
7
default:
8
cout << "x is not 1, 2 nor 3";
9
}
Observe que a estrutura switch s pode ser usada para comparar uma expresso e constantes.
Portanto, no podemos colocar variveis como etiquetas (por exemplo, case n: onde n uma
varivel) ou intervalos (case (1..3:)) porque eles no so vlidos como constantes C++.
Se voc precisar verificar um intervalo de valores ou valores que no so constantes use uma
concatenao if e else if.
Pgina | 37 de 93
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// function example
#include <iostream>
using namespace std;
The result is 8
A fim de examinar este cdigo e, antes de tudo, lembrar algo dito no incio desta apostila: um
programa em C++ sempre inicia sua execuo pela funo main. Ento, vamos comear por
ela.
Podemos ver que a funo main inicia pela declarao da varivel z do tipo int. Logo
depois, uma chamada a uma funo denominada addition. Prestando ateno,
seremos capazes de ver a semelhana entre a estrutura de chamada da funo e a
declarao da funo:
Pgina | 38 de 93
return (r);
finaliza a funo addition e retorna o controle para a funo que a chamou (neste caso, a
funo main). Nesse momento, o programa segue curso regular do mesmo ponto em que foi
interrompida pela a adio. Mas, alm disso, porque a instruo de retorno ( return) da funo
addition especificou um valor: o contedo da varivel r (return (r);), que naquele
momento tinha um valor de 8. Este valor torna-se o valor da avaliao da chamada de funo.
Assim sendo, o valor retornado pela funo addition, a partir dos valores passados a ela (5,
3), atribudo varivel z, neste caso, o valor que ser atribudo a z 8. Para explicar de outra
forma, voc pode imaginar que a chamada da funo (addition (5,3)) literalmente
substitudo pelo valor que ela retorna (8).
A seguinte linha de cdigo, na funo principal, :
Pgina | 39 de 93
Alm disso, teria sido impossvel usar a varivel z dentro da funo addition, uma vez que
esta era uma varivel local da funo principal (main).
Portanto, o escopo de variveis locais limitado ao nvel do mesmo bloco em que elas so
declaradas. No entanto, tambm temos a possibilidade de declarar variveis globais, que so
visveis e que podem ser usadas em qualquer ponto do cdigo, dentro e fora de todas as
funes. Para declarar variveis globais, voc simplesmente tem que declarar a varivel fora de
qualquer funo ou bloco, ou seja, diretamente no corpo do programa.
E aqui est outro exemplo sobre funes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// function example
#include <iostream>
using namespace std;
The
The
The
The
first result is 5
second result is 5
third result is 2
fourth result is 6
" <<
is "
" <<
is "
Pgina | 40 de 93
Neste caso, criamos uma funo chamada de subtraction (subtrao). A nica coisa que esta
funo faz subtrair os parmetros passados a ela e retornar o resultado.
No entanto, se examinarmos a funo main, veremos que temos feito vrias chamadas para a
funo de subtrao. Ns usamos diferentes mtodos de chamada para que voc veja outras
formas ou momentos em que uma funo pode ser chamada.
A fim de compreender estes exemplos, deve-se considerar mais uma vez que uma chamada
para uma funo poderia ser substituda pelo valor que a funo vai retornar. Por exemplo, o
primeiro caso (que voc j deve saber, porque o mesmo padro que temos usado nos
exemplos anteriores):
1 z = subtraction (7,2);
2 cout << "The first result is " << z;
Se substituirmos a chamada de funo com o valor que retorna (i.e., 5), teramos:
1 z = 5;
2 cout << "The first result is " << z;
Bem como
tem o mesmo resultado que a chamada anterior, mas neste caso ns fizemos a chamada para a
funo subtrao diretamente como um parmetro de insero para cout. Basta considerar que
o resultado o mesmo como se tivssemos escrito:
A nica coisa nova que foi introduzida que os parmetros da funo de subtrao so
variveis, ao invs de constantes. Isso perfeitamente vlido. Neste caso, os valores passados
para a funo subtraction so os valores armazenados nas variveis X e Y, que so 5 e 3,
respectivamente, obtemos, ento, 2 como resultado.
O quarto caso o mesmo dos anteriores. Simplesmente note que ao invs de:
z = 4 + subtraction (x,y);
Pgina | 41 de 93
ns poderamos escrever:
z = subtraction (x,y) + 4;
com exatamente o mesmo resultado. Eu tenho mudado de lugar e assim voc pode ver que o
sinal de ponto e vrgula (;) vai ao final de toda a declarao. No tem que ir, necessariamente,
logo aps a chamada da funo.
2.2.2
1
2
3
4
5
6
7
8
9
10
11
12
I'm a function!
void tambm pode ser usado como parmetro de uma funo quando queremos especificar
(explicitamente) que no queremos transferir nenhum parmetro a ela no momento que
chamada. Por exemplo, a funo printmessage poderia ter sido declarada como:
Embora seja opcional para especificar void na lista de parmetros. Em C++, a lista de
parmetros pode simplesmente ser deixada em branco, se queremos uma funo sem
parmetros.
O que voc deve sempre lembrar que o formato de chamada de uma funo deve iniciar por
seu nome e encerrar com os respectivos parmetros entre parnteses. A inexistncia de
Pgina | 42 de 93
parmetros no nos exime da obrigao de escrever os parnteses. Por esse motivo, a chamada
da funo printmessage :
printmessage ();
Os parnteses indicam claramente que esta uma chamada de uma funo e no o nome de
uma varivel ou alguma outra declarao. A chamada a seguir seria incorreta:
printmessage;
At agora, em todas as funes j vimos que os argumentos eram passados para as funes por
valor. Isto significa que ao chamar uma funo com parmetros, o que temos passado para a
funo eram cpias de seus valores, mas nunca as prprias variveis. Por exemplo, suponha que
ns chamamos a nossa primeira funo addition usando o seguinte cdigo:
O que fizemos nesse caso foi a chamada da funo addition passando os valores de x e y, ou
seja, 5 e 3 respectivamente, mas no as variveis x e y.
Dessa forma, quando a funo adio chamada, so atribudos 5 e 3 s suas variveis locais a
e b, respectivamente, mas qualquer modificao para a ou b dentro da funo no ter nenhum
efeito nos valores de X e Y, isto porque as variveis X e Y no eram passadas para a funo,
mas apenas cpias de seus valores no momento em que a funo foi chamada.
Mas pode haver alguns casos em que voc precisa manipular de dentro de uma funo o valor
de uma varivel externa. Para esse efeito, podemos usar argumentos passados por referncia,
como na funo duplicate (duplicar), no seguinte exemplo:
1
2
3
4
5
void duplicate
int& c){
6
a*=2;
8
b*=2;
9
c*=2;
(int&
a,
int&
b,
Pgina | 43 de 93
10 }
11
12 int main (){
13
int x=1, y=3, z=7;
14
duplicate (x, y, z);
15
cout << "x=" << x << ", y=" << y
<< ", z=" << z;
16
return 0;
17 }
A primeira coisa que deve chamar a ateno que na declarao de duplicate o tipo de cada
parmetro foi seguido por um sinal "e" comercial (&). Esse smbolo especifica que os seus
argumentos correspondentes devem ser passados por referncia em vez de por valor.
Quando uma varivel passada por referncia, no estamos passando uma cpia do seu valor,
na realidade as variveis a, b e c e suas correspondentes, x, y e z, pertencentes funo
duplicate ocupam a mesma posio de memria do computador e, consequentemente, qualquer
alterao a, b ou c implica, diretamente, em uma alterao em x, y ou z.
ou seja, sem os sinais e comercial (&), no teramos passado por referncia as variveis, mas
uma cpia de seus valores, e, portanto, a sada na tela do nosso programa teria sido os valores
iniciais de X, Y e Z (sem ter sido modificado).
Passagem por referncia tambm uma forma eficaz de permitir uma funo retornar mais de
um valor. Por exemplo, a seguir tem-se uma funo que retorna o nmero anterior e o prximo
do primeiro parmetro passado.
1
2
3
4
5
6
7
8
Previous=99, Next=101
Pgina | 44 de 93
9
10 int main (){
11
int x=100, y, z;
12
prevnext (x, y, z);
13
cout << "Previous=" << y << ",
Next=" << z;
14
return 0;
15 }
2.3.2
Ao declarar uma funo ns podemos especificar valores a cada um dos ltimos parmetros.
Esse valor ser usado caso o argumento correspondente seja deixado em branco quando a
funo chamada. Para atribuir valores padro, ns simplesmente temos que usar o operador
de atribuio e um valor para os argumentos na declarao da funo. Se nenhum valor para
esse parmetro passado, no momento em que a funo chamada, o valor padro usado.
No entanto, se um valor especificado, o valor padro ignorado e o valor passado utilizado.
Por exemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
6
5
Como podemos ver no corpo do programa h duas chamadas para a funo divide. Na
primeira:
divide (12)
divide (20,4)
Pgina | 45 de 93
Aqui existem parmetros, ento o valor padro para b (int b=2) ignorado e b assume o valor
passado por argumento, isto 4, fazendo que o resultado retornado seja igual a 5 (20/4).
2.3.3
Sobrecarga de funes
Em C++ duas diferentes funes podem ter o mesmo nome. Isso significa que voc pode dar o
mesmo nome para mais de uma funo caso estas tenham um nmero (quantidade) diferente
de parmetros ou tipos diferentes de seus parmetros. Por exemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// overloaded function
#include <iostream>
using namespace std;
10
2.5
Neste caso, ns definimos duas funes com o mesmo nome, operate, mas um deles aceita
dois parmetros do tipo int e o outro aceita do tipo float. O compilador sabe qual funo
deve ser chamada em cada caso, examinando os tipos passados como argumentos, no momento
em que a funo chamada. Se for chamada com dois inteiros como argumentos, ser chamada
a funo que tem dois parmetros int em sua declarao. E se for chamada com dois
argumentos do tipo float, ser chamada quela que possui dois parmetros float.
Na primeira chamada de operate os dois argumentos passados so do tipo int, portanto, a
primeira funo declarada chamada; essa funo retorna o resultado da multiplicao de
ambos os parmetros. Enquanto a segunda chamada passa dois argumentos do tipo float,
ento a segunda funo chamada. Esta possui um comportamento diferente: ela divide um
parmetro pelo outro. Assim, o comportamento de uma chamada depende do tipo dos
argumentos passados, isto , a funo operate foi sobrecarregada.
Observe que uma funo no pode ser sobrecarregada apenas pelo seu tipo de retorno. Pelo
menos um dos seus parmetros deve ter um tipo diferente.
2.3.4
Recursividade
Pgina | 46 de 93
5! = 5 * 4 * 3 * 2 * 1 = 120
e uma funo recursiva para calcular isso em C++ pode ser:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// factorial calculator
#include <iostream>
using namespace std;
Repare como na funo factorial inclumos uma chamada para si mesma, no entanto,
somente se o argumento passado for maior que 1, pois, caso contrrio, a funo ir executar um
loop infinito (provavelmente provocando um erro de estouro de pilha durante a execuo).
Esta funo tem uma limitao, devido ao tipo de dados foram utilizados ( long). Os resultados
obtidos no sero vlidos para valores muito maiores do que 10! ou 15!, dependendo do sistema
operacional que compil-lo.
2.3.5
Declarando funes
At agora, temos declarado todas as funes antes de sua primeira chamada no cdigo-fonte.
Estas chamadas foram, em geral, dentro da funo main. Se voc tentar repetir alguns dos
exemplos anteriores, mas colocando a funo main antes de quaisquer outras funes, voc
provavelmente ir obter alguns erros de compilao. A razo que uma chamada somente pode
ser realizada para uma funo conhecida, isto , declarada em algum ponto antes do cdigo,
como fizemos em todos os nossos exemplos anteriores.
Mas h uma maneira alternativa para evitar escrever todo o cdigo de uma funo antes de sua
chamada, na funo main ou em alguma outra funo. Isto pode ser conseguido, declarando
apenas um prottipo da funo antes de ser usado, em vez de toda a definio. Esta declarao
menor, mas suficiente para o compilador para determinar o seu tipo de retorno e os tipos de
seus parmetros.
Sua forma :
Pgina | 47 de 93
De qualquer forma, incluindo um nome para cada varivel faz com que o prottipo fique mais
inteligvel.
1
2
3
4
5
6
7
8
9
10
11
Type a
Number
Type a
Number
Type a
Number
Type a
Number
number (0
is odd.
number (0
is even.
number (0
is even.
number (0
is even.
to exit): 9
to exit): 6
to exit): 1030
to exit): 0
12
13
14
15
16
17
18 void odd (int a){
19
if ((a%2)!=0) cout << "Number is
odd.\n";
20
else even (a);
21 }
22
23 void even (int a){
24
if ((a%2)==0) cout << "Number is
even.\n";
25
else odd (a);
26 }
Este exemplo no de fato um exemplo de eficincia. Estou certo de que, neste ponto voc j
pode fazer um programa com o mesmo resultado, mas utilizando apenas metade das linhas de
cdigo que foram usados neste exemplo. De qualquer forma este exemplo ilustra como funciona
a prototipagem. Alm disso, neste exemplo, a prototipagem de pelo menos uma das duas
funes necessria para compilar o cdigo sem erros.
As primeiras coisas que ns vemos a declarao das funes odd e even:
Pgina | 48 de 93
Isso permite que essas funes possam ser utilizadas antes de serem definidas, por exemplo,
em main, que agora est localizado onde algumas pessoas acham que seja um lugar mais
lgico: o incio do cdigo-fonte.
Enfim, a razo pela qual este programa precisa que pelo menos uma das funes deve ser
declarada antes de ser definido porque em odd existe uma chamada para even e em even
existe uma chamada para odd. Se nenhuma das duas funes tivesse sido declarada
anteriormente, um erro de compilao aconteceria, uma vez que even no seria visvel para
odd ou odd no seria visvel para even.
Incluir o prottipo de todas as funes no incio do programa uma soluo prtica encontrada
por alguns programadores para evitar erros de compilao.
Pgina | 49 de 93
Captulo 3:
compostos
Tipos
de
dados
3.1 Matrizes
Uma matriz um conjunto de elementos do mesmo tipo, colocados em locais contguos de
memria, para que possam ser individualmente referenciados pela adio de um ndice para um
identificador exclusivo.
Isso significa que, por exemplo, podemos armazenar 5 valores do tipo int em uma matriz sem
ter que declarar 5 variveis diferentes, cada uma com um identificador diferente. Em vez disso,
usando uma matriz, podemos armazenar 5 valores diferentes do mesmo tipo, int por exemplo,
com um identificador exclusivo.
Por exemplo, uma matriz que contm 5 valores inteiros do tipo int chamada billy poderia ser
representada assim:
onde cada painel em branco representa um elemento da matriz, que neste caso so valores
inteiros do tipo int. Estes elementos so numerados de 0 a 4, pois em C++ as matrizes
possuem o primeiro ndice sempre igual a 0, independentemente do seu comprimento.
Como uma varivel normal, uma matriz deve ser declarada antes de ser usada. Uma declarao
tpica para uma matriz em C++ a seguinte:
Pgina | 50 de 93
3.1.1
Inicializando matrizes
Ao declarar uma matriz regular de mbito local (dentro de uma funo, por exemplo), se no
especificarmos os seus elementos, estes no sero inicializados, por padro, e seu contedo
ser indeterminado at que ns guardamos algum valor neles. Os elementos de matrizes
estticas e de mbito global, por outro lado, so automaticamente inicializados com seus valores
padro, que, para todos os tipos fundamentais, significa que so preenchidos com zeros.
Em ambos os casos, seja mbito local ou global, quando se declarar uma matriz temos a
possibilidade de atribuir valores iniciais para cada um dos seus elementos, colocando os valores
em chaves {}. Por exemplo:
A quantidade de valores entre chaves {} no deve ser maior que o nmero de elementos que
declaramos para a matriz entre colchetes []. Por exemplo, no exemplo da matriz billy foi
declarado 5 elementos e na lista de valores iniciais dentro de chaves {} temos que especificar 5
valores, um para cada elemento.
Quando a inicializao de valores est prevista em uma matriz, a linguagem C++ permite a
possibilidade de deixar os colchetes [] vazios. Neste caso, o compilador ir assumir uma
dimenso para a matriz que corresponde ao nmero de valores compreendidos entre chaves {}:
Aps esta declarao, a matriz billy possuiria 5 nmeros inteiros, uma vez que inserimos 5
valores durante sua inicializao.
3.1.2
Em qualquer ponto de um programa em que uma matriz visvel, podemos acessar o valor de
qualquer um dos seus elementos individualmente como se fosse uma varivel normal, sendo
capaz de ler e modificar seu valor. O formato to simples como:
name[index]
Seguindo os exemplos anteriores em que billy possua 5 elementos e cada um desses
elementos era do tipo int, devemos chamar cada elemento da seguinte maneira:
Pgina | 51 de 93
billy[2] = 75;
e, por exemplo, para passar o valor do terceiro elemento de billy para uma varivel chamada
a, poderamos escrever:
a = billy[2];
Portanto, a expresso billy[2] para todos os efeitos como uma varivel do tipo int.
Observe que o terceiro elemento de billy especificado billy[2], uma vez que o primeiro
billy[0], o segundo billy[1] e, portanto, o terceiro billy[2]. Por esta mesma razo,
o seu ltimo elemento billy[4]. Desta forma, se escrevessemos billy[5] estaramos
acessando o sexto elemento de billy e, portanto, superior ao tamanho da matriz.
NOTA: Em C++ sintaticamente correto exceder o intervalo vlido de ndices para uma matriz.
Isso pode criar problemas, uma vez que o acesso de elementos fora da faixa no causa erros de
compilao, mas pode causar erros de execuo. A razo para que isso seja permitido ser vista
mais adiante quando comearmos a usar ponteiros.
Neste ponto importante ser capaz de distinguir claramente entre os dois usos que [] colchetes
tm relacionado a matrizes. Eles executam duas tarefas diferentes: uma para especificar o
tamanho das matrizes que tenham sido declaradas; e a segunda especificar os ndices para os
elementos de matrizes. No confundir estes dois usos possveis de colchetes [].
1 int billy[5];
2 billy[2] = 75;
Se voc ler cuidadosamente, voc ver que um especificador de tipo sempre precede uma
declarao de varivel ou matriz, enquanto ela nunca precede um acesso.
Algumas vlidas outras operaes com matrizes:
1
2
3
4
1
2
3
4
5
billy[0] = a;
billy[a] = 75;
b = billy [a+2];
billy[billy[a]] = billy[2] + 5;
// arrays example
#include <iostream>
using namespace std;
12206
40,
Pgina | 52 de 93
13
return 0;
14 }
3.1.3
Matrizes multidimensionais
Matrizes multidimensionais podem ser descritas como "matrizes de matrizes". Por exemplo, uma
matriz bidimensional pode ser imaginada como uma tabela bidimensional feita de elementos,
todos eles de um mesmo tipo de dados.
jimmy representa uma matriz bidimensional de 3 por 5 elementos do tipo int. A maneira de
declarar esta matriz em C++ :
e, por exemplo, a forma para fazer referncia ao segundo elemento verticalmente e o quarto
horizontalmente em uma expresso seria:
jimmy[1][3]
Matrizes multidimensionais no so limitadas a dois ndices (ou seja, duas dimenses). Elas
podem conter quantos ndices que forem necessrios. Mas cuidado! A quantidade de memria
necessria para uma matriz aumenta rapidamente com cada dimenso. Por exemplo:
declara uma matriz com elementos do tipo char para cada segundo de um sculo, ou seja mais
de 3 bilhes de caracteres. Ento, essa declarao iria consumir mais de 3 GB de memria!
As matrizes multidimensionais so apenas uma abstrao para os programadores, uma vez que
podemos obter os mesmos resultados com uma matriz unidimensional simplesmente colocando
um fator entre os ndices:
// is equivalent to
Pgina | 53 de 93
// (3 * 5 = 15)
pseudo-multidimensional array
#define WIDTH 5
#define HEIGHT 3
#define WIDTH 5
#define HEIGHT 3
int main ()
int main ()
{
{
for (n=0;n<HEIGHT;n++)
for (n=0;n<HEIGHT;n++)
for (m=0;m<WIDTH;m++)
for (m=0;m<WIDTH;m++)
{
{
jimmy[n][m]=(n+1)*(m+1);
jimmy[n*WIDTH+m]=(n+1)*(m+1);
}
}
return 0;
return 0;
}
}
Nenhum dos dois cdigos-fontes acima produz sada na tela, mas ambos atribuem valores para
o bloco de memria chamado Jimmy, da seguinte forma:
Temos usado "constantes definidas" (# define) para simplificar as possveis modificaes futuras
do programa. Por exemplo, no caso em que decidimos ampliar a matriz para uma altura de 4 em
vez dos 3 que poderia ser feito simplesmente mudando a linha:
#define HEIGHT 3
para:
#define HEIGHT 4
3.1.4
Em algum momento podemos precisar passar uma matriz para uma funo como um parmetro.
Em C++ no possvel passar um bloco inteiro de memria por valor como um parmetro para
Pgina | 54 de 93
uma funo, mas podemos passar o seu endereo. Na prtica, isso tem quase o mesmo efeito e
muito mais rpida alm de ser uma operao mais eficiente.
Para utilizar matrizes como parmetros a nica coisa que temos que fazer , quando se declara
a funo, especificar em seus parmetros o tipo dos elementos da matriz, um identificador e um
par de colchetes vazio []. Por exemplo, a seguinte funo:
aceita um parmetro do tipo "array de int" chamado arg. Para passar para esta funo uma
matriz declarada como:
procedure (myarray);
1
2
3
4
5
// arrays as parameters
#include <iostream>
using namespace std;
void printarray (int arg[],
length) {
for (int n=0; n<length; n++)
cout << arg[n] << " ";
cout << "\n";
}
5 10 15
2 4 6 8 10
int
6
7
8
9
10
11 int main (){
12
int firstarray[] = {5, 10, 15};
13
int secondarray[] = {2, 4, 6, 8,
10};
14
printarray (firstarray,3);
15
printarray (secondarray,5);
16
return 0;
17 }
Como voc pode ver, o primeiro parmetro (int arg[]) aceita qualquer matriz cujos
elementos so do tipo int, independentemente do seu comprimento. Por essa razo, ns
inclumos um segundo parmetro que diz a funo do comprimento de cada array que
passamos. Isso permite que o loop que imprime a matriz saiba o intervalo que deve iterar sem
ultrapassar o intervalo de dados.
Em uma declarao de funo tambm possvel incluir matrizes multidimensionais. O formato
de um parmetro de matriz tridimensional :
base_type[][depth][depth]
Pgina | 55 de 93
por exemplo, uma funo com uma matriz multidimensional como argumento poderia ser:
pode armazenar at 20 elementos do tipo char. Ele pode ser representado como:
Pgina | 56 de 93
Note como depois do contedo vlido um caractere nulo ('\ 0') foi includo a fim de indicar o fim
da sequncia. Os painis em cor cinza representam elementos char com valores indeterminados.
3.2.1
Inicializao de sequncias
terminada por caractere nulo
de
caracteres
Como arrays de caracteres so vetores comuns como os demais, estes seguem as mesmas
regras dos demais. Por exemplo, se quisermos inicializar um array de caracteres com uma
sequncia pr-determinada podemos faz-lo tal como qualquer outro:
Neste caso, foi declarada uma matriz de 6 elementos, do tipo char, e inicializado com os
caracteres que formam a palavra "Hello" mais o caractere nulo '\0'. No entanto, vetores
char tm um mtodo adicional para inicializar seus valores: usando literais string.
Em exemplos descritos nos captulos anteriores, ns j usamos constantes que representam
sequncias de caracteres vrias vezes. Estas sequncias so especificadas incluindo o texto (que
queremos que se torne uma sequncia de caracteres) entre aspas ("). Por exemplo:
1 mystext = "Hello";
2 mystext[] = "Hello";
Pgina | 57 de 93
A razo para isso pode se tornar mais compreensvel uma vez que voc sabe um pouco mais
sobre ponteiros. Desde ento ficar claro que uma matriz , na verdade, um ponteiro constante
que aponta para um bloco de memria.
3.2.2
Usando uma sequncia de caracteres terminada
por caractere nulo
Sequncias de caracteres a maneira natural de tratar strings em C++ e estas podem ser
usadas em muitos procedimentos. Na verdade, os literais strings possuem este tipo (char []) e
tambm podem ser usados na maioria dos casos.
Por exemplo, cin e cout suportam sequncias terminadas por caractere nulo tal que estes
comandos podem ser usados para extrair diretamente sequncias de caracteres usando cin ou
para inseri-los atravs de cout. Por exemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// null-terminated sequences
characters
#include <iostream>
using namespace std;
of Please, enter
John
Hello, John!
your
first
name:
Como voc pode ver, foi declarado trs arrays de elementos char. Os dois primeiros foram
inicializados com constantes literais enquanto o terceiro no foi inicializado. Em qualquer caso,
temos que especificar o tamanho do vetor: nos dois primeiros ( question e greeting) o
tamanho foi definido implicitamente pelo comprimento da constante literal inicializada. Enquanto
que para yourname foi explicitamente especificado o tamanho de 80 caracteres.
Finalmente, as sequncias de caracteres armazenados em arrays char podem ser facilmente
convertidas em objetos string usando apenas o operador de atribuio:
1 string mystring;
2 char myntcs[]="some text";
3 mystring = myntcs;
Pgina | 58 de 93
3.3 Ponteiros
Anteriormente vimos que as variveis so vistas como clulas de memria e podem ser
acessadas usando seus identificadores. Desta forma, no precisa se preocupar com a localizao
fsica dos dados dentro da memria, ns simplesmente usamos sua identificao sempre que for
necessrio referir-se varivel.
A memria do seu computador pode ser imaginada como uma sucesso de clulas de memria,
cada uma do tamanho mnimo que computadores podem administrar (um byte). Estas clulas de
memria (byte) so numeradas de forma consecutiva, de modo que, dentro de qualquer bloco
de memria, cada clula tem o mesmo nmero que a anterior mais um.
Desta forma, cada clula pode ser facilmente localizada na memria, porque ela tem um
endereo nico e todas as clulas de memria seguem um padro, sucessivamente. Por
exemplo, se ns estamos olhando para a clula 1776, sabemos que deve estar entre as clulas
de 1775 e 1777, exatamente mil clulas aps 776 e exatamente mil clulas antes 2776.
3.3.1
Assim que ns declaramos uma varivel, a quantidade de memria necessria atribuda por
ela em uma posio especfica na memria (o endereo de memria). Ns geralmente no
decidimos o local exato da varivel dentro das clulas disponveis da memria - Felizmente, essa
uma tarefa executada automaticamente pelo sistema operacional durante a execuo do
programa. No entanto, em alguns casos, podemos estar interessados em conhecer o endereo
onde a varivel est sendo armazenada durante a execuo do programa, a fim de operar com
posies relativas a ela.
O endereo que localiza uma varivel na memria o que chamamos uma referncia para essa
varivel. A referncia de qualquer varivel pode ser obtida precedendo o identificador da
varivel com um sinal de e comercial (&), conhecido como operador de referncia, e que pode
ser traduzido literalmente como "o endereo de". Por exemplo:
ted = &andy;
Isso atribuiria a ted o endereo da varivel andy. Ao inserir o operador de referncia (&)
varivel andy no estamos mais falando sobre o contedo da varivel em si, mas sobre a sua
referncia (ou seja, o seu endereo na memria).
De agora em diante vamos supor que andy colocado (durante a execuo) no endereo de
memria 1776. Este nmero (1776) apenas uma suposio arbitrria que estamos inventando
agora, a fim de ajudar a esclarecer alguns conceitos neste material, mas na realidade, no
podemos saber antes da execuo o valor real do endereo que uma varivel ter na memria.
Considere as seguintes linhas de cdigo:
1 andy = 25;
2 fred = andy;
3 ted = &andy;
Pgina | 59 de 93
Os valores contidos em cada varivel, aps sua execuo, so mostrados no diagrama abaixo:
Primeiro, foi atribudo o valor de 25 a andy (uma varivel cujo endereo na memria que temos
assumido como sendo 1776).
Na segunda declarao foi copiado para fred o contedo da varivel andy (que 25). Esta
uma operao de atribuio padro.
Finalmente, a terceira declarao no copia para ted o valor contido em andy, mas uma
referncia a ela (isto , seu endereo, que foi assumido igual a 1776). Isto ocorreu, pois na
terceira linha de cdigo foi precedido ao identificador andy o operador de referncia(&).
A varivel que armazena a referncia a outra varivel (como Ted, no exemplo anterior) o que
chamamos de um ponteiro. Os ponteiros so um poderoso recurso da linguagem C++ e tem
muita utilidade na programao avanada. Mais frente, vamos ver como esse tipo de varivel
utilizada e declarada.
3.3.2
Acabamos de ver que uma varivel que armazena uma referncia outra varivel chamada de
ponteiro. Ponteiros "apontam para" a varivel cuja referncia armazenada por eles.
Usando um ponteiro, podemos acessar diretamente o valor armazenado na varivel que ele
aponta. Para fazer isso, ns simplesmente temos que preceder o identificador do ponteiro com
um asterisco (*), que atua como operador de referncia e que pode ser traduzido literalmente
como "valor apontado por".
Assim, seguindo com os valores do exemplo anterior, se escrevermos:
beth = *ted;
(que poderamos ler como: " beth igual ao valor apontado por ted ") beth levaria o valor
25, uma vez que ted 1776, e o valor apontado pelo 1776 25.
Pgina | 60 de 93
Voc deve notado claramente que a expresso de ted se refere ao valor de 1776, enquanto
*ted (com um asterisco * antes do identificador) refere-se ao valor armazenado no endereo
1776, que neste caso 25. Observe a diferena ao incluir ou no o operador dereferncia (Eu
inclu um comentrio explicativo de como cada uma dessas duas expresses pode ser lido):
1 beth = ted;
2 beth = *ted;
Assim, eles tm significados complementares (ou opostos). Uma varivel de referncia pode ser
dereferenciada com *.
Anteriormente foram realizadas as seguintes operaes de atribuio:
1 andy = 25;
2 ted = &andy;
1
2
3
4
andy == 25
&andy == 1776
ted == 1776
*ted == 25
A primeira expresso bastante clara, considerando que a operao de atribuio foi realizada
em andy (andy=25). A segunda usa o operador de referncia (&), que retorna o endereo da
varivel andy, que foi assumido o valor de 1776. A terceira um tanto bvia, j que a segunda
expresso era verdade e da operao de atribuio realizada foi ted=&andy. A quarta expresso
usa o operador de dereferncia (*) que, como acabamos de ver, pode ser lido como "valor
apontado por", e, o valor apontado por ted realmente 25.
Pgina | 61 de 93
Ento, depois de tudo isso, voc tambm pode concluir que, enquanto o endereo apontado por
ted permanece inalterado a seguinte expresso tambm ser verdadeira:
*ted == andy
3.3.3
Devido capacidade de um ponteiro referir-se diretamente para o valor que ele aponta, torna-se
necessrio especificar em sua declarao que tipo de dados um ponteiro vai apontar. No a
mesma coisa apontar para um char como para apontar para um int ou float.
A declarao de ponteiros segue este formato:
type * name;
onde type o tipo de dados que o ponteiro ir apontar. Este tipo no o tipo do ponteiro em si,
mas o tipo de dados que o ponteiro aponta. Por exemplo:
1 int * number;
2 char * character;
3 float * greatnumber;
Estes so trs declaraes de ponteiros. Cada um deles destina-se a apontar para um tipo de
dado diferente, mas na verdade todos eles so ponteiros e todos eles vo ocupar o mesmo
espao na memria (o tamanho da memria de um ponteiro depende da plataforma onde o
cdigo est sendo executado). No entanto, os dados que eles apontam no ocupam o mesmo
espao na memria nem so do mesmo tipo: o primeiro aponta para um int, o segundo para
um char e o ltimo para um float. Portanto, embora estas trs variveis so ponteiros que
ocupam o mesmo tamanho em memria, dito que eles tm tipos diferentes: int*, char* e
float*, respectivamente, dependendo do tipo que eles apontam.
NOTA: O sinal asterisco (*) que usamos quando declaramos um ponteiro significa apenas que
ele um ponteiro (faz parte do seu especificador composto tipo), e no deve ser confundido com
o operador dereferncia que vimos anteriormente, mas tambm escrito com um asterisco (*).
Eles so duas coisas diferentes representados com o mesmo sinal.
Agora d uma olhada neste cdigo:
1
2
3
4
5
6
7
8
9
10
11
12
13
// my first pointer
#include <iostream>
using namespace std;
firstvalue is 10
secondvalue is 20
mypointer = &firstvalue;
*mypointer = 10;
mypointer = &secondvalue;
*mypointer = 20;
cout << "firstvalue is
firstvalue << endl;
14
cout << "secondvalue is
"
<<
"
<<
Pgina | 62 de 93
Observe que, embora no foi definido diretamente um valor para as variveis firstvalue ou
secondvalue, estes valores foram definidos indiretamente atravs do uso de mypointer. Este
o procedimento:
Primeiro, foi atribudo como valor de mypointer uma referncia para firstvalue usando o
operador de referncia (&). E ento foi atribudo o valor 10 para a localizao de memria
apontada por mypointer. Neste momento mypointer est apontando para o local da memria
do firstvalue e, consequentemente, modifica o valor de firstvalue.
Para demonstrar que um ponteiro pode tomar vrios valores no mesmo programa, foi repetido o
processo com secondvalue com mesmo ponteiro, mypointer.
Aqui est um exemplo um pouco mais elaborado:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// more pointers
#include <iostream>
using namespace std;
firstvalue is 10
secondvalue is 20
Foi includo como um comentrio em cada linha do cdigo: comercial (&) como "endereo de" e
um asterisco (*) como "valor apontado por".
Observe que h expresses com os ponteiros p1 e p2 com e sem operador dereferncia (*). O
significado de uma expresso usando o operador de dereferncia (*) muito diferente de um
que no o utiliza: quando este operador precede o nome do ponteiro, a expresso se refere ao
valor que est sendo apontado, ao mesmo tempo quando um nome de ponteiro aparece sem
Pgina | 63 de 93
este operador, refere-se para o valor do ponteiro em si (ou seja, o endereo ao qual o ponteiro
est apontando).
Esta linha de cdigo declara os dois ponteiros usados no exemplo anterior. Mas repare que h
um asterisco (*) para cada ponteiro, de modo que ambos tm tipo int* (ponteiro para int).
Caso contrrio, o tipo para a segunda varivel declarada teria sido int (e no int *), devido
s relaes de precedncia. Se tivssemos escrito:
p1 seria certamente do tipo int*, mas p2 seria tipo int. Isto devido s regras de
precedncia do operador. Mas de qualquer maneira, basta lembrar que voc tem que colocar um
asterisco por ponteiro que suficiente para a maioria dos usurios de ponteiro.
3.3.4
Ponteiros e matrizes
p = numbers;
numbers = p;
Como numbers uma matriz, este funciona como um ponteiro constante, e, portanto, no
podemos atribuir valores para constantes.
Devido s caractersticas das variveis, todas as expresses que incluem ponteiros no exemplo a
seguir so perfeitamente vlidas:
Pgina | 64 de 93
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// more pointers
#include <iostream>
using namespace std;
No captulo sobre matrizes usamos colchetes ([]) vrias vezes a fim de especificar o ndice de
um elemento da matriz a que queramos nos referir. Bem, estes operadores (sinal de colchetes
[]) tambm so um operador dereferncia conhecido como operador de offset. Eles
dereferenciam a varivel como faz o operador asterisco (*), mas tambm adicionam o nmero
entre parnteses para o endereo a ser dereferenciado. Por exemplo:
1 a[5] = 0;
2 *(a+5) = 0;
// a [offset of 5] = 0
// pointed by (a+5) = 0
3.3.5
Inicializao de ponteiros
Ao declarar ponteiros, ns podemos especificar explicitamente qual a varivel que queremos que
eles apontem:
1 int number;
2 int *tommy = &number;
1 int number;
2 int *tommy;
3 tommy = &number;
Pgina | 65 de 93
1 int number;
2 int *tommy;
3 *tommy = &number;
que est incorreto, e, mesmo assim, no teria muito sentido neste caso.
Como no caso de matrizes, o compilador permite o caso especial que queremos inicializar o
contedo ao qual o ponteiro aponta com constantes no mesmo instante que o ponteiro
declarado:
Neste caso, o espao de memria reservado para conter a palavra "hello" e, em seguida,
um ponteiro para o primeiro caractere do bloco de memria atribudo a terry. Se
imaginarmos que "hello" armazenado em locais da memria que comeam a partir do
endereo 1702, podemos representar a declarao anterior como:
importante indicar que terry contm o valor 1702, e no 'h', nem "hello", embora, na
verdade, 1702 o endereo de ambos.
O ponteiro terry aponta para uma sequncia de caracteres e pode ser lido como se fosse uma
matriz comum (lembre-se que uma matriz igual a um ponteiro constante). Por exemplo,
podemos acessar o quinto elemento da matriz com qualquer uma dessas duas expresses:
1 *(terry+4)
2 terry[4]
3.3.6
Aritmtica de ponteiros
As operaes aritmticas com ponteiros um pouco diferente do que as operaes com dados
inteiros. Para comear, as nicas operaes que podem ser realizadas so adio e subtrao, as
outras no fazem sentido no mundo dos ponteiros. Mas a adio e subtrao tm um
comportamento diferente de acordo com o tamanho do tipo de dados para o qual eles apontam.
Quando vimos os diferentes tipos de dados fundamentais, vimos que alguns ocupam menos ou
mais espao que outros na memria. Por exemplo, vamos supor que em um dado compilador,
para uma mquina especfica, char tem 1 byte, short ocupa 2 bytes e long 4.
Pgina | 66 de 93
1 char *mychar;
2 short *myshort;
3 long *mylong;
e que ns sabemos que eles apontam para posies de memria 1000, 2000 e 3000,
respectivamente.
Ento se n escrevemos:
1 mychar++;
2 myshort++;
3 mylong++;
mychar, como voc pode esperar, deve conter o valor de 1001. Mas no to obviamente,
myshort dever conter o valor de 2002, e mylong dever conter 3004, apesar de terem sido
aumentados uma s vez. A razo que, ao adicionar uma unidade a um ponteiro estamos
fazendo com que ele aponte para o elemento seguinte do mesmo tipo com o qual ele foi definido
e, portanto, o tamanho em bytes do tipo apontado adicionado ao ponteiro.
Isto aplicvel tanto ao somar e subtrair qualquer nmero para um ponteiro. Iria acontecer
exatamente o mesmo se escrevermos:
1 mychar = mychar + 1;
2 myshort = myshort + 1;
3 mylong = mylong + 1;
*p++
Pgina | 67 de 93
essa expresso equivalente a *(p++). Portanto, o que esta expresso faz incrementar o
valor de p (de modo que agora ele aponta para o elemento seguinte), isto acontece porque ++
usado como sufixo e toda a expresso avaliada como o valor apontado pela referncia original
(o endereo do ponteiro apontado para antes de ser aumentada).
Observe a diferena com:
(*p)++
Aqui, a expresso foi avaliada como o valor apontado por p incrementado em uma unidade. O
valor de p (o prprio ponteiro) no seria alterado (o que est sendo modificado o que est
sendo apontado por este ponteiro).
Se escrevermos:
*p++ = *q++;
1 *p = *q;
2 ++p;
3 ++q;
Como sempre, eu recomendo que voc use parnteses (), a fim de evitar resultados inesperados
e para dar maior legibilidade ao cdigo.
3.3.7
C++ permite o uso de ponteiros que apontam para ponteiros, e estes, por sua vez, apontam
para dados (ou at mesmo para outros ponteiros). Para fazer isto s precisamos adicionar um
asterisco (*) para cada nvel de referncia em suas declaraes:
1
2
3
4
5
6
char a;
char * b;
char ** c;
a = 'z';
b = &a;
c = &b;
Supondo que os locais de memria escolhidos aleatoriamente para cada varivel so 7230, 8092
e 10502, respectivamente, estes cdigos podem ser representados graficamente como:
Pgina | 68 de 93
O valor de cada varivel escrito dentro de cada clula, as clulas esto sob seus respectivos
endereos na memria.
A novidade nesse exemplo a varivel c, que pode ser utilizada em trs diferentes nveis de
indireo, cada uma delas corresponderia a um valor diferente:
3.3.8
Ponteiros void
Um de seus usos pode ser a passagem de parmetros genricos para uma funo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// increaser
#include <iostream>
using namespace std;
y, 1603
Pgina | 69 de 93
sizeof um operador integrado na linguagem C++ que retorna o tamanho em bytes do seu
parmetro. Para tipos de dados no dinmicos (char, int, float, etc) esse valor uma
constante. Assim, por exemplo, sizeof(char) 1, porque o tipo char possui um byte.
3.3.9
Ponteiro nulo
Um ponteiro nulo um ponteiro comum de qualquer tipo que tem um valor especial e indica que
ele no est apontando para qualquer referncia vlida ou endereo de memria. Este valor
especial o zero para qualquer tipo de ponteiro.
1 int * p;
2 p = 0;
NOTA: No confundir com ponteiros nulos ponteiros void. Um ponteiro nulo um valor que pode
assumir um ponteiro de um determinado tipo para indicar que ele no est apontando para
"nenhum lugar". Um ponteiro void um tipo especial de ponteiro que pode apontar para
qualquer lugar sem um tipo especfico. Um se refere ao valor armazenado no ponteiro e outro
para o tipo de dados que ele aponta.
3.3.10
A linguagem C++ permite operaes com ponteiros para funes. O uso tpico deste para
passar uma funo como um argumento para outra funo, uma vez que estes ponteiros no
podem ser passados dereferenciados. Para declarar um ponteiro para uma funo temos que
declar-la como uma funo comum, exceto que o nome da funo colocado entre parnteses
() e um asterisco (*) inserido antes do nome:
1
2
3
4
5
6
7
8
9
10
11
12
13
// pointer to functions
#include <iostream>
using namespace std;
14
15
16
17
18
19 int main (){
20
int m,n;
21
int
(*minus)(int,int)
subtraction;
22
Pgina | 70 de 93
23
24
25
26
27 }
No exemplo, minus um ponteiro para uma funo que tem dois parmetros do tipo int. Ele
imediatamente atribudo para apontar para a funo subtraction, tudo em uma nica linha:
3.4.1
Para alocar memria dinamicamente devemos usar operador new. new seguido por um tipo de
dados e, se uma sequncia de mais de um elemento necessria, o nmero de elementos deve
ser inserido entre colchetes []. Ele retorna um ponteiro para o incio do novo bloco de memria
alocada. Sua forma :
1 int * bobby;
2 bobby = new int [5];
Neste caso, o sistema atribui dinamicamente espao para cinco elementos do tipo int e retorna
um ponteiro para o primeiro elemento da seqncia, que atribudo bobby. Portanto, agora
bobby aponta para um bloco vlido de memria com espao para cinco elementos do tipo int.
Pgina | 71 de 93
O primeiro elemento apontado por bobby pode ser acessado tanto com a expresso bobby[0]
ou a expresso *bobby. Ambos so equivalentes, como foi explicado na seo sobre ponteiros.
O segundo elemento pode ser acessado tanto com bobby[1] ou *(bobby+1) e assim por
diante.
Voc pode estar se perguntando a diferena entre declarar uma matriz normal e atribuio
dinmica de memria para um ponteiro, como acabamos de fazer. A diferena mais importante
que o tamanho de uma matriz um valor constante, limitado no momento da concepo do
programa, antes de sua execuo, enquanto ao utilizar a alocao dinmica de memria permite
a atribuio de memria durante a execuo do programa (runtime) usando qualquer varivel
ou um valor constante para determinar seu tamanho.
A memria solicitada pelo nosso programa durante a execuo atribuda pelo sistema
operacional a partir da pilha de memria. No entanto, a pilha um recurso limitado e pode se
esgotar. Portanto, importante ter algum mecanismo para verificar se o nosso pedido de
alocao foi bem sucedido ou no.
C++ fornece dois mtodos padro para verificar se a alocao foi bem sucedida:
Uma delas o tratamento de excees. Usando este mtodo uma exceo do tipo bad_alloc
acionada quando a alocao falhar. As excees so um poderoso recurso do C++ explicado
mais tarde nessa apostila. Mas, por agora voc deve saber que, se essa exceo lanada e no
tratada por um manipulador especfico, a execuo do programa ser encerrada.
Este mtodo de exceo o mtodo padro usado pelo new e o utilizado em uma declarao
como:
O outro mtodo conhecido como nothrow, e o que acontece quando ele usado que,
quando uma alocao de memria falha, em vez de executar uma exceo bad_alloc ou
encerrar o programa, o ponteiro retornado por new um ponteiro nulo, e o programa continua
sua execuo normalmente.
Este mtodo pode ser especificado usando um objeto especial chamado nothrow, declarado no
cabealho <new>, como argumento para o new:
Neste caso, se a atribuio deste bloco de memria falha, a falha pode ser detectada verificando
se bobby teve um valor de ponteiro nulo:
1 int * bobby;
2 bobby = new (nothrow) int [5];
3 if (bobby == 0) {
4
// error assigning memory. Take measures.
Pgina | 72 de 93
5 };
Este mtodo nothrow requer mais trabalho do que o mtodo de exceo, uma vez que o valor
retornado deve ser verificado aps cada alocao de memria, mas vou us-lo nos nossos
exemplos, devido sua simplicidade. De qualquer forma esse mtodo pode se tornar tedioso
para projetos maiores, onde o mtodo de exceo geralmente preferido. O mtodo de exceo
ser explicado em detalhe mais tarde neste material.
3.4.2
Uma vez que a quantidade de memria dinmica geralmente limitada dentro de um programa,
aps ser utilizada ela deve ser liberada, para que a memria se torne disponvel novamente para
outras solicitaes. Este o objetivo do operador delete, seu formato :
1 delete pointer;
2 delete [] pointer;
A primeira expresso deve ser usada para apagar a memria alocada de um nico elemento, e a
segunda para a memria alocada para vrios elementos (matrizes).
O valor passado como argumento para excluir deve ser um ponteiro para um bloco de memria
previamente alocado com o operador new, ou um ponteiro nulo (no caso de um ponteiro nulo,
delete no produz nenhum efeito).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// rememb-o-matic
#include <iostream>
#include <new>
using namespace std;
Pgina | 73 de 93
Observe como o valor entre parntesis na declarao de new um valor varivel digitado pelo
usurio (i), no um valor constante:
Mas o usurio poderia ter entrado um valor para i to grande que nosso sistema no poderia
lidar. Por exemplo, quando eu tentei dar um valor de 1000 milhes para a pergunta "Quantos
nmeros", meu sistema no pde alocar a memria e recebi a mensagem de texto para este
caso (Error: memory could not be allocated). Lembre-se que se tentssemos alocar a memria,
sem especificar o parmetro nothrow na expresso new, uma exceo seria iniciada, que se no
for tratada, termina o programa.
uma boa prtica sempre verificar se um bloco de memria dinmica com xito foi atribudo.
Portanto, se voc usar o mtodo nothrow, voc deve sempre verificar o valor do ponteiro
retornado. Caso contrrio, use o mtodo de exceo, mesmo se voc no tratar a exceo.
Desta forma, o programa ser encerrado neste ponto, sem causar resultados inesperados ao
continuar a execuo de um cdigo que pressupe um bloco de memria que tenha sido
atribudo, quando na verdade ele no foi.
3.5.1
Estruturas de dados
Uma estrutura de dados um grupo de elementos de dados agrupados sob um nico nome.
Esses elementos de dados, conhecidos como membros, podem ter diferentes tipos e tamanhos.
As estruturas de dados so declaradas em C++ usando a seguinte sintaxe:
struct structure_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;
onde structure_name um nome para o tipo de estrutura, object_name pode ser um
conjunto de identificadores vlidos para objetos que tenham o tipo desta estrutura. Dentro das
chaves {} existe uma lista com os membros de dados, cada um especificado com um tipo e
um identificador vlido como o seu nome.
A primeira coisa que temos que saber que uma estrutura de dados cria um novo tipo: quando
uma estrutura de dados declarada, um novo tipo de identificador especificado como
Pgina | 74 de 93
structure_name criado e pode ser usado no resto do programa como se fosse qualquer
outro tipo. Por exemplo:
1
2
3
4
5
6
7
struct product {
int weight;
float price;
} ;
product apple;
product banana, melon;
Temos primeiro declarado uma estrutura chamada product com dois membros: weight (peso)
e price (preo), cada um de um tipo de dado diferente. Usamos, em seguida, este nome de
estrutura (product) para declarar trs objetos: apple, banana e melon como teria feito com
qualquer tipo de dados fundamental.
Uma vez declarado, product tornou-se um novo tipo de dado vlido como os fundamentais
int, char ou short e, a partir desse ponto, somos capazes de declarar objetos (variveis)
desse novo tipo de composto, tal como temos feito com, banana, ma e melo.
Logo no final da declarao struct, e antes do ponto e vrgula final, podemos usar o campo
opcional object_name para declarar objetos diretamente. Por exemplo, podemos tambm
declarar a estrutura de objetos de apple, banana e melon no momento em que definimos o
tipo de estrutura de dados:
1 struct product {
2
int weight;
3
float price;
4 } apple, banana, melon;
1
2
3
4
5
6
apple.weight
apple.price
banana.weight
banana.price
melon.weight
melon.price
Pgina | 75 de 93
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mine.title
=
"2001
A
Space
Odyssey";
18
mine.year = 1968;
19
20
cout << "Enter title: ";
21
getline (cin,yours.title);
22
cout << "Enter year: ";
23
getline (cin,mystr);
24
stringstream(mystr)
>>
25 yours.year;
26
27
cout << "My favorite movie is:\n
";
28
printmovie (mine);
29
cout << "And yours is:\n ";
30
printmovie (yours);
31
return 0;
32 }
33
34 void printmovie (movies_t movie){
35
cout << movie.title;
36
cout << " (" << movie.year <<
")\n";
37 }
O exemplo mostra como podemos usar os membros de um objeto como variveis normais. Por
exemplo, o yours.year membro uma varivel vlida do tipo int, e mine.title uma
varivel vlida do tipo string.
Os objetos mine e yours tambm podem ser tratados como variveis do tipo movies_t, por
exemplo, ns os passamos para a funo printmovie como teramos feito com variveis
comuns. Portanto, uma das vantagens de estruturas que podemos fazer referncia aos seus
membros individualmente ou para toda a estrutura como um bloco com apenas um identificador.
Estruturas de dados um recurso que pode ser usado para representar bancos de dados,
especialmente se considerarmos a possibilidade de construo de matrizes:
1
2
// array of structures
#include <iostream>
Pgina | 76 de 93
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <string>
#include <sstream>
using namespace std;
Enter
Enter
Enter
Enter
title: Matrix
year: 1999
title: Taxi Driver
year: 1976
#define N_MOVIES 3
struct movies_t {
string title;
int year;
} films [N_MOVIES];
31
32
33
34
35
36 void printmovie (movies_t movie){
37
cout << movie.title;
38
cout << " (" << movie.year <<
")\n";
39 }
3.5.2
Como qualquer outro tipo de dados, as estruturas tambm podem ser apontadas pelo seu
prprio tipo de ponteiro:
1
2
3
4
5
6
7
struct movies_t {
string title;
int year;
};
movies_t amovie;
movies_t * pmovie;
Pgina | 77 de 93
Aqui amovie um objeto de movies_t, uma estrutura, e pmovie um ponteiro para apontar
objetos do tipo estrutura movies_t. Ento, o seguinte cdigo tambm seria vlido:
pmovie = &amovie;
ao valor do ponteiro pmovie atribudo uma referncia ao objeto amovie (seu endereo de
memria).
Agora vamos analisar outro exemplo que inclui ponteiros, e tambm serve para introduzir um
novo operador: o operador seta (->):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// pointers to structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct movies_t {
string title;
int year;
};
body
snatchers
28
29
return 0;
30 }
O cdigo anterior inclui uma introduo importante: o operador seta (->). Este um operador
dereferncia que usado exclusivamente com ponteiros para objetos com membros. Este
operador serve para acessar um membro de um objeto para o qual temos uma referncia. No
exemplo que usamos:
pmovie->title
Pgina | 78 de 93
(*pmovie).title
*pmovie.title
que equivalente a:
*(pmovie.title)
e isso poderia acessar o valor apontado por um ponteiro membro hipottico chamado title do
objeto estrutura pmovie (que neste caso no seria um ponteiro e sim um valor). O quadro a
seguir resume as combinaes possveis de ponteiros e os membros da estrutura:
Expresso O que avaliado
Equivalente
a.b
Membro b do objeto a
a->b
Membro b do objeto apontado por a
(*a).b
*a.b
Valor apontado pelo membro b do objeto a *(a.b)
3.5.3
Estruturas aninhadas
Estruturas tambm podem ser aninhadas de modo que um elemento de uma estrutura tambm
pode ser outra estrutura.
1
2
3
4
5
6
7
8
9
10
11
12
struct movies_t {
string title;
int year;
};
struct friends_t {
string name;
string email;
movies_t favorite_movie;
} charlie, maria;
friends_t * pfriends = &charlie;
Aps a declarao anterior, podemos usar qualquer uma das seguintes expresses:
1
2
3
4
charlie.name
maria.favorite_movie.title
charlie.favorite_movie.year
pfriends->favorite_movie.year
Pgina | 79 de 93
O C++ permite a definio de nossos prprios tipos de dados baseados em tipos existentes
(int, float, etc). Podemos fazer isto utilizando a palavra-chave typedef, cujo formato :
1
2
3
4
typedef
typedef
typedef
typedef
char C;
unsigned int WORD;
char * pChar;
char field [50];
Neste caso, foi definido quatro tipos de dados: C, WORD, pChar e field como unsigned, int
char *, char e char [50], respectivamente, que poderamos perfeitamente usar em
declaraes posteriores como qualquer outro tipo de dados:
1
2
3
4
typedef no cria outros tipos de dados. Ela s cria sinnimos dos tipos existentes. Isso significa
que o objeto myword pode ser considerado um unsigned int ou WORD, j que ambos so, de
fato, do mesmo tipo.
typedef pode ser til para definir um alias (apelido) para um tipo que usado frequentemente
dentro do programa. Tambm til para definir os tipos quando tivermos que alterar o tipo de
dado de um conjunto de variveis em verses posteriores do nosso programa, ou se um tipo de
dado cujo nome muito longo ou confuso.
3.6.2
Unies (union)
Unies permitem uma mesma poro de memria a ser acessada como diferentes tipos de
dados, uma vez que todos eles esto, de fato, no mesmo local da memria. Sua declarao e
utilizao so semelhantes s estruturas, mas sua funcionalidade totalmente diferente:
union union_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;
Pgina | 80 de 93
Todos os elementos da declarao union ocupam o mesmo espao fsico na memria. Seu
tamanho assumido como sendo o do maior elemento da declarao. Por exemplo:
1 union mytypes_t {
2
char c;
3
int i;
4
float f;
5
} mytypes;
1 mytypes.c
2 mytypes.i
3 mytypes.f
cada um com um tipo de dado diferente. Uma vez que todos eles esto se referindo ao mesmo
local na memria, a modificao de um dos elementos afetar o valor de todos eles. No
podemos armazenar valores diferentes em cada uma das variveis ao mesmo tempo.
Um dos usos das unies a possibilidade de unir um tipo elementar de dado com um conjunto
de outros elementos ou estruturas de menor dimenso. Por exemplo:
1 union mix_t {
2
long l;
3
struct {
4
short hi;
5
short lo;
6
} s;
7
char c[4];
8 } mix;
define trs nomes que nos permitem acessar o mesmo grupo de 4 bytes: mix.l, mix.s e
mix.c. Podemos us-lo, como se fossem um nico tipo de dados, como se fosse um long,
como se fossem dois short ou como uma matriz com 4 elementos char, respectivamente. Esta
unio, para um sistema little-endian (maioria das plataformas PC), pode ser representada como:
Pgina | 81 de 93
3.6.3
Unies annimas
Em C++, temos a opo de declarar unies annimas. Se declarar uma unio sem qualquer
nome, a unio ser annima e seremos capazes de acessar seus membros diretamente pelo
nome. Por exemplo, olhe a diferena entre essas duas declaraes de estrutura:
estrutura com unio regular estrutura com unio annima
struct {
char title[50];
char author[50];
union {
float dollars;
int yens;
} price;
} book;
struct {
char title[50];
char author[50];
union {
float dollars;
int yens;
};
} book;
A nica diferena entre os dois cdigos que no primeiro foi dado um nome para a unio
(price) e na segunda no foi inserido um nome. A diferena vista quando acessamos os
membros dollars e yens desse objeto. Para o primeiro cdigo seria:
1 book.price.dollars
2 book.price.yens
1 book.dollars
2 book.yens
Mais uma vez devo lembrar que, porque uma unio e no uma estrutura, os membros
dollars e yens ocupam o mesmo espao fsico na memria de modo que no pode ser usado
para armazenar dois valores diferentes simultaneamente. Voc pode definir um valor para o
preo dollars ou em yens, mas no em ambos ao mesmo tempo.
3.6.4
Enumeraes (enum)
Enumeraes criam novos tipos de dados para conter algo diferente (no limitado aos valores
fundamentais de dados). Sua forma a seguinte:
enum enumeration_name {
value1,
value2,
value3,
.
.
} object_names;
Por exemplo, poderamos criar um novo tipo de varivel chamada colors_t para armazenar as
cores, com a seguinte declarao:
Pgina | 82 de 93
enum colors_t {black, blue, green, cyan, red, purple, yellow, white};
Observe que no incluem qualquer tipo de dado fundamental na declarao. Para diz-lo de
outra forma, criamos um novo tipo de dados a partir do zero, sem base-lo em qualquer outro
tipo existente. Os possveis valores que as variveis deste novo tipo color_t podem tomar a
constante de novos valores includos dentro de chaves. Por exemplo, uma vez que a
enumerao colors_t declarada as seguintes expresses so vlidas:
1 colors_t mycolor;
2
3 mycolor = blue;
4 if (mycolor == green) mycolor = red;
Neste caso, a varivel y2k de months_t pode conter qualquer um dos 12 possveis valores que
vo de janeiro at dezembro, e, neste caso, so equivalentes aos valores entre 1 e 12 (no
entre 0 e 11, j fizemos january=1, no incio da declarao).
Pgina | 83 de 93
Functions in <algorithm>
Non-modifying sequence operations:
for_each
find
find_if
find_end
find_first_of
adjacent_find
count
count_if
mismatch
equal
template)
Return first position where two ranges differ (function template)
Test whether the elements in two ranges are equal (function
template)
search
search_n
copy_backward
swap
swap_ranges
iter_swap
template)
transform
replace
replace_if
replace_copy
Pgina | 84 de 93
replace_copy_if
fill
fill_n
generate
generate_n
remove
remove_if
remove_copy
remove_copy_if
unique
unique_copy
reverse
reverse_copy
rotate
rotate_copy
random_shuffle
partition
stable_partition
Sorting:
sort
stable_sort
partial_sort
partial_sort_copy
nth_element
upper_bound
equal_range
binary_search
inplace_merge
includes
template)
set_union
set_intersection
Pgina | 85 de 93
set_difference
pop_heap
make_heap
sort_heap
Min/max:
min
max
min_element
max_element
next_permutation
prev_permutation
A.2 complex
header
Complex numbers library
The complex library implements the complex class to contain complex numbers in cartesian form
and several functions and overloads to operate with them:
Classes
complex
Functions
Complex values:
real
imag
abs
arg
norm
conj
polar
Transcendentals overloads:
Pgina | 86 de 93
cos
cosh
exp
log
log10
pow
sin
sinh
sqrt
tan
tanh
Operator overloads:
complex operators
sin
tan
acos
asin
atan
atan2
Hyperbolic functions:
cosh
sinh
tanh
frexp
ldexp
Pgina | 87 de 93
log
log10
modf
Power functions
pow
sqrt
fabs
floor
fmod
Stream properties
Streams have some properties that define which functions can be used on them and how these
will treat the data input or output through them. Most of these properties are defined at the
moment the stream is associated with a file (opened) using the http://www.cplusplus.com/fopen
function:
Read/Write Access
Specifies whether the stream has read or write access (or both) to the physical media
they are associated with.
Text / Binary
Text streams are thought to represent a set of text lines, each one ending with a newline character. Depending on the environment where the application is run some
character translation may occur with text streams to adapt some special characters to
the text file specifications of the environment. A binary stream, on the other hand, is a
sequence of characters written or read from the physical media with no translation,
having a one-to-one correspondence with the characters read or written to the stream.
Buffer
A buffer is a block of memory where data is accumulated before being physically read or
written to the associated file or device. Streams can be either fully buffered, line
Pgina | 88 de 93
buffered or unbuffered. On fully buffered streams, data is read/written when the buffer
is filled, on line buffered streams this happens when a new-line character is
encountered, and on unbuffered streams characters are intended to be read/written as
soon as possible.
Indicators
Streams have certain internal indicators that specify their current state and which affect the
behavior of some input and output operations performed on them:
Error indicator
This indicator is set when an error has occurred in an operation related to the stream.
This indicator can be checked with the ferror function, and can be reset by calling either
to clearerr or to any repositioning function (rewind, fseek and fsetpos).
End-Of-File indicator
When set, indicates that the last reading or writing operation performed with the stream
reached the End of File. It can be checked with the feof function, and can be reset by
calling either to clearerr or to any repositioning function (rewind, fseek and fsetpos).
Position indicator
It is an internal pointer of each stream which points to the next character to be read or
written in the next I/O operation. Its value can be obtained by the ftell and fgetpos
functions, and can be changed using the repositioning functions rewind, fseek and
fsetpos.
Functions
Operations on files:
remove
rename
tmpfile
tmpnam
File access:
fclose
fflush
fopen
freopen
setbuf
setvbuf
Formatted input/output:
fprintf
fscanf
printf
scanf
sprintf
sscanf
vfprintf
Pgina | 89 de 93
vprintf
vsprintf
Character input/output:
fgetc
fgets
fputc
fputs
getc
getchar
gets
putc
putchar
puts
ungetc
Direct input/output:
fread
fwrite
File positioning:
fgetpos
fseek
fsetpos
ftell
rewind
Error-handling:
clearerr
feof
ferror
perror
Macros
EOF
End-of-File (constant)
FILENAME_MAX
NULL
TMP_MAX
And also _IOFBF, _IOLBF, _IONBF, BUFSIZ, FOPEN_MAX, L_tmpnam, SEEK_CUR, SEEK_END
and SEEK_SET, each described with its corresponding function.
Pgina | 90 de 93
Types
FILE
fpos_t
size_t
(type)
Unsigned integral type (type)
Functions
String conversion:
atof
atoi
atol
strtod
strtol
strtoul
srand
free
malloc
realloc
Environment:
abort
atexit
exit
getenv
system
Pgina | 91 de 93
qsort
Integer arithmethics:
abs
div
labs
ldiv
Multibyte characters:
mblen
mbtowc
wctomb
Multibyte strings:
mbstowcs
wcstombs
Macros
EXIT_FAILURE
EXIT_SUCCESS
MB_CUR_MAX
NULL
RAND_MAX
Types
div_t
ldiv_t
size_t
Functions
Time manipulation
clock
difftime
Pgina | 92 de 93
mktime
time
Conversion:
asctime
ctime
gmtime
localtime
strftime
Macros
CLOCKS_PER_SEC
NULL
types
clock_t
size_t
time_t
struct tm
Pgina | 93 de 93