Variáveis

Imagine que, ao final da aula de Algoritmos e Estruturas de Dados, você se dirigiu a uma cantina. Lá, consultou o preço de um copo de café (R$ 1,00) e de um pão de queijo (R$ 5,00), optando por comprar os dois produtos. Saindo da cantina, você encontra um colega, que lhe pergunta o preço do copo de café. Nesse momento, você provavelmente se lembrará que o café custou R$ 1,00 e compartilhará a informação.

Nessa situação fantasiosa, observe que o apreciador de pão de queijo e de café não anotou em nenhum momento o preço de cada produto: ele simplesmente se lembrou. De alguma forma, seu cérebro se encarregou de registrar essa informação (vamos deixar o entendimento de como isso acontece para os especialistas). Por parecer natural que a pessoa se lembre de informações, temos a impressão de nenhum processo especial foi necessário nessa situação.

Para o computador, no entanto, o processo não é tão simples assim. Embora pareçam inteligentes, computadores não são capazes de se lembrar de informações e acontecimentos de forma automática. Tudo precisa ser feito de forma planejada. Assim, quando estamos desenvolvendo um programa, precisamos ter o cuidado de fazer com que as informações importantes sejam armazenadas para que sejam recuperadas depois (mesmo que esse depois seja meio segundo).

De forma bem simples, é como se o computador sempre precisasse anotar as informações em um papel ✍🏻

🥣 Entendendo o conceito

Os programas de computador, independentemente de seu tamanho, precisam lidar com diversos valores. Uma simples mensagem enviada pelo WhatsApp, por exemplo, envolve o armazenamento de, pelo menos, os seguintes dados:

  1. a identificação do usuário que escreveu a mensagem;
  2. o conteúdo da mensagem;
  3. o horário de envio.

Cada valor a ser utilizado em um software precisa ocupar um espaço próprio na memória. A memória de um computador é comumente representada como um armário com vários espaços. Assim como escolhemos uma posição disponível quando precisamos guardar algum objeto, selecionamos uma posição disponível da memória quando precisamos armazenar um valor no programa de computador.

Reservar um espaço na memória parece ser um procedimento bastante complicado, mas não é. Embora cada posição de memória tenha uma identificação própria (chamada de endereço de memória e representada em hexadecimal), podemos criar um apelido para essa posição de memória. A esse apelido damos o nome de variável.

Nas linguagens de máquina, o programador armazenava valores informando diretamente os endereços de memória. Com as linguagens de montagem, já abarcando o conceito de variáveis, os programas não só ficaram mais legíveis (facilitando o desenvolvimento e a manutenção), como também a seleção dos endereços de memória passa a ser feita de forma automática.

Voltando ao exemplo do WhatsApp, precisaríamos de três variáveis (e, portanto, três posições de memória) para armazenar o autor, o conteúdo da mensagem e o horário.

🕵️ Um Raio-X da variável

De acordo com Robert Sebesta (2018), no livro "Linguagens de Programação", uma variável pode ser compreendida como um conjunto de seis atributos:

  • Nome:
    • O identificador único usado para se referir à variável durante o código.
  • Endereço:
    • O endereço de memória onde a variável está armazenada.
  • Valor:
    • O conteúdo armazenado na variável, que pode ser um número, um caractere, uma string, ou qualquer outro tipo de dado.
  • Tipo:
    • O tipo de dado que a variável pode armazenar, como inteiro, ponto flutuante, caractere, etc.
  • Tempo de Vida:
    • O período durante o qual a variável existe na memória. Pode ser de curta duração (temporária) ou de longa duração (persistente).
  • Escopo:
    • A região do código onde a variável é acessível. Pode ser local (restrito a uma função ou bloco) ou global (acessível em todo o programa).

💾 Tipos de dados

Conforme explicado por Sebesta (2018), um tipo de dado pode ser definido como uma "coleção de valores de dados e um conjunto de operações pré-definidas sobre eles".

