cblc/aulas/04-variaveis/README.org
2025-03-20 15:05:11 -03:00

181 lines
4.6 KiB
Org Mode
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#+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.