Memory
O que é memória?
Imagine a memoria como um gigante array de bytes. Cada "gaveta" dessa array tem um índice, que chamamos de endereço (address, em inglês).

Variáveis: São apenas nomes légiveis que apontam para um desses endereços. Em vez de decorar o endereço0xfff8você usa o nomeage.
- Operador
&(Address-of): Esse operador permite que você pergunta ao C: "Em qul gaveta da memória esta variavél está guardada?" - Exibição(
%p): Usamos o especificador%pnoprintfpara exibir esse endereço, geralmente em formato hexadecimal.
Isso é base para os famosos pointers
Exemplo de código
#include <stdio.h>
int main(){
float temperature = 36.5;
//Imprime o valor e o endereço exato na memória
printf("Valor da variável: %.1f\n", temperature);
printf("Endereço de memória (índice array): %p\n", (void*)&temperature);
return 0
}O que é endereço?
Um endereço de memória nada mais é do que um número! Pense nele com o índice exato de uma "gaveta" no grande array que é a memória do seu computador.

- Apenas um número: Apesar de não parecer uma "casa", o endereço é um identificador numérico único para cada byte.
- Hexadecimal (Base 16): Usamos formatos como
0xfff8porque é o padrão da computação, mas ele representa um valor real (neste caso, 65.528). - Legibilidade: O hexadecimal ajuda a organizar endereços grandes de uma forma que faz mais sentido para o hardware e compiladores.
#include <stdio.h>
int main() {
int value = 100;
// %p exibe o número em hexadecimal (ex: 0x7ffd...)
printf("Endereço (Hexadecimal): %p\n", (void*)&value);
// Podemos ver o mesmo número "cru" em decimal
printf("Enderecço (Decimal): %lu\n", ( unsigned long)&value);
return 0;
}Memória Virtual
- Camada de Abstração: Seu programa não acessa os pentes de RAM físico diretamente. O Sistema Opereacional (OS, OPERATING SYSTEM) cria a Memória Virtual, fazendo o programa acreditar que tem acesso exclusivo a um bloco contínuo de memória.

- Segurança e Isolamento: Essa técnica impede que um processo acesse ou corrompa os dados de outro programa, garantindo estabilidade ao sistema.
- Simplicidade e Performance: O desenvolvedor não precisa gerenciar o hardware físico, e o OS pode otimizar o uso da RAM movendo dados para o disco se necessário.
- Sistemas Embarcados: A única grande exceção é quando você programa firmware para dispositivos simploes sem OS; neles, o acesso à memória física costuma ser direto.
No fim, para o seu código C, a memória virtual continua sendo aquele grande "array de bytes" onde cada posição tem um endereço número.
Pointers
- O Que é: Um ponteiro é apneas uma variável que armazena um memory address.
- Por que o nome? Ele é chamado assim porque "aponta" para o local onde o dado real está guardado.
- Sintaxe de Declaração: Usamos um asterisco (*) após o tipo de declaração para indicar que é um ponteiro (ex.
int *). - Atribuição: Usamos o operador
&(address-of) para pegar o endereço de uma variável comum e salvá-lo no ponteiro.
int age = 37;
int *pointer_to_age = &age; // O ponteiro agora guardad o endereço de 'idade'- Modificação Direta: Por padrão, o C copia dos dados ao passá-los para uma função (passagem por valor). Se você alterar a cópia dentro da função a variável original permanece igual. Com ponteiros, você passa o endereço e altera o dado original
- Eficiência: Imagine uma
structcom milhares de campos. Copiar tudo isso para cada função consumiriar muita memória e tempo. Passar apenas o endereço (pointer) é extremamente rápido e leve.
Em resumo, ponteiros dão às suas funções o "endereço da casa" em vez de uma "cópia da casa".
Pointer Basics
Os ponteiros funcionam como endereços residencias; eles não são o dado em si, mas indicam exatamente onde a inforrmação está guardada na memória. Para começar, você declara um ponteiro usando o simbolo de asterisco após o tipo e utiliza o operador & para capturar o endereço de uma variável específica.
A grande novidade aqui é a desreferenciação, que usa o mesmo asterisco para "entrar"no endereço e acessar ou modificar o valor real ali armazenado.
É essencial não confundir o uso do asterisco na declaração do tipo com o seu uso na manipulação dos dados, pois essa técnica permite que você altere o conteúdo original de uma variável diretamente, sem precisar criar cópias desnecessárias, o que torna o seu código muito mais eficiente e poderoso
#include <stdio.h>
int main() {
int numero = 10;
int *ptr = № // Declaração: ptr é um ponteiro para int
printf("Valor original: %d\n", numero);
printf("Endereço armazenado: %\n";, (void*)ptr);
// Desreferenciando para ler o valor
printf("Acessando valor pelo ponteiro: %d\n", * ptr);
// Desreferenciando para modificar o valor original
*ptr = 20;
printf("Novo valor de 'numero': %d\n", numero);
return 0;
}O segredo é lembrar que o * tem duas personalidades: na declaração, ele cria o ponteiro; no uso direto, ele serve para acessar o conteúdo dentro do endereço.
Pointers to Stucts
- Ponto vs. Seta: Use (
.) para acessar campos de structs comuns e->quando tiver um ponteiro para struct. - Atalho elegeante: O comando
ponteiro->campoé uma forma simplificada de escrever(*ponteior).campo. - Prioridade: Como o operador
.tem maior precedência que o *, usar a seta evita a necessidade de parantêses confusos, tornando o códgico muti mais limpo.
#include <stdio.h>
typedef struct {
int x;
int y;
} ponto_t;
int main() {
ponto_t p1 {10, 20};
ponto_t *ptr = &p1;
// Usando a seta para ler e modificar
printf("X inicial: %d\n", ptr->x);
ptr->x = 100;
prtinf("X atualziado: %d\n", p1.x);
return 0;
}