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