cblc/aulas/04-variaveis/README.org

182 lines
4.6 KiB
Org Mode
Raw Permalink Normal View History

2025-03-20 15:05:11 -03:00
#+title: Curso Básico da Linguagem C
#+subtitle: Aula 4: Variáveis e ponteiros
#+author: Blau Araujo
#+startup: show2levels
#+options: toc:3
* Variáveis e ponteiros
- *Variáveis* são elementos da linguagem que representam dados na memória.
- *Ponteiros* são variáveis que representam endereços de dados na memória.
** Declaração e definição
Variáveis precisam ser declaradas e definidas antes de serem utilizadas.
Exemplo (=var1.c=):
#+begin_src c
#include <stdio.h>
int main(void) {
int a = 10; /* Variável declarada e inicializada (definida). */
int b; /* Variável declarada, mas não inicializada! */
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("a + b = %d\n", a + b);
return 0;
}
#+end_src
Compilando e executando:
#+begin_example
:~$ gcc -o var1 var1.c
:~$ ./var1
a = 10
b = 361680176
a + b = 361680186
#+end_example
Observe:
- A compilação não emitiu avisos e nem terminou com erro.
- A variável =b= (não inicializada) avaliou um valor qualquer.
*** Por que isso aconteceu?
Ao ser declarada, a variável recebeu um endereço e um tipo (=int=). Como não
foi inicializada, seu valor será o que quer que esteja nos 4 bytes da
memória a partir do endereço designado para =b=.
Por exemplo:
#+begin_example
a -> 0x7ffd45c33fdc: 0a 00 00 00 (10)
b -> 0x7ffd45c33fd8: 3a cd 8e 15 (361680176) <-- LIXO!
#+end_example
*** Como evitar esse erro?
A primeira (e mais óbvia) opção é não se esquecer de atribuir um valor
à variável antes de usá-la, mas a compilação poderia ter sido feita com
as opções de avisos:
- =-Wall=: Habilita todos os avisos sobre problemas evitáveis no código.
- =-Wextra=: Habilita avisos adicionais.
- =-Werror=: Trata todos os avisos como erros fatais.
Exemplo:
#+begin_example
:~$ gcc -o var1 var1.c -Wall -Wextra -Werror
var1.c: In function main:
var1.c:10:5: error: b is used uninitialized [-Werror=uninitialized]
10 | printf("b = %d\n", b);
| ^~~~~~~~~~~~~~~~~~~~~
var1.c:7:9: note: b was declared here
7 | int b; /* Variável declarada, mas não inicializada! */
| ^
cc1: all warnings being treated as errors
#+end_example
** Atributos das variáveis
Toda variável tem como atributos...
- Um nome (identificador);
- Um valor associado;
- O endereço do valor associado.
O nome da variável expressa o seu valor:
#+begin_src c
int a = 21;
int b = a; // O valor de 'b' é o valor de 'a' (21).
int c = a + b; // O valor de 'c' é 21+21 (42).
#+end_src
Para que uma variável expresse o endereço do valor associado, nós utilizamos
o operador unário =&= antes de seu nome:
#+begin_src c
int a = 123;
printf("Valor de a : %d", a);
printf("Endereço de a: %p", &a); // Imprime o endereço do dado em 'a'.
#+end_src
O tamanho do tipo da variável é expresso com o operador =sizeof(VAR)=:
#+begin_src c
int a = 10;
int b = sizeof(a); // O valor de 'b' será 4 (bytes).
#+end_src
#+begin_quote
O tipo do valor expresso por =sizeof= é =size_t=, um apelido para =unsigned long=.
#+end_quote
** Escopo de variáveis
- Toda variável declarada numa função só é visível na própria função (escopo /local/).
- Toda variável declarada fora de funções é visível em todo o programa (escopo global).
Exemplo (=var3.c=):
#+begin_src c
#include <stdio.h>
int c = 17; // Variável global.
// As variáveis 'num' e 'b' são locais à função 'soma10'.
int soma10(int num) {
int b = 10;
return b + num;
}
int main(void) {
int a = 25; // A variável 'a' é local à função 'main'.
// Isso causará um erro na compilação!
printf("a = %d\nb = %d\nc = %d\nnum = %d\n", a, b, c, num);
return 0;
}
#+end_src
** Ponteiros
Antes de qualquer coisa, os ponteiros são simplesmente variáveis, embora
possuam algumas particularidades:
- São declarados com o operador de derreferência (ou indireção) =*NOME=.
- Recebem endereços como valores.
- Seus tipos são suas unidades aritméticas.
- Seus nomes expressam os endereços associados.
- Quando derreferenciados (=*NOME=), expressam os valores nos endereços.
*** Declaração do ponteiro
#+begin_src c
int a = 25;
int *pa = &a; // O valor de 'pa' será o endereço de 'a'.
int b = *pa; // O valor de 'b' será o valor no endereço em 'pa'.
#+end_src
** Perguntas da aula
*** A cada execução do programa, os endereços das variáveis mudam?
Sim, porque o /espaço de endereços/ é designado pelo sistema operacional
assim que o processo para executar o programa é criado.
*** O ponto da declaração de uma variável global faz diferença?
Sim, toda variável tem que ser declarada antes do ponto no código
em que é utilizada.