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