Problemas de Rastreamento de Memória

Leia cada trecho de código e acompanhe como o valor de cada variável muda. Tente resolver primeiro com papel e caneta.

Rastreando Variáveis e Atribuição

T-01Variável
int a = 5, b = 10;
a = b;
b = a + 3;
a = b - a;

Quais são os valores finais de a e b?

Linha 1: a=5, b=10
Linha 2: a=10, b=10 (copia b em a)
Linha 3: a=10, b=13 (10+3)
Linha 4: a=3, b=13 (13-10)
Resposta: a=3, b=13
T-02Variável
int x = 7;
x = x * 2;
x += 3;
x %= 5;
x++;

Qual é o valor final de x?

x=7 → x=14 (7*2) → x=17 (14+3) → x=2 (17%5 = resto 2) → x=3 (2+1)
Resposta: x=3
T-03Variável
int a = 3, b = 5, tmp;
tmp = a;
a = b;
b = tmp;

Quais são os valores finais de a, b, tmp? (O que isso está fazendo?)

tmp=3 (salva o valor original de a) → a=5 (copia b em a) → b=3 (copia tmp de volta para b)
Resposta: a=5, b=3, tmp=3
Esse é o padrão clássico de troca de valores.
T-04Variável
int a = 10;
int b = a / 3;
int c = a % 3;
double d = (double)a / 3;

Quais são os valores de b, c, d?

b = 10/3 = 3 (divisão inteira trunca)
c = 10%3 = 1 (resto)
d = 10.0/3 = 3.333... (o cast promove para divisão em double)
Resposta: b=3, c=1, d=3.333333
T-05Variável
int a = 1;
a += a++;  // aviso de comportamento indefinido
printf("%d\n", a);

Qual é a saída? Dica: é uma questão "pegadinha".

Isso é comportamento indefinido. Modificar e ler a mesma variável em uma única expressão não é garantido pelo padrão C.
Compiladores diferentes podem produzir 2, 3 ou outros resultados.
Lição: Nunca misture ++ e atribuição na mesma variável em uma única expressão.
T-06Variável
int i = 0, sum = 0;
while (i < 5) {
    sum += i;
    i++;
}

Rastreie i e sum após cada iteração do laço em uma tabela.

Iteri (antes)sum += iapós i++
100+0=01
210+1=12
321+2=33
433+3=64
546+4=105
Resposta: i=5, sum=10 (0+1+2+3+4)
T-07Variável
int n = 12345, rev = 0;
while (n > 0) {
    rev = rev * 10 + n % 10;
    n /= 10;
}

Rastreie n e rev após cada iteração. O que este programa faz?

Itern%10revn
150*10+5=51234
245*10+4=54123
3354*10+3=54312
42543*10+2=54321
515432*10+1=543210
Resposta: n=0, rev=54321
Este programa inverte os dígitos de um inteiro.

Rastreando Vetores

T-08Vetor
int a[5] = {3, 1, 4, 1, 5};
a[0] = a[4];
a[2] = a[0] + a[1];
a[4] = a[2] - a[3];

Qual é o estado final do vetor a?

Inicial: {3,1,4,1,5}
a[0]=a[4] → {5,1,4,1,5}
a[2]=a[0]+a[1] → {5,1,6,1,5}
a[4]=a[2]-a[3] → {5,1,6,1,5}
Resposta: {5, 1, 6, 1, 5}
T-09Vetor
int a[4] = {10, 20, 30, 40};
for (int i = 0; i < 3; i++) {
    a[i] = a[i + 1];
}

Qual é o estado final de a? O que este código faz?

i=0: a[0]=a[1] → {20,20,30,40}
i=1: a[1]=a[2] → {20,30,30,40}
i=2: a[2]=a[3] → {20,30,40,40}
Resposta: {20, 30, 40, 40}
Isso remove o primeiro elemento deslocando todos para a esquerda (o último elemento fica duplicado).
T-10Vetor
int a[5] = {2, 8, 3, 9, 1};
int max = a[0], idx = 0;
for (int i = 1; i < 5; i++) {
    if (a[i] > max) {
        max = a[i];
        idx = i;
    }
}

Rastreie como max e idx mudam a cada passo.

ia[i]a[i]>max?maxidx
init--20
188>2 Sim81
233>8 Não81
399>8 Sim93
411>9 Não93
Resposta: max=9, idx=3
T-11Vetor
int a[5] = {5, 3, 8, 1, 4};
// Primeira passada do bubble sort (levando o mínimo para o começo)
for (int j = 4; j > 0; j--) {
    if (a[j-1] > a[j]) {
        int tmp = a[j-1]; a[j-1] = a[j]; a[j] = tmp;
    }
}

