Variáveis
Definição e Inicialização
A maneira mais simples de armazenar dados em C é pelo uso de variáveis.
Variáveis simples podem ser criadas especificando:
- O tipo de dado que a variável armazena.
- Seu declarador, que nos casos mais simples é simplesmente o identificador (nome) da variável
Para armazenar um número inteiro podemos criar uma variável do tipo int
. Vamos
criar, por exemplo, a variável num
com a sintaxe <tipo> <declarador>;
:
int num;
Como a variável num
foi definida sem algum valor especificado, na maioria dos
casos ela é uma variável não inicializada—armazena um valor "lixo" que já estava
na memória. Para inicializá-la, basta especificar um inicializador (valor
inicial), tornando a sintaxe <tipo> <declarador> = <inicializador>;
:
int num = 62;
Assim, a variável armazena o número 62
e não algum valor aleatório. O 62
pode ser trocado por qualquer outro número representável como um int
, e.g.
-5
ou 0
.
Várias variáveis podem ser definidas de uma só vez, para isso basta utilizar a
sintaxe <tipo> <decl-init-lista>;
, sendo decl-init-lista
uma lista (separada
por vírgula) de 1 ou mais declaradores opcionalmente seguidos de
inicializadores. Seguem 3 exemplos:
int a = 62, b = 30, c = 49;
int d, e = 50, f;
int g = 32, h, i;
Uso
Uma variável substituir um valor em vários casos, como uma chamada de função. As
duas funções a seguir retornam o mesmo resultado, porém a primeira faz o uso de
uma variável n
:
int foo(void)
{
int n = 13;
return log(n);
}
int bar(void)
{
return log(13);
}
Variáveis, assim como o nome sugere, podem ter seus valores alterados durante a
execução do código. A função a seguir retorna o valor 5
, e não 99
:
int foo(void)
{
int n = 99;
n = 5;
return n;
}
Escopo
Todos os identificadores, como nomes de variáveis e funções, possuem um escopo que determina onde podem ser acessados.
Escopo de Bloco
Os parâmetros de uma função podem ser acessados apenas em seu corpo, isso
significa que n
pode ser acessado em foo
mas não em bar
:
int foo(int n)
{
return n; // Okay
}
int bar(void)
{
return n; // Erro: n não existe nesse contexto
}
Isso se chama escopo de bloco, ou seja, o identificador é acessível dentro do
bloco ({}
}) a que pertence. No caso da seguinte variável n
, o escopo é o
mesmo que seria como parâmetro:
int foo(void)
{
int n;
return n; // Okay
}
int bar(void)
{
return n; // Erro: n não existe nesse contexto
}
Um identificador também não pode ser definido duas vezes no mesmo bloco, mas blocos podem ser aninhados:
int foo(void)
{
int n;
int n; // Erro: n já foi definido nesse bloco
}
int bar(void)
{
int n;
{
int n; // Okay: Esse n está contido apenas nesse bloco
}
}
Vale lembrar, também, que mesmo sendo o mesmo identificador, n
representa uma
entidade diferente em cada bloco que é redefinido:
int foo(void)
{
int n = 5;
{
int n = 10;
return n; // Isso retorna 10 e não 5, pois a redefinição de n torna o
// n anterior inacessível
}
return n; // Isso retorna 5 pois aqui o segundo n sai de escopo e o primeiro
// volta a estar acessível
}
Caso um identificador não seja redefinido em um bloco aninhado, sua definição anterior será acessada:
int foo(void)
{
int n = 5;
{
return n; // Isso retorna 5
}
}
Escopo de Arquivo
Uma variável declarada fora de um bloco possui escopo de arquivo—pode ser acessada em qualquer lugar do arquivo após sua declaração:
int n = 5;
int foo(void)
{
return n; // Retorna 5
}
int bar(void)
{
return n; // Retorna 5
}
Diferente de variáveis com escopo de bloco, variáveis com escopo de arquivo são
inicializadas com um valor definido de acordo com seu tipo. Se o inicializador
fosse removido do código acima n
armazenaria 0
, enquanto se n
tivesse
escopo de bloco não haveria nenhuma garantia de seu valor.
Referências
- Padrão C18 (ISO/IEC 9899:2018):
- 6.2.1 Scopes of identifiers
- 6.2.5 Types
- 6.7 Declarations
- 6.7.9 Initialization