Detalhes técnicos

Agora que entendemos os conceitos, podemos nos aprofundar nos aspectos técnicos.

No maior nível de detalhe, a memória principal é formada por células, cada uma com a capacidade de armazenamento de um bit (0 ou 1). No entanto, as células não são normalmente utilizadas de forma isolada. Tipicamente, trabalhamos com conjuntos de oito células (8 células = 8 bits = 1 byte). Esse conjunto de células recebe o nome de palavra, enquanto a quantidade de células é chamada de tamanho de palavra.

Tipo de DadoEspaço de MemóriaIntervalo de Representação
char1 byte-128 a 127 ou 0 a 255 (para unsigned)
short2 bytes-32,768 a 32,767 ou 0 a 65,535 (unsigned)
int4 bytes-2,147,483,648 a 2,147,483,647
long4 ou 8 bytes-2,147,483,648 a 2,147,483,647
float4 bytesPrecisão de 6 dígitos decimais
double8 bytesPrecisão de 15 dígitos decimais
long double8, 12 ou 16 bytesPrecisão estendida
unsigned int4 bytes0 a 4,294,967,295
signed char1 byte-128 a 127
unsigned char1 byte0 a 255

➖ Por que intervalos negativos?

A diferença da capacidade de armazenamento entre os tipos int e unsigned int (por exemplo) pode provocar uma estranheza inicial. Se ambos os tipos ocupam o mesmo espaço de armazenamento, por que o intervalo de valores representáveis muda?

Para entender isso, precisamos relembrar como funciona a representação de números negativos no sistema binário. Acompanhe, a seguir, a tabela:

🧮 Sistema de representação binária com 4 bits

Na tabela de conversão acima, se atribuirmos o valor 1 a cada célula de memória, teremos o binário 11112, que equivale a 3110. Observe, no entanto, que essa representação binária permite apenas a representação de inteiros positivos.

8421
1111

Para representarmos um valor negativo, precisamos usar uma célula para indicar que aquele valor é negativo. A célula responsável por isso é a primeira célula, que representa o bit mais significativo (de maior valor que, no caso anterior, seria a célula representando o número 8). A tabela de conversão passa a ficar da seguinte forma:

-421
1111

Observe que agora conseguimos representar tanto valores positivos quanto negativos, porém o intervalo de valores representáveis é menor, já que uma célula de memória precisou ser destinada à representação do sinal, em detrimento do valor.

🗣️ Declarações implícitas e explícitas

Apesar de simples, a declaração de variáveis pode ocorrer de formas distintas, de acordo com a estratégia adotada pela linguagem de programação. Em seu livro, Robert Sebesta classifica duas abordagens para a declaração de variáveis:

Declaração Explícita:

Na declaração explícita de variáveis, o programador especifica explicitamente o tipo da variável durante a declaração. Isso é mais comum em linguagens de programação estáticas, onde os tipos são definidos em tempo de compilação. Em C, por exemplo:

int a = 5;        // a é explicitamente declarado como um inteiro
double b = 2.718; // b é explicitamente declarado como um número de ponto flutuante

Declaração Implícita:

Na declaração implícita de variáveis, o tipo da variável não é explicitamente especificado, e a linguagem de programação infere automaticamente o tipo com base no valor atribuído à variável. Isso é mais comum em linguagens de programação dinâmicas, onde os tipos são determinados em tempo de execução. Aqui está um exemplo em Python:

x = 10  # x é inferido como um inteiro (int)
y = 3.14  # y é inferido como um número de ponto flutuante (float)

A diferença fundamental entre esses dois métodos é a abordagem para o tratamento de tipos de dados, que estudaremos a seguir.

📖 Bibliografia

  • SEBESTA, Robert W. Conceitos de linguagens de programação. 11. ed. Porto Alegre: Bookman, 2018. xvi, 757 p. ISBN 9788582604687.

https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html

https://www.tutorialspoint.com/cprogramming/c_data_types.htm