Rastreie o estado do vetor depois de uma passada.

Inicial: {5,3,8,1,4}
j=4: a[3]>a[4]? 1>4 Não → {5,3,8,1,4}
j=3: a[2]>a[3]? 8>1 Sim → {5,3,1,8,4}
j=2: a[1]>a[2]? 3>1 Sim → {5,1,3,8,4}
j=1: a[0]>a[1]? 5>1 Sim → {1,5,3,8,4}
Resposta: {1, 5, 3, 8, 4} (o valor mínimo 1 borbulha até o começo)
T-12Vetor
int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
int sum = 0;
for (int i = 0; i < 3; i++) {
    sum += a[i][i];
}

Qual é o valor de sum? O que isso calcula?

a[0][0]=1, a[1][1]=5, a[2][2]=9
sum = 1+5+9 = 15
Isso calcula o traço de uma matriz (soma dos elementos da diagonal principal).

Rastreando Ponteiros

T-13Ponteiro
int a = 10, b = 20;
int *p = &a;
*p = 30;
p = &b;
*p = *p + 5;

Quais são os valores finais de a, b e *p?

p=&a → *p=30 → a=30
p=&b → *p=20+5=25 → b=25
Resposta: a=30, b=25, *p=25
T-14Ponteiro
int a = 5, b = 10;
int *p = &a, *q = &b;
*p = *q;
*q = 0;
printf("%d %d\n", a, b);

Qual é a saída?

*p=*q → a=10 (copia o valor de b para a)
*q=0 → b=0
Resposta: 10 0
T-15Ponteiro
int arr[4] = {10, 20, 30, 40};
int *p = arr;
printf("%d ", *p);
p += 2;
printf("%d ", *p);
printf("%d ", *(p - 1));
printf("%d\n", p[1]);

Qual é a saída?

p=arr → *p=10
p+=2 → p aponta para arr[2] → *p=30
*(p-1)=arr[1]=20
p[1]=*(p+1)=arr[3]=40
Resposta: 10 30 20 40
T-16Ponteiro
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr + 1;
int *q = arr + 3;
printf("%d %d %ld\n", *p, *q, q - p);

Qual é a saída?

p=&arr[1] → *p=2
q=&arr[3] → *q=4
q-p = 3-1 = 2 (diferença em número de elementos)
Resposta: 2 4 2
T-17Ponteiro
int x = 100;
int *p = &x;
int **pp = &p;
**pp = 200;
printf("%d %d %d\n", x, *p, **pp);

Qual é a saída? (Ponteiro duplo)

Cadeia pp → p → x. **pp=200 modifica x para 200.
x=200, *p=200, **pp=200 (todos se referem ao mesmo local)
Resposta: 200 200 200
T-18Ponteiro
int a[] = {10, 20, 30, 40, 50};
int *p = a;
for (int i = 0; i < 5; i++) {
    *(p + i) *= 2;
}

Qual é o estado final de a?

Dobra cada elemento: {20, 40, 60, 80, 100}
*(p+i) é equivalente a a[i]. Manipulação do vetor via aritmética de ponteiros.

Rastreando Chamadas de Função

T-19Função
void add_ten(int x) { x += 10; }

int main(void) {
    int a = 5;
    add_ten(a);
    printf("%d\n", a);
}

Qual é a saída?

Resposta: 5
O C usa passagem por valor. O x dentro de add_ten é uma cópia de a, então modificar x não afeta a.
T-20Função
void add_ten(int *px) { *px += 10; }

int main(void) {
    int a = 5;
    add_ten(&a);
    printf("%d\n", a);
}

Qual é a saída? (Compare com T-19.)

Resposta: 15
Como passamos um ponteiro, *px += 10 modifica o próprio a.
T-21Função
int mystery(int a, int b) {
    a = a + b;
    b = a - b;
    a = a - b;
    return a * 10 + b;
}
printf("%d\n", mystery(3, 7));

Qual é a saída? Rastreie a e b linha por linha.

a=3, b=7
a=3+7=10
b=10-7=3
a=10-3=7
return 7*10+3 = 73
Isso é uma troca sem variável temporária. a e b são trocados, então o resultado é 7*10+3=73.
T-22Função
void modify(int arr[], int n) {
    for (int i = 0; i < n; i++) arr[i] *= 3;
}
int main(void) {
    int data[] = {1, 2, 3};
    modify(data, 3);
    printf("%d %d %d\n", data[0], data[1], data[2]);
}

Qual é a saída? (Passagem de vetor vs. passagem de int)

