C Quiz
40 perguntas sobre o que você estudou no guia, divididas nos três níveis. Muitas mostram um trecho de código e perguntam o que ele imprime: tente responder de cabeça, sem rodar. Todas as respostas foram conferidas de verdade, com gcc -std=c23 -Wall -Wextra (gcc 15) na máquina da Ana. A correção é na hora; abra "Explicação" para entender o porquê, e o link "Revise" leva à aula do assunto.
Acertos: 0 de 40
Para economizar espaço, os trechos que só têm instruções estão, na verdade, dentro de um int main(void) { … return 0; }, com #include <stdio.h>, <string.h> e <stdlib.h> no começo. Quando o trecho tem outras funções, o main aparece. Para conferir uma resposta, cole o trecho dentro do main de qualquer caixa "Experimente" do guia, como a de Olá, Mundo.
Ir para: Nível 1 · Nível 2 · Nível 3
Nível 1 · Iniciante
Saída, tipos, operadores, decisões, laços, arrays, strings e funções.
1. O que este código imprime?
printf("%d\n", 7 / 2);
Explicação
Os dois números são int, então a divisão é inteira: o resultado é 3 e a parte decimal é jogada fora (não arredonda).
Revise: float e double
2. O que este código imprime?
printf("%.2f\n", 7 / 2.0);
Explicação
Com um dos lados double (2.0), a divisão é real: 3.5. O %.2f mostra exatamente duas casas decimais: 3.50.
Revise: Formatos do printf
3. Qual é o problema de int total; seguido de printf("%d\n", total);?
Explicação
Uma variável local sem valor inicial guarda o que estava naquela memória antes. Usá-la é comportamento indefinido. O hábito do guia: inicialize sempre, int total = 0;.
Revise: Variáveis
4. O que este código imprime?
char c = 'A' + 2;
printf("%c\n", c);
Explicação
Um char é um número: 'A' vale 65, e 65 + 2 = 67, que na tabela ASCII é o C. Como o formato é %c, aparece a letra; com %d, apareceria 67.
Revise: Caracteres (char)
5. O que este código imprime?
char d = '7';
printf("%d\n", d - '0');
Explicação
O caractere '7' vale 55 na tabela e o '0' vale 48. Como os algarismos estão em ordem, 55 − 48 = 7: é o truque para transformar um algarismo no número.
Revise: Caracteres (char)
6. A Ana escreveu char letra = "A";. O que o gcc 15 faz?
Explicação
Aspas duplas fazem um texto, que o C entrega como endereço (char *). O gcc 15 recusa: error: initialization of ‘char’ from ‘char *’ makes integer from pointer without a cast. Para um caractere, aspas simples: 'A'.
Revise: Caracteres (char)
7. O que este código imprime?
int i = 5;
int j = i++;
printf("%d %d\n", i, j);
Explicação
O i++ (pós-incremento) entrega o valor antigo (5) para o j e só depois soma 1 ao i. Com ++i, os dois seriam 6.
Revise: ++ e --
8. O que este código imprime?
int x = 5;
if (x = 0) {
printf("zero\n");
} else {
printf("não zero\n");
}
Explicação
x = 0 é uma atribuição, não uma comparação: guarda 0 no x e vale 0, que é "falso". Então cai no else. O -Wall avisa: suggest parentheses around assignment used as truth value. Para comparar, ==.
Revise: if e else
9. O que este código imprime?
printf("%d\n", 2 + 3 * 4);
Explicação
Como na escola, a multiplicação vem antes da soma: 2 + (3 * 4) = 14. Para somar primeiro, use parênteses: (2 + 3) * 4 = 20.
Revise: Precedência
10. O que este código imprime?
int nota = 15;
if (0 <= nota <= 10) {
printf("válida\n");
} else {
printf("inválida\n");
}
Explicação
O C lê (0 <= nota) <= 10. A primeira comparação dá 1 (verdadeiro), e 1 <= 10 também é verdadeiro. O gcc avisa: comparisons like ‘X<=Y<=Z’ do not have their mathematical meaning. O certo é nota >= 0 && nota <= 10.
Revise: Operadores de Comparação e Operadores Lógicos
11. O que este código imprime?
for (int i = 0; i < 3; i++) {
printf("%d", i);
}
printf("\n");
Explicação
O i começa em 0 e o laço roda enquanto i < 3: 0, 1 e 2. Quando i vira 3, para. O printf não tem espaço nem \n, então os números saem colados.
Revise: for
12. O que este código imprime?
int n = 0;
while (n > 0) {
printf("volta\n");
n--;
}
printf("fim\n");
Explicação
O while confere a condição antes de cada volta. Como 0 > 0 já é falso, o bloco roda zero vezes. Um do while rodaria uma vez.
13. O que este código imprime?
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (j == 1) {
break;
}
printf("%d%d ", i, j);
}
}
printf("\n");
Explicação
O break só sai do laço em que está, o de dentro. Em cada volta do i, o j mostra o 0 e para no 1; o laço de fora continua normalmente.
Revise: break e continue e Laços Aninhados
14. Num int v[5];, quais são os índices válidos?
Explicação
O índice conta quantas posições andar a partir do começo, então o primeiro é 0 e o último é o tamanho menos 1. v[5] passa do fim, e o C não confere: é comportamento indefinido.
Revise: Arrays
15. O que este código imprime?
char nome[] = "Ana";
printf("%zu %zu\n", strlen(nome), sizeof nome);
Explicação
O strlen conta as letras até o '\0', sem contá-lo: 3. O sizeof mede o array inteiro, que tem as 3 letras e o '\0' do fim: 4 bytes.
16. Como conferir se duas strings, a e b, têm o mesmo texto?
Explicação
O == compara os endereços dos arrays, não as letras. O strcmp compara letra por letra e devolve 0 quando os textos são iguais. Ter o mesmo tamanho não quer dizer ter o mesmo texto.
Revise: Funções de String
17. O fgets(linha, sizeof linha, stdin) leu a linha Ana, que a pessoa digitou e confirmou com Enter. O que ficou em linha?
Explicação
O fgets guarda a linha inteira, incluindo o \n do Enter (se couber), e põe o '\0' depois. Para tirar o \n: linha[strcspn(linha, "\n")] = '\0';.
Revise: Ler uma Linha (fgets)
18. A pessoa digitou abc. O que este código imprime?
int n = 7;
int lidos = scanf("%d", &n);
printf("%d %d\n", lidos, n);
Explicação
O scanf devolve quantos campos conseguiu preencher. abc não é um número, então ele devolve 0 e não mexe no n, que continua 7 (e o abc fica esperando na entrada). Se a entrada acabasse, devolveria EOF (−1). Por isso: confira sempre o retorno.
Revise: Entrada com scanf
19. O que este programa imprime?
void dobra(int x) {
x = x * 2;
}
int main(void) {
int n = 5;
dobra(n);
printf("%d\n", n);
return 0;
}
Explicação
Em C, a função recebe uma cópia do argumento (passagem por valor). Ela dobrou a cópia, e o n do main continuou 5. Para mudar o n, devolva o resultado com return ou passe o endereço (&n).
Revise: Parâmetros
20. O que este programa imprime?
int contar(void) {
static int n = 0;
n++;
return n;
}
int main(void) {
contar();
contar();
printf("%d\n", contar());
return 0;
}
Explicação
Uma variável static dentro da função é criada uma vez só e lembra o valor entre as chamadas: 1, 2 e, na terceira, 3. Sem o static, seria 1 toda vez.
Revise: Escopo e Variáveis static
21. O main terminou com return 3;. O que o terminal mostra depois de echo $??
Explicação
O valor do return do main vira o código de saída do programa, que o echo $? mostra. Por convenção, 0 é sucesso e outros números indicam erro.
Revise: Olá, Mundo
Nível 2 · Intermediário
Ponteiros, memória dinâmica, structs, arquivos e a organização do código.
22. O que este código imprime?
int x = 10;
int *p = &x;
*p = 20;
printf("%d\n", x);
Explicação
p guarda o endereço de x. *p = 20 vai até esse endereço e escreve lá: é o próprio x que muda.
Revise: Ponteiros
23. O que este programa imprime?
void zera(int *p) {
*p = 0;
}
int main(void) {
int n = 5;
zera(&n);
printf("%d\n", n);
return 0;
}
Explicação
Desta vez a função recebeu o endereço de n, e não uma cópia do valor. Pelo ponteiro, ela mudou o n do main. É o mesmo motivo de o scanf pedir o &.
Revise: Passar por Ponteiro
24. O que este código imprime?
int v[] = {10, 20, 30};
int *p = v;
printf("%d\n", *(p + 2));
Explicação
O nome do array vira um ponteiro para o primeiro elemento. p + 2 anda dois elementos (não dois bytes), e *(p + 2) é o mesmo que v[2]: 30.
Revise: Ponteiros e Arrays
25. No gcc do laboratório (Linux de 64 bits), o que este programa imprime?
void tamanho(int v[10]) {
printf("%zu\n", sizeof v);
}
int main(void) {
int notas[10] = {0};
printf("%zu\n", sizeof notas);
tamanho(notas);
return 0;
}
Explicação
No main, notas é o array: 10 × 4 bytes = 40. No parâmetro, o array chega como ponteiro, mesmo escrito int v[10], e um ponteiro tem 8 bytes no gcc de 64 bits. O gcc avisa: ‘sizeof’ on array function parameter ‘v’ will return size of ‘int *’. Por isso se passa o tamanho num parâmetro à parte.
Revise: Ponteiros e Arrays
26. O que acontece ao rodar int *p = NULL; printf("%d\n", *p); no Linux?
Explicação
Um ponteiro nulo não aponta para lugar nenhum. Ir até ele com *p é mexer numa memória proibida, e o sistema mata o programa (sinal SIGSEGV: 128 + 11 = 139). Confira if (p != NULL) antes de usar.
Revise: Ponteiro Nulo
27. Qual destas é a forma certa de usar o malloc?
Explicação
O malloc devolve NULL quando não há memória. A memória do heap fica reservada até o free, mesmo depois que a função termina: esquecer é um vazamento. E a memória vem com lixo: inicialize antes de ler.
Revise: malloc e free e Pilha e Heap
28. O que este programa imprime?
struct ponto {
int x;
};
int main(void) {
struct ponto a = {1};
struct ponto b = a;
b.x = 2;
printf("%d %d\n", a.x, b.x);
return 0;
}
Explicação
O = copia a struct inteira, campo por campo. Depois disso, a e b são independentes: mudar b.x não mexe em a.x. (Comparar com ==, esse sim, não compila.)
Revise: Structs
29. Se p é um ponteiro para uma struct aluno, p->nota é o mesmo que…
Explicação
A seta é um atalho: vá até a struct apontada (*p) e pegue o campo. Os parênteses são necessários porque o . vem antes do * na precedência: *p.nota seria *(p.nota).
Revise: Structs e Ponteiros
30. O fopen("nao-existe.txt", "r") falhou e o programa chamou perror("nao-existe.txt"). O que aparece?
Explicação
Quando falha, o fopen devolve NULL e deixa o motivo em errno (aqui, ENOENT). O perror mostra o seu texto, dois-pontos e a frase do erro. Confira o NULL primeiro; o errno só vale depois de uma falha.
Revise: errno e perror
31. O que este programa imprime?
#define DOBRO(x) x * 2
int main(void) {
printf("%d\n", DOBRO(1 + 2));
return 0;
}
Explicação
A macro troca texto por texto, antes da compilação: DOBRO(1 + 2) vira 1 + 2 * 2, que é 5. A regra: parênteses em volta de cada parâmetro e do resultado, #define DOBRO(x) ((x) * 2).
Revise: Macros com Parâmetros
32. Para que serve o trio #ifndef DATAS_H / #define DATAS_H / #endif num arquivo datas.h?
Explicação
Na primeira inclusão, DATAS_H ainda não existe: o conteúdo entra e o nome é definido. Numa segunda inclusão, o #ifndef é falso e o conteúdo é pulado, evitando definições repetidas.
Revise: Compilação Condicional e Arquivos .h e .c
33. O gcc mostrou referência não definida para "soma" (em inglês, undefined reference to). O que isso quer dizer?
Explicação
Essa mensagem vem do ligador, a última etapa, e não do compilador: cada arquivo compilou, mas na hora de juntar tudo ninguém tinha o corpo de soma. Confira se todos os .c estão no comando do gcc.
Revise: Vários Arquivos e Protótipos
Nível 3 · Avançado
Bits, comportamento indefinido, a linguagem a fundo e as ferramentas.
34. O que este código imprime?
printf("%d %d %d\n", 5 & 3, 5 | 3, 5 ^ 3);
Explicação
Em binário, 5 = 101 e 3 = 011. E bit a bit (&): 001 = 1. OU (|): 111 = 7. OU exclusivo (^), 1 onde os bits são diferentes: 110 = 6.
Revise: Operadores de Bits
35. O que este código imprime?
unsigned int flags = 0;
flags |= 1u << 2;
flags |= 1u;
printf("%u\n", flags);
Explicação
1u << 2 é a máscara do bit 2 (100 = 4), e |= liga esse bit. Depois, o bit 0 (1). Resultado: 101 = 5.
Revise: Máscaras e Flags
36. Com int x = INT_MAX; (o maior int, do limits.h), o que é x + 1?
Explicação
Passar do limite de um inteiro com sinal é comportamento indefinido. Na prática, muitas vezes "dá a volta" para o negativo, mas com -O2 o otimizador pode fazer coisas inesperadas. Só os unsigned dão a volta de forma garantida. O -fsanitize=undefined acusa o estouro.
Revise: Comportamento Indefinido e Inteiros
37. A Ana quer empurrar o texto de um array uma posição para a direita, dentro do mesmo array: ???(a + 1, a, 5);. Que função usar?
Explicação
O memcpy tem restrict nos parâmetros: promete que as áreas não se sobrepõem, e com -O2 o resultado pode sair errado. O memmove aceita sobreposição: com "abcdef", dá aabcde.
Revise: volatile e restrict
38. Um tratador de sinal muda a variável parar, que o laço principal espera. Como declará-la?
Explicação
Para o compilador, o tratador "nunca é chamado" pelo laço; sem volatile, com -O2 ele lê parar uma vez e o laço nunca termina. O sig_atomic_t é o tipo que pode ser escrito de uma vez só, sem o sinal chegar no meio.
Revise: volatile e restrict
39. Um programa tem assert(scanf("%d", &idade) == 1);. O que acontece quando ele é compilado com -DNDEBUG?
Explicação
Com NDEBUG definido, cada assert(…) vira nada, com tudo o que estava dentro dos parênteses. Por isso nada que precise acontecer vai dentro de um assert, e a entrada do usuário se confere com if.
Revise: Testes (assert)
40. O programa às vezes cai e você quer descobrir em que linha. Qual é o primeiro passo?
Explicação
O -g guarda no executável a ligação entre as instruções e as linhas do código. Com ele, o gdb e os sanitizers mostram arquivo.c:linha. O Valgrind (valgrind ./programa) também mostra a linha, se o programa tiver sido compilado com -g.
Revise: Depurar com gdb, Sanitizers e Valgrind
E agora?
Errou alguma? Abra a aula do "Revise", leia a seção do assunto e pratique nas caixas "Experimente". Para consultar rapidamente um termo, use o Glossário.