bool
, int
(e variantes),
float
(e variantes)
e char
. char
como inteiros.Alertar para importância de ler as folhas teóricas: as aulas não cobrem toda a matéria!
Na nossa analogia da culinária, em que uma receita correspondia a um algoritmo, a que é que corresponde o cozinheiro?
O cozinheiro executa instruções da receita usando os recipientes, o frigorífico e a despensa para preparar os cozinhados. O processador executa instruções de um programa usando as variáveis (memória rápida) e ficheiros no disco rígido (memória lenta) para produzir os seus resultados.As variáveis são portanto a nossa maneira de usar a memória rápida do computador em C++. As variáveis são nomes que nós atribuímos a pedaços de memória.
Em culinária cada recipiente tem um tipo, que enquadra e limita as suas utilizações. Por exemplo, um pimenteiro é usado para guardar grãos de pimenta.
Também em C++.
Por exemplo:
Esta instrução define uma nova variável com:
bool encontrado = false;
bool
, ou seja Booleano (falar do Sr. Boole), só pode tomar os valores falso e
verdadeiro.Esta variável, quando o programa é compilado e executado, é colocada algures na memória.
No nosso computador de papel e lápis, pensem na memória como um bloco de notas em que cada folha pode ser destinada a uma variável.
Desenhar bloco de notas em que a primeira página se chama
encontrado
e contém o valor falso. Cada página é desenhada em
UML.
Outros exemplos:
Chamar "decimal" aos float
.
Explicar cada um dos exemplos. Caracteres não são só letras! Explicar que
int número_de_alunos = 30;
float f = 0.0f;
char c = 'A';
30
, 0.0f
, e 'A'
são valores
literais. Isto é, constantes cujos valores são indicados
explicitamente.
O que é a memória do computador? Uma sequência de bits. Quantos? Na mercúrio são 768 Mbytes, ou seja, 805306368 octetos, que são 6442450944 bits! Exacto, seis mil milhões, quatrocentos e quarenta e dois milhões, quatrocentos e cinquenta mil, novecentos e quarenta e quatro! Aproximadamente um bit por cada habitante do planeta. Ou ainda 150 000 páginas densas em 300 livros de quinhentas páginas.
Como são representadas estas variáveis na memória do computador?
Tipicamente cada caractere (variável do tipo char
) é representado
por oito bits (i.e., dígitos binários, com valor 0
ou 1), formando um padrão. Quantos diferentes padrões
é possível formar com 8 bits?
A resposta é 28, ou seja, 256. Se se fizer corresponder cada padrão a um caractere (um símbolo gráfico: letra, dígito decimal, sinal de pontuação, etc.), podem-se representar 256 diferentes caracteres.
É suficiente para português, sê-lo-á para o chinês?
A correspondência usada entre os padrões de bits e os caracteres é chamada um código. O código mais frequente nesta ponta da Europa é o código ISO-Latin-9 (ISO-8859-15), que veio substituir o ISO-Latin-1 (ISO-8859-15) aquando da introdução do euro, e que é uma extensão do código ASCII (American Standard Code for Information Interchange).
Nesse código ISO-Latin-9:
'A' é representado pelo padrão: 01000001
'a' é representado pelo padrão: 01100001
'0' é representado pelo padrão: 00110000
Num outro código, praticamente caído em desuso, como o EBCDIC (Extended Binary Coded Decimal Interchange Code):
'A' é representado pelo padrão: 11000001
'a' é representado pelo padrão: 10000001
'0' é representado pelo padrão: 11110000
Estes padrões costumam ser interpretados como números inteiros em base binária.
Fazer brevíssima revisão, pois em Arquitectura de Computadores já lhes devem ter ensinado esta matéria.
Assim, em ISO-Latin-1:
'A' é representado pelo padrão: (01000001)2 = (65)10
'a' é representado pelo padrão: (01100001)2 = (97)10
'0' é representado pelo padrão: (00110000)2 = (48)10
Note-se que o caractere '0' é representado pelo padrão 00110000, ou seja, 48 na base 10!
Será que temos de nos preocupar com a representação em bits ou com o código em decimal dos caracteres? Em princípio não. Se quisermos guardar um 'A' numa variável fazemos:
e não precisamos de saber o código, ou seja, não é necessário fazer:
char caractere = 'A';
I.e., os valores literais (constantes com valor explícito) do tipo
char caractere = 65;
char
escrevem-se envolvendo o caracter em causa entre plicas.
Porquê têm os valores literais de caracteres de ser escritos entre plicas? Para distinguir os caracteres das variáveis normais:
Qual a diferença?
char c =
...;
...
char a =;
c = a;
c = 'a';
Discutir.
Compare-se com a frase em português:
Está correcta? E se fosseO Joaquim tem cinco vogais.
"O Joaquim" tem cinco vogais.
?
E os inteiros? Como se representam? Os int
têm
tipicamente 32 bits. Para simplificar vamos imaginar que tinham somente
4 bits. Quantos valores diferentes se podem representar com quatro bits? 16!
Se os int
não pudessem representar valores negativos, que valores
representariam?
Discutir numeração binária de novo se necessário. Explicar que são valores de 0 a 24-1. Generalizar.
Que acontece se se somar 1 a 15?
mas o bit mais significativo não cabe nos nossos inteiros de quatro bits! Logo, o resultado é.... 0 (zero)!
1111
0001 +
10000
Que acontece se se somar 2 a 14?
mas o bit mais significativo não cabe nos nossos inteiros de quatro bits! Logo, o resultado é.... 0 (zero) de novo!
1110
0010 +
10000
É mais claro se desenharmos os padrões de bits num relógio.
Colocar 0000 em cima. Primeiro desenhar sem os valores em decimal. Depois colocar os valores em decimal.
E se se pretendesse representar também valores negativos? Qual seria o padrão de bits candidato a representar -1?
Apagar os valores decimais maiores.
Discutir com eles. A resposta é 1111.
E qual o candidato a representar -2? Não é o 1110?
Onde se deve parar?
Discutir com eles. Possibilidades seriam parar em -7 ou -8. Claro que não se pode parar em zero, porque não sobrariam positivos.
As razões porque se pára em -8 são simples:
Discutir e concluir que é -8 a 7.
Que fazer se se quiser saber a representação de -5 sem
olhar para o relógio? Simples, basta subtrair 5 de 16:
E se os nossos inteiros tivessem n bits, qual seria a gama representável?10000
0101 -
1011
Discutir porque é que a resposta é: -2n-1 a 2n-1-1.
A este tipo de representação dos inteiros sem sinal chama-se complemento para 2 e será aprofundada nas aulas de Arquitectura de Computadores.
Quando se define uma variável com tipo int
, está-se a
definir uma variável com 32 bits e representação em
complemento para 2, e que portanto que pode tomar valores entre...
Os computadores são finitos! As variáveis não guardam valores arbitrários!-2147483648 e 2147483647
Aqui falar no bug do ano 2000.
E o bug do ano 2038? Conhecem-no?
O tempo em C++ é contado em segundos a partir de 1970 e guardado
em variáveis do tipo int
. Como os int
têm 32 bits,
a gama de valores é de -2147483648 a 2147483647. Isso são
aproximadamente 68 anos. Logo, em 2038 passa-se para... 1902...
Os caracteres também são interpretados como inteiros. Que valor inteiro tem o caractere 'A'? Como se usa o código ISO-Latin-9, o padrão de 8 bits correspondente ao caractere 'A' é (01000001)2 = (65)10. Que aparecerá então no ecrã dadas as instruções
?
char caractere = 'A';
int código = caractere;
cout << código << endl;
Aparece 65! E se fosse
?
char caractere = 'A';
int código = caractere + 1;
cout << código << endl;
Apareceria 66! E se fosse
?
char caractere = 'A';
cout << caractere << endl;
++caractere;
cout << caractere << endl;
Apareceria
Mas só aparece 'B' porque se está a usar um código em que os códigos correspondentes às letras do alfabeto são sucessivos! Em EBCDIC 'I' é 137 mas 'J' é 145!
A
B
E os float
? Como são representados? Os float
representam
valores decimais na forma de padrões de 32 bits.
Fazer boneco! Incluir s, m e e. Ver figuras das folhas teóricas.
Dos 32 bits:
float
é s m 2e.
Ou seja, o valor maior representável é aproximadamente
2x2127 ou seja 3,4028x1038.
E o mais pequeno positivo é aproximadamente 1x2-126
ou seja 1,1755x10-38.
Explicar bem porque é que (1,11111111111...)2 é aproximadamente 2. Aliás, neste caso é 2 - 2-23.
Que tipos básicos existem?
bool
- curiosamente ocupa 8 bits!char
- vistoshort [int]
- inteiro com 16 bits em complemento para dois (gama de
valores?)unsigned short [int]
- inteiro sem sinal com 16 bits.int
- vistounsigned [int]
- inteiro com 32 bits sem sinallong [int]
- igual a int
em Linux (desperdício! podia ter 64
bits!)unsigned long [int]
- igual a unsigned int
float
- visto, 32 bits e 6 dígitos de significativos [1,17549435
× 10-38 a 3,40282347 × 1038]double
- com 64 bits e 15 dígitos significativos [2,2250738585072014
× 10-308 a 1,7976931348623157 × 10+308]long double
- com 96 bits e 18 dígitos significativos [3.36210314311209350626e
× 10-4932 a 1.18973149535723176502
× 104932]Valores literais:
Mudando de assunto, agora que se viram as variáveis, seus tipos e representação, o que é um programa em C++? É um conjunto de instruções. A instrução mais usual é:
true - bool
-
10int
-
10Llong int
-
10Uunsigned int
-
'A'char
-
'.'char
-
10.0double
-
10.0ffloat
-
10.0Llong double
=
3.3e33300.0
-double
Em que expressão é uma expressão envolvendo os operadores do C++. O operador mais importante é o de atribuição. Este operador tem a forma
expressão;
e tem como resultado atribuir o valor da expressão à variável do lado esquerdo. É uma operação que afecta o estado do programa, pois altera o valor de uma variável.
variável = expressão;
Deixar claro que uma instrução consistindo apenas numa expressão que não afecta o estado do programa não é muito interessante: daí o interesse da atribuição. Referir que o estado do programa é o valor das suas variáveis.
Outros operadores interessantes são os aritméticos: +
,
-
, *
, /
e %
. Destes a divisão
/
e o resto da divisão %
merecem menção especial.
A divisão /
é a divisão inteira se os operandos
forem inteiros.
Que fica em x
depois de:
?
int x = 1 / 2;
Discutir! É 0 (zero).
O resto da divisão inteira só se pode aplicar a operandos inteiros:
dá erro de compilação! O tradutor para linguagem máquina (compilador) não aceita a expressão.
int x = 1.0 % 2.0;
Que fica em x depois de:
?
int x = 15 % 6;
Fica 3.
O tipo do resultado é o tipo dos operandos. Se os operandos forem de tipos diferentes, o operando de um tipo "menos potente" é convertido para o tipo "mais potente" antes do cálculo. Por exemplo:
o que é escrito?
cout << 'a' + 1 << endl;
Discutir. Não é 'b', é 98!
Existem também os operadores relacionais >
, >=
,
<
, <=
e
de igualdade e diferença ==
e !=
. O resultado é um
bool
com valor verdadeiro (literal true
) ou falso (literal false
).
Os operadores respeitam regras de precedência e associatividade. Por exemplo:
escreve 18 ou 16?
cout << 1 + 5 * 3 << endl;
É 16, porque *
tem precedência face a +
.
Por exemplo:
escreve 16 ou 4?
cout << 16 / 2 / 2 << endl;
É 4, porque /
associa-se à esquerda.
Quase todos os operadores em C++ se associam à esquerda. A atribuição é uma excepção:
tem o resultado esperado.
int i, j;
i = j = 0;
Explicar que o valor da operação de atribuição é o valor que fica na variável atribuída.
Exemplo:
Que fica em
int x;
double f;
f = x = 1.3;
f
?
Discutir. double
para int
é possível, mas perde
parte decimal. É preferível explicitar a conversão:
E melhor ainda é fazer apenas uma atribuição por instrução.
int x;
double f;
f = x = int(1.3);
Explicar que a atribuição é uma operação com efeitos laterais, ao contrário da adição, por exemplo.
É comum encontrar-se expressões do tipo:
O C++ permite abreviar estas expressões para:
x = x + 10
x += 10
+=
, -=
, *=
, /=
, %=
são
todos operadores especiais de atribuição.
Finalmente, também são frequentes expressões do tipo:
O C++ permite abreviar estas expressões para:
x = x + 1
x += 1
ou
++x
x++
Recomendar vivamente a primeira!
E de igual modo para a subtracção. Chamam-se operadores
de incrementação (++
) e decrementação (--
)
prefixos ou sufixos.
Na versão prefixo o valor da operação é o valor da variável depois de incrementada. Na versão sufixo o valor da operação é o valor da variável antes de incrementada. Compare-se:
com
int i = 0;
int j = ++i;
No primeiro caso
int i = 0;
int j = i++;
j
termina com 1, no segundo com 0! Em ambos os casos
i
fica com 1. Perceberam?
Discutir.