mirror of
https://gitlab.com/blau_araujo/cblc.git
synced 2025-05-09 10:16:35 -03:00
181 lines
4.6 KiB
Org Mode
181 lines
4.6 KiB
Org Mode
#+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.
|