Como Trabalhar com Variáveis, Tipos de Dados e Expressões Aritméticas na Linguagem de Programação C

C tem uma rica variedade de operadores matemáticos que você pode utilizar para manipular seus dados. Neste capítulo da Programação em C, 4ª Edição, Stephen G. Kochan cobre os tipos de dados int, float, double, char, e _Bool, modificando os tipos de dados com curto, longo e longo, as regras para nomear variáveis, operadores matemáticos básicos e expressões aritméticas, e tipo casting.

O verdadeiro poder dos programas que você cria é a manipulação de dados. Para realmente tirar proveito desse poder, você precisa entender melhor os diferentes tipos de dados que você pode usar, assim como como criar e nomear variáveis. C tem uma rica variedade de operadores de matemática que você pode usar para manipular seus dados. Neste capítulo, você irá abordar:

  • Os tipos de dados int, float, double, char, e _Bool
  • Modificar os tipos de dados com short, long, e longo
  • As regras para nomeação de variáveis
  • Os operadores de matemática básica e expressões aritméticas
  • Fusão por tipos

Os tipos de dados e constantes

Você já foi exposto ao tipo de dados básicos C int. Como você se lembrará, uma variável declarada como sendo do tipo int pode ser usada para conter apenas valores integrais – isto é, valores que não contenham casas decimais.

A linguagem de programação C fornece quatro outros tipos de dados básicos: float, double, char, e _Bool. Uma variável declarada como do tipo float pode ser usada para armazenar números de pontos flutuantes (valores que contêm casas decimais). O tipo duplo é o mesmo que o tipo de margem de flutuação, apenas com aproximadamente o dobro da precisão. O tipo de dado char pode ser usado para armazenar um único caractere, como a letra ‘a’, o caractere numérico ‘6’ ou um ponto-e-vírgula (‘;’) (mais sobre isso mais adiante). Finalmente, o tipo de dado _Bool pode ser usado para armazenar apenas os valores 0 ou 1. Variáveis deste tipo são usadas para indicar uma situação on/off, yes/no, ou true/false. Estas escolhas um ou outro são também conhecidas como escolhas binárias.

Em C, qualquer número, caractere único, ou cadeia de caracteres é conhecida como uma constante. Por exemplo, o número 58 representa um valor inteiro constante. A cadeia de caracteres “Programação em C é divertida.\n” é um exemplo de uma cadeia de caracteres constante. Expressões que consistem inteiramente de valores constantes são chamadas expressões constantes. Então, a expressão

128 + 7 - 17

é uma expressão constante porque cada um dos termos da expressão é um valor constante. Mas se i fosse declarada como uma variável inteira, a expressão

128 + 7 – i

não representaria uma expressão constante porque seu valor mudaria com base no valor de i. Se i for 10, a expressão é igual a 125, mas se i for 200, a expressão é igual a -65.

The Integer Type int

Em C, uma constante inteira consiste em uma seqüência de um ou mais dígitos. Um sinal de menos que precede a sequência indica que o valor é negativo. Os valores 158, -10, e 0 são todos exemplos válidos de constantes inteiras. Não são permitidos espaços embutidos entre os dígitos, e valores maiores que 999 não podem ser expressos usando vírgulas. (Então, o valor 12.000 não é uma constante inteira válida e deve ser escrito como 12000.)

Dois formatos especiais em C permitem que constantes inteiras sejam expressas em uma base que não seja decimal (base 10). Se o primeiro dígito do valor inteiro for um 0, o inteiro é tomado como expresso em notação octal – isto é, na base 8. Nesse caso, os dígitos restantes do valor devem ser dígitos de base válidos – 8 dígitos e, portanto, devem ser 0-7. Assim, para expressar o valor 50 na base 8 em C, que é equivalente ao valor 40 em decimal, é usada a notação 050. Da mesma forma, a constante octal 0177 representa o valor decimal 127 (1 × 64 + 7 × 8 + 7). Um valor inteiro pode ser exibido no terminal em notação octal, usando os caracteres de formato %o na cadeia de formato de uma declaração printf(). Neste caso, o valor é exibido em octal sem um zero inicial. O caractere de formato %#o faz com que um zero inicial seja exibido antes de um valor octal.

Se uma constante inteira for precedida por um zero e a letra x (minúscula ou maiúscula), o valor é tomado como sendo expresso em notação hexadecimal (base 16). Imediatamente após a letra x estão os dígitos do valor hexadecimal, que podem ser compostos pelos dígitos 0-9 e as letras a-f (ou A-F). As letras representam os valores 10-15, respectivamente. Assim, para atribuir o valor hexadecimal FFEF0D a uma variável inteira chamada rgbColor, a instrução

rgbColor = 0xFFEF0D;