Resposta: 3 6 9
Vetores são passados como ponteiros, então modificações dentro da função afetam o chamador. Isso é diferente da passagem por valor de ints (T-19)!
T-23Função
int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}
printf("%d\n", factorial(5));

Rastreie a expansão e o retorno da pilha de chamadas.

factorial(5) → 5 * factorial(4)
→ 5 * 4 * factorial(3)
→ 5 * 4 * 3 * factorial(2)
→ 5 * 4 * 3 * 2 * factorial(1)
→ 5 * 4 * 3 * 2 * 1 (caso base)
= 5*4*3*2*1 = 120

Rastreando Strings

T-24String
char s[] = "Hello";
s[0] = 'J';
s[4] = '!';
printf("%s\n", s);

Qual é a saída? Quais são os bytes na memória?

índice012345
inicialHello\0
depoisJell!\0
Resposta: Jell!
T-25String
char s[] = "abcde";
int len = 0;
while (s[len] != '\0') len++;
printf("%d\n", len);

Rastreie como len muda e dê a saída.

s[0]='a'≠'\0' → len=1
s[1]='b'≠'\0' → len=2
s[2]='c'≠'\0' → len=3
s[3]='d'≠'\0' → len=4
s[4]='e'≠'\0' → len=5
s[5]='\0' → sai do laço
Resposta: 5 (equivalente a strlen)
T-26String
char s[] = "Hello";
for (int i = 0; s[i]; i++) {
    if (s[i] >= 'a' && s[i] <= 'z')
        s[i] -= 32;
}
printf("%s\n", s);

Rastreie a mudança de cada caractere.

H: maiúsculo → sem mudança
e: minúsculo → e-32=E
l: minúsculo → l-32=L
l: minúsculo → l-32=L
o: minúsculo → o-32=O
Resposta: HELLO (conversão de minúsculas para maiúsculas; a diferença ASCII é 32)

Problemas Mistos

T-27Misto
struct Point { int x, y; };
struct Point a = {3, 7};
struct Point b = a;
b.x = 10;
printf("a=(%d,%d) b=(%d,%d)\n", a.x, a.y, b.x, b.y);

Qual é a saída? (A atribuição de struct é cópia ou referência?)

Resposta: a=(3,7) b=(10,7)
A atribuição de struct é uma cópia por valor. b é uma cópia independente de a, então mudar b.x não afeta a.x.
T-28Misto
struct Point { int x, y; };
struct Point p = {1, 2};
struct Point *ptr = &p;
ptr->x = 10;
ptr->y = ptr->x + 5;
printf("(%d,%d)\n", p.x, p.y);

Qual é a saída? (Modificação via operador seta)

ptr->x=10 → p.x=10
ptr->y=10+5=15 → p.y=15
Resposta: (10,15)
T-29Misto
int a[3] = {1, 2, 3};
int *p = a;
for (int i = 0; i < 3; i++) {
    a[i] = a[(2-i)];
}

Qual é o estado final de a? (Dica: NÃO vira um vetor invertido. Por quê?)

i=0: a[0]=a[2] → {3,2,3}
i=1: a[1]=a[1] → {3,2,3}
i=2: a[2]=a[0] → {3,2,3} (a[0] já é 3!)
Resposta: {3, 2, 3} (NÃO {3, 2, 1})
Motivo: As iterações anteriores sobrescrevem o começo do vetor, então leituras posteriores pegam valores já modificados. Uma inversão correta precisa de um vetor temporário ou uma troca com dois ponteiros.
T-30Misto
int f(int *a, int *b) {
    *a += *b;
    *b = *a - *b;
    return *a + *b;
}
int main(void) {
    int x = 4, y = 6;
    int z = f(&x, &y);
    printf("%d %d %d\n", x, y, z);
}

Qual é a saída? (Rastreie modificações via ponteiros.)

*a=&x, *b=&y
*a += *b → x=4+6=10
*b = *a-*b → y=10-6=4
return 10+4=14
Resposta: 10 4 14
T-31Misto
int a[5] = {5, 2, 8, 1, 9};
for (int i = 0; i < 4; i++) {
    if (a[i] > a[i+1]) {
        int t = a[i]; a[i] = a[i+1]; a[i+1] = t;
    }
}

Qual é o estado final de a? O que está garantido sobre ele?

i=0: 5>2 → troca → {2,5,8,1,9}
i=1: 5>8? Não → {2,5,8,1,9}
i=2: 8>1 → troca → {2,5,1,8,9}
i=3: 8>9? Não → {2,5,1,8,9}
Resposta: {2, 5, 1, 8, 9}
Está garantido que o valor máximo (9) termina na última posição (uma passagem de bubble sort varrendo para frente).
T-32Misto
int count = 0;
for (int i = 1; i <= 100; i++) {
    if (i % 3 == 0 && i % 5 == 0)
        count++;
}