pode ser usada. Os caracteres de formato %x mostram um valor em formato hexadecimal sem o 0x inicial, e usando letras minúsculas a-f para dígitos hexadecimais. Para exibir o valor com o 0x à esquerda, você usa os caracteres de formato %#x, como no seguinte:

printf ("Color is %#x\n", rgbColor);

Uma maiúscula x, como em %X ou %#X, pode ser usada para exibir o x à esquerda e os dígitos hexadecimais que seguem usando letras maiúsculas.

Tamanhos e Intervalos de Armazenamento

Todos os valores, seja um caractere, inteiro ou número de ponto flutuante, tem um intervalo de valores associados a ele. Esse intervalo tem a ver com a quantidade de armazenamento que é alocada para armazenar um determinado tipo de dado. Em geral, esse montante não é definido no idioma. Normalmente depende do computador que está sendo executado e é, portanto, chamado de dependente da implementação ou da máquina. Por exemplo, um número inteiro pode ocupar 32 bits no seu computador, ou talvez seja armazenado em 64. Você nunca deve escrever programas que façam suposições sobre o tamanho dos seus tipos de dados. Você tem, no entanto, a garantia de que uma quantidade mínima de armazenamento será reservada para cada tipo de dados básicos. Por exemplo, é garantido que um valor inteiro será armazenado em um mínimo de 32 bits de armazenamento, que é o tamanho de uma “palavra” em muitos computadores.

O tipo de flutuação do número flutuante

Uma variável declarada como sendo do tipo flutuante pode ser usada para armazenar valores contendo casas decimais. Uma constante de ponto flutuante é distinguida pela presença de uma vírgula decimal. É possível omitir dígitos antes do ponto decimal ou dígitos após o ponto decimal, mas obviamente não se pode omitir ambos. Os valores 3., 125,8 e -,0001 são todos exemplos válidos de constantes de vírgula flutuante. Para exibir um valor de ponto flutuante no terminal, os caracteres de conversão de impressão %f são usados.

Constantes de ponto flutuante também podem ser expressas em notação científica. O valor 1.7e4 é um valor de ponto flutuante expresso nesta notação e representa o valor 1.7 × 104. O valor antes da letra e é conhecido como mantissa, enquanto que o valor que se segue é chamado de expoente. Este expoente, que pode ser precedido por um sinal opcional de mais ou menos, representa o poder de 10 pelo qual a mantissa deve ser multiplicada. Assim, na constante 2,25e-3, o 2,25 é o valor da mantissa e -3 é o valor do expoente. Esta constante representa o valor 2,25 × 10-3, ou 0,00225. A propósito, a letra e, que separa a mantissa do expoente, pode ser escrita em minúsculas ou maiúsculas.

Para exibir um valor em notação científica, os caracteres de formato %e devem ser especificados na string de formato printf(). Os caracteres de formato printf() %g podem ser usados para permitir que a printf() decida se o valor do ponto flutuante deve ser exibido em notação normal de ponto flutuante ou em notação científica. Esta decisão é baseada no valor do expoente: Se for menor que -4 ou maior que 5, o formato %e (notação científica) é utilizado; caso contrário, o formato %f é utilizado.

Utilizar os caracteres do formato %g para exibir números de vírgula flutuante- produz a saída esteticamente mais agradável.

Uma constante flutuante hexadecimal consiste de uma constante flutuante 0x ou 0X, seguida de um ou mais dígitos decimais ou hexadecimais, seguidos de um p ou P, seguido de um expoente binário assinado opcionalmente. Por exemplo, 0x0.3p10 representa o valor 3/16 × 210 = 0.5.

O tipo de precisão estendida duplo

O tipo duplo é muito semelhante ao tipo de flutuador, mas é usado sempre que o intervalo fornecido por uma variável flutuante não é suficiente. As variáveis declaradas como sendo do tipo duplo podem armazenar aproximadamente o dobro dos dígitos significativos que uma variável do tipo flutuante. A maioria dos computadores representa valores duplos usando 64 bits.

Sem dizer o contrário, todas as constantes de ponto flutuante são tomadas como valores duplos pelo compilador C. Para expressar explicitamente uma constante flutuante, anexe um f ou F ao final do número, como segue:

12.5f

Para exibir um valor duplo, os caracteres de formato %f, %e, ou %g, que são os mesmos caracteres de formato usados para exibir um valor flutuante, podem ser usados.

O tipo de caractere único char

Uma variável char pode ser usada para armazenar um caractere único.1 Uma constante de caractere é formada por um caractere dentro de um par de aspas simples. Então ‘a’, ‘;’, e ‘0’ são todos exemplos válidos de constantes de caracteres. A primeira constante representa a letra a, a segunda é um ponto-e-vírgula, e a terceira é o caractere zero, que não é o mesmo que o número zero. Não confunda uma constante de caracteres, que é um caractere único entre aspas simples, com uma cadeia de caracteres, que é qualquer número de caracteres entre aspas duplas.

A constante de caracteres ‘\n’ – o novo caractere de linha – é uma constante de caracteres válida mesmo que pareça estar em contradição com a regra citada anteriormente. Isto porque o caractere da barra invertida é um caractere especial no sistema C e na verdade não conta como um caractere. Em outras palavras, o compilador C trata o caractere ‘\n’ como um único caractere, mesmo que ele seja formado por dois caracteres. Existem outros caracteres especiais que são iniciados com o caractere de contrabarra. Consulte o Apêndice A, “Resumo da Linguagem C”, para uma lista completa.

Os caracteres de formato %c podem ser usados em uma chamada printf() para exibir o valor de uma variável char no terminal.

O Tipo de Dados Booleanos _Bool

A _Variável Bool é definida na linguagem para ser grande o suficiente para armazenar apenas os valores 0 e 1. A quantidade precisa de memória que é usada não é especificada. As variáveis _Bool são utilizadas em programas que precisam indicar uma condição Booleana. Por exemplo, uma variável deste tipo pode ser usada para indicar se todos os dados foram lidos de um arquivo.

Por convenção, 0 é usado para indicar um valor falso, e 1 indica um valor verdadeiro. Ao atribuir um valor a uma variável _Bool, um valor 0 é armazenado como 0 dentro da variável, enquanto que qualquer valor não zero é armazenado como 1.

Para facilitar o trabalho com variáveis _Bool no seu programa, o arquivo de cabeçalho padrão <stdbool.h> define os valores bool, true, e false. Um exemplo disto é mostrado no Programa 5.10A no Capítulo 5, “Tomando Decisões”

No Programa 3.1, os tipos de dados básicos C são usados.

Programa 3.1 Usando os Tipos de Dados Básicos

Programa 3.1 Saída

integerVar = 100floatingVar = 331.790009doubleVar = 8.440000e+11doubleVar = 8.44e+11charVar = WboolVar = 0;

A primeira declaração do Programa 3.1 declara a variável integerVar como sendo uma variável inteira e também atribui a ela um valor inicial de 100, como se as duas instruções seguintes tivessem sido usadas em seu lugar:

int integerVar;integerVar = 100;

Na segunda linha da saída do programa, observe que o valor de 331,79, que é atribuído a floatingVar, é realmente exibido como 331,790009. Na verdade, o valor real exibido depende do sistema de computador específico que você está usando. O motivo desta imprecisão é a forma particular pela qual os números são representados internamente dentro do computador. Você provavelmente já encontrou o mesmo tipo de imprecisão ao lidar com números na sua calculadora de bolso. Se você dividir 1 por 3 na sua calculadora, você obtém o resultado .33333333, com talvez alguns 3s adicionais colados no final. A sequência de 3s é a aproximação da calculadora para um terço. Teoricamente, deve haver um número infinito de 3s. Mas a calculadora pode conter apenas tantos dígitos, portanto a imprecisão inerente da máquina. O mesmo tipo de imprecisão se aplica aqui: Certos valores de vírgula flutuante não podem ser exatamente representados dentro da memória do computador.

Ao exibir os valores das variáveis flutuantes ou duplas, você tem a escolha de três formatos diferentes. Os caracteres %f são usados para exibir valores de uma forma padrão. A menos que seja dito o contrário, printf() sempre exibe um valor flutuante ou duplo com seis casas decimais arredondadas. Você verá mais adiante neste capítulo como selecionar o número de casas decimais que são exibidas.

Os caracteres %e são usados para exibir o valor de uma variável flutuante ou dupla na notação científica. Mais uma vez, seis casas decimais são automaticamente exibidas pelo sistema.

Com os caracteres %g, o printf() escolhe entre %f e %e e também remove automaticamente da exibição quaisquer zeros residuais. Se nenhum dígito segue o ponto decimal, ele não exibe que.

Na instrução next-to-last printf(), os caracteres %c são usados para exibir o caractere único ‘W’ que você atribuiu a charVar quando a variável foi declarada. Lembre-se que enquanto uma string de caracteres (como o primeiro argumento para printf()) é incluída dentro de um par de aspas duplas, uma constante de caracteres deve sempre ser incluída dentro de um par de aspas simples.

A última printf() mostra que uma variável _Bool pode ter seu valor exibido usando os caracteres de formato inteiro %i.

Type Specifiers: long, long, short, unsigned, and signed

Se o especificador long for colocado diretamente antes da declaração int, a variável inteira declarada é de longo alcance em alguns sistemas de computador. Um exemplo de uma declaração de int longo pode ser

long int factorial;

Esta declara que a variável factorial é uma variável inteira longa. Assim como com flutuações e duplas, a precisão particular de uma variável longa depende do seu sistema informático em particular. Em muitos sistemas, um int e um int longo têm o mesmo intervalo e podem ser usados para armazenar valores inteiros de até 32 bits de largura (231 – 1, ou 2.147.483.647).

Um valor constante do tipo int longo é formado opcionalmente anexando a letra L (maiúscula ou minúscula) no final de uma constante inteira. Não são permitidos espaços entre o número e o L. Assim, a declaração

long int numberOfPoints = 131071100L;

declara a variável númeroOfPoints para ser do tipo int longo com um valor inicial de 131.071.100,

Para exibir o valor de um int longo usando printf(), a letra l é usada como um modificador antes dos caracteres de formato inteiro i, o, e x. Isto significa que os caracteres de formato %li podem ser usados para exibir o valor de um int longo em formato decimal, os caracteres %lo podem exibir o valor em formato octal, e os caracteres %lx podem exibir o valor em formato hexadecimal.

Há também um tipo de dado inteiro longo, portanto

long long int maxAllowedStorage;

declara que a variável indicada tem a precisão estendida especificada, que é garantida como tendo pelo menos 64 bits de largura. Em vez de uma única letra l, dois ls são usados na string printf para exibir números inteiros longos, como em “%lli”.

O especificador longo também é permitido em frente a uma declaração dupla, como segue:

long double US_deficit_2004;

Uma constante dupla longa é escrita como uma constante flutuante com a letra l ou L imediatamente a seguir, como em

1.234e+7L

Para exibir um duplo longo, o modificador L é usado. Assim, %Lf exibe um valor duplo longo na notação de ponto flutuante, %Le exibe o mesmo valor na notação científica, e %Lg diz ao printf() para escolher entre %Lf e %Le.

O especificador curto, quando colocado na frente da declaração int, diz ao compilador C que a variável particular sendo declarada é usada para armazenar valores inteiros bastante pequenos. A motivação para usar variáveis curtas é principalmente a de conservar espaço de memória, o que pode ser um problema em situações nas quais o programa precisa de muita memória e a quantidade de memória disponível é limitada.

Em algumas máquinas, um int curto ocupa metade da quantidade de armazenamento como faz uma variável int regular. Em qualquer caso, é garantido que a quantidade de espaço alocado para um int curto não será inferior a 16 bits.

Não há como escrever explicitamente uma constante do tipo int curto em C. Para exibir uma variável int curta, coloque a letra h na frente de qualquer um dos caracteres normais de conversão de números inteiros: %hi, %ho, ou %hx. Alternativamente, você também pode usar qualquer um dos caracteres de conversão de números inteiros para exibir os números inteiros curtos, devido à forma como eles podem ser convertidos em números inteiros quando são passados como argumentos para a rotina printf().

O especificador final que pode ser colocado na frente de uma variável int é usado quando uma variável inteira será usada para armazenar apenas números positivos. A declaração

unsigned int counter;

declara ao compilador que o contador de variáveis é usado para conter apenas valores positivos. Ao restringir o uso de uma variável inteira ao armazenamento exclusivo de números inteiros positivos, a precisão da variável inteira é estendida.

Uma constante int não assinada é formada colocando a letra u (ou U) após a constante, como segue:

0x00ffU

Você pode combinar as letras u (ou U) e l (ou L) ao escrever uma constante inteira, assim

20000UL

diz ao compilador para tratar a constante 20000 como um comprimento não assinado.

Uma constante inteira que não é seguida por nenhuma das letras u, U, l, ou L e que é muito grande para caber em uma int de tamanho normal é tratada como uma int sem assinatura pelo compilador. Se for muito pequena para caber numa int sem assinatura, o compilador trata-a como uma int longa. Se ainda não cabe dentro de uma int longa, o compilador a torna uma int longa não assinada. Se não caber lá, o compilador trata-a como uma int longa se caber, e como uma int longa não assinada.

Ao declarar variáveis como sendo do tipo int longa, int longa, int curta, ou int não assinada, você pode omitir a palavra-chave int. Portanto, o contador de variáveis não assinadas poderia ter sido declarado equivalentemente da seguinte forma:

unsigned counter;

Você também pode declarar variáveis char como não assinadas.

O qualificador assinado pode ser usado para dizer explicitamente ao compilador que uma determinada variável é uma quantidade assinada. Seu uso é principalmente na frente da declaração char, e discussões posteriores são adiadas até o Capítulo 13, “Mais sobre Tipos de Dados”

Não se preocupe se as discussões desses especificadores parecerem um pouco esotéricas para você neste ponto. Em seções posteriores deste livro, muitos desses diferentes tipos são ilustrados com exemplos reais de programas. O capítulo 13 entra em mais detalhes sobre tipos de dados e conversões.

Tabela 3.1 resume os tipos de dados básicos e qualificadores.

Tabela 3.1 Tipos de dados básicos