Qual é o valor final de count? (Não precisa rastrear tudo — ache o padrão.)

Divisíveis por 3 e por 5 → conta os múltiplos de 15.
Múltiplos de 15 entre 1..100: 15, 30, 45, 60, 75, 90 — 6 valores.
Resposta: count=6
T-33Misto
int fib(int n) {
    if (n <= 1) return n;
    return fib(n-1) + fib(n-2);
}
printf("%d\n", fib(6));

Dê o valor de fib(6) e quantas vezes fib é chamada no total.

fib(6)=fib(5)+fib(4)=5+3=8
Contagem de chamadas: expandindo fib(6)→fib(5),fib(4)→... dá 25 chamadas.
fib(0)=0, fib(1)=1, fib(2)=1, fib(3)=2, fib(4)=3, fib(5)=5, fib(6)=8
T-34Misto
char *p = "ABCDE";
printf("%c %c %s\n", *p, *(p+2), p+3);

Qual é a saída? (Operações de ponteiro em literal de string)

*p = 'A'
*(p+2) = 'C'
p+3 = "DE" (a string começando no deslocamento 3)
Resposta: A C DE
T-35Misto
int m[2][3] = {{1,2,3},{4,5,6}};
int result = 0;
for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        if (m[i][j] % 2 == 0) result += m[i][j];

Qual é o valor de result?

Elementos pares: 2, 4, 6
result = 2+4+6 = 12
T-36Misto
int a = 0xAB;  // hexadecimal
int hi = (a >> 4) & 0x0F;
int lo = a & 0x0F;
printf("hi=%d lo=%d\n", hi, lo);

Qual é a saída? (Rastreamento de operação bitwise)

0xAB = 1010 1011 (binário)
a>>4 = 0000 1010 → & 0x0F → 10 (0x0A)
a & 0x0F = 0000 1011 → 11 (0x0B)
Resposta: hi=10 lo=11 (4 bits superiores = A = 10, 4 bits inferiores = B = 11)
T-37Misto
int gcd(int a, int b) {
    while (b != 0) {
        int tmp = b;
        b = a % b;
        a = tmp;
    }
    return a;
}
printf("%d\n", gcd(48, 18));

Rastreie a, b e tmp em cada iteração.

Iterabtmpa%b
148181848%18=12
218121218%12=6
3126612%6=0
fim60--
Resposta: 6 (o maior divisor comum de 48 e 18)
T-38Misto
int *p = (int *)malloc(sizeof(int) * 3);
p[0] = 10; p[1] = 20; p[2] = 30;
int *q = p;
free(p);
// printf("%d\n", *q); ← isso é seguro?

O que acontece se acessarmos *q após free?

Comportamento indefinido (ponteiro solto).
q estava apontando para o mesmo local que p, mas free(p) liberou aquela memória. q ainda guarda o mesmo endereço, mas a memória não é mais válida.
Lição: Depois do free, defina também todos os ponteiros relacionados como NULL.
T-39Misto
int a[4] = {10, 20, 30, 40};
int *p = a, *q = a + 3;
while (p < q) {
    int t = *p; *p = *q; *q = t;
    p++; q--;
}

Qual é o estado final de a? O que está fazendo?

Iter 1: p=a[0], q=a[3] → troca(10,40) → {40,20,30,10}, p++, q--
Iter 2: p=a[1], q=a[2] → troca(20,30) → {40,30,20,10}, p++, q--
p>=q → sai
Resposta: {40, 30, 20, 10}
Isso é uma inversão in-place do vetor. Troca das duas pontas em direção ao centro.
T-40Misto
int binary_search(int a[], int n, int key) {
    int lo = 0, hi = n - 1;
    while (lo <= hi) {
        int mid = (lo + hi) / 2;
        if (a[mid] == key) return mid;
        else if (a[mid] < key) lo = mid + 1;
        else hi = mid - 1;
    }
    return -1;
}
// a = {2, 5, 8, 12, 16, 23, 38, 56}, key = 23

Rastreie lo, hi, mid e diga em quantas iterações a chave é encontrada.

Iterlohimida[mid]decisão
10731212<23 → lo=4
24752323==23 → encontrou!
Resposta: retorna índice=5 na iteração 2
Compartilhe este artigo
Compartilhar no X (Twitter) Compartilhar no Facebook Compartilhar no LinkedIn Compartilhar no Reddit