Reunimos 12 exercícios com ponteiros, do nível iniciante ao avançado. Na maioria deles, a função main já está pronta e você escreve o corpo da função pedida. Ao clicar em "Corrigir", seu código é testado com várias entradas usando gcc de verdade, e a saída é conferida.
Obs.: Executar e Corrigir enviam seu código ao Wandbox, um serviço externo e gratuito de compilação, que o executa com gcc.
void swap(int *a, int *b), que troca os valores de duas variáveis int. A função main já está pronta (ela lê dois inteiros, chama swap e mostra o resultado no formato "a = valor, b = valor")."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
tmp. *a é a própria "variável para onde a aponta" (o a da main), então a troca é tmp = *a; *a = *b; *b = tmp;.#include <stdio.h> void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } int main(void) { int a, b; scanf("%d %d", &a, &b); swap(&a, &b); printf("a = %d, b = %d\n", a, b); return 0; }
void swap(int a, int b), só as cópias são trocadas dentro da função, e as variáveis da main não mudam. Quem chama passa o endereço com &a, e a função altera o valor apontado com *a. Se você esquecer o *, como em a = b;, só o ponteiro (uma variável local) é alterado e nada acontece.void divmod(int a, int b, int *q, int *r), que devolve por meio de argumentos ponteiro o quociente e o resto de a ÷ b. A função main já está pronta."Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
return só dá para devolver um valor. Receba os endereços das variáveis que devem guardar os resultados (&q, &r) e escreva no local apontado, como em *q = a / b;.#include <stdio.h> void divmod(int a, int b, int *q, int *r) { *q = a / b; *r = a % b; } int main(void) { int a, b, q, r; scanf("%d %d", &a, &b); divmod(a, b, &q, &r); printf("Quociente: %d\n", q); printf("Resto: %d\n", r); return 0; }
& no scanf). Se você esquecer o * e escrever q = a / b;, estará atribuindo um int a um ponteiro, e o compilador mostra um aviso (a partir do gcc 14, um erro). Mesmo que o programa rodasse, o q da main não seria alterado e continuaria sem valor inicial.int sum(const int *a, int n), que retorna a soma de um array de int com n elementos. Não use o índice [ ]: avance um ponteiro elemento por elemento para somar. A função main já está pronta (ela lê N (1 ≤ N ≤ 100) e N inteiros (cada um entre −10000 e 10000) e mostra a soma)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
for (const int *p = a; p < a + n; p++), p aponta, em ordem, do primeiro ao último elemento. O valor do elemento apontado é *p.#include <stdio.h> int sum(const int *a, int n) { int s = 0; for (const int *p = a; p < a + n; p++) { s += *p; } return s; } int main(void) { int n, a[100]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } printf("Soma: %d\n", sum(a, n)); return 0; }
a para uma função, o que é passado é o endereço do primeiro elemento. a + i é o endereço do elemento i posições à frente, e a[i] significa o mesmo que *(a + i). const int * é a promessa de que "esta função não altera o valor apontado"; se você escrever *p = 0; sem querer, dá erro de compilação. a + n aponta para uma posição depois do último elemento, então a condição usa < (com <= a leitura sai dos limites).strlen, a função int my_strlen(const char *s), que retorna o tamanho de uma string (o número de caracteres antes do '\0'). A função main já está pronta (ela lê uma string sem espaços, de letras e dígitos (1 a 99 caracteres), e mostra o tamanho)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
*s não for '\0', conte avançando o ponteiro um caractere por vez com s++. while (*s != '\0') também pode ser escrito como while (*s).#include <stdio.h> int my_strlen(const char *s) { int len = 0; while (*s != '\0') { len++; s++; } return len; } int main(void) { char str[100]; scanf("%99s", str); printf("Tamanho: %d\n", my_strlen(str)); return 0; }
'\0' (caractere nulo). O tamanho não é o tamanho do array (100), e sim o número de caracteres até o '\0'. O que s++ avança é o ponteiro dentro da função (uma cópia), então o str da main não se move. Se você confundir s com *s e escrever while (s != '\0'), como '\0' é uma constante de valor 0, a comparação vira "s é NULL?". Como s nunca vira NULL, o laço não para e continua lendo fora dos limites do array (o compilador também avisa).void minmax(const int *a, int n, int *max, int *min), que encontra o maior e o menor valor de um array de int com n elementos e os escreve nas variáveis apontadas pelos argumentos ponteiro max e min. A função main já está pronta (ela lê N (1 ≤ N ≤ 100) e N inteiros (cada um entre −10000 e 10000) e mostra o resultado)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
*max = *min = a[0];. Depois compare com os elementos a partir do segundo e atualize. A comparação é feita com *max (o valor apontado).#include <stdio.h> void minmax(const int *a, int n, int *max, int *min) { *max = a[0]; *min = a[0]; for (int i = 1; i < n; i++) { if (a[i] > *max) *max = a[i]; if (a[i] < *min) *min = a[i]; } } int main(void) { int n, a[100], max, min; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } minmax(a, n, &max, &min); printf("Máximo: %d\n", max); printf("Mínimo: %d\n", min); return 0; }
if (a[i] > max), estará comparando um valor com um endereço, e o compilador avisa.void reverse(int *a, int n), que inverte no próprio array a ordem dos n elementos de um array de int. Use dois ponteiros, um apontando para o início e outro para o fim, e troque os elementos enquanto eles se aproximam. A função main já está pronta (ela lê N (1 ≤ N ≤ 100) e N inteiros e mostra o array depois de reverse, separado por espaços)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
int *left = a; e int *right = a + n - 1; e, enquanto left < right, troque *left e *right e avance para dentro com left++ e right--.#include <stdio.h> void reverse(int *a, int n) { int *left = a; int *right = a + n - 1; while (left < right) { int tmp = *left; *left = *right; *right = tmp; left++; right--; } } int main(void) { int n, a[100]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } reverse(a, n); for (int i = 0; i < n; i++) { printf("%d ", a[i]); } printf("\n"); return 0; }
a + n - 1, e não a + n (a + n fica fora do array). Para um array, o que é passado é o endereço do início, então alterá-lo dentro da função também muda o array da main. Se você continuar trocando até o fim (até left chegar ao último elemento), cada par é trocado duas vezes e tudo volta ao original; por isso, o ponto-chave é parar no meio.void to_upper(char *s), que troca na própria string as letras minúsculas (a a z) por maiúsculas. Os demais caracteres ficam como estão. Não use funções de biblioteca como toupper: trate um caractere por vez com ponteiro. A função main já está pronta (ela lê uma string sem espaços, de letras e dígitos (1 a 99 caracteres), e mostra o resultado da conversão)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
while (*s != '\0') e, se 'a' <= *s && *s <= 'z', troque com *s = *s - 'a' + 'A';. Não esqueça o s++ no final.#include <stdio.h> void to_upper(char *s) { while (*s != '\0') { if ('a' <= *s && *s <= 'z') { *s = *s - 'a' + 'A'; } s++; } } int main(void) { char str[100]; scanf("%99s", str); to_upper(str); printf("%s\n", str); return 0; }
*s - 'a' + 'A' desloca de minúscula para maiúscula. Como a função altera a string, o argumento é char * sem const. Se você colocar o s++ dentro do if, o laço para no primeiro caractere que não é minúsculo e vira um laço infinito.int *find(int *a, int n, int key), que procura o valor key, a partir do início, em um array de int com n elementos e retorna um ponteiro para o primeiro elemento encontrado. Se não encontrar, retorna NULL. A função main já está pronta: ela calcula o índice pela diferença entre o ponteiro retornado e o início do array (subtração de ponteiros) e o mostra. A entrada é, nesta ordem, N (1 ≤ N ≤ 100), N inteiros e key."Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
for (int *p = a; p < a + n; p++) e, quando *p == key, dê return nesse p. Se sair do laço, é porque não encontrou: retorne NULL.#include <stdio.h> int *find(int *a, int n, int key) { for (int *p = a; p < a + n; p++) { if (*p == key) { return p; } } return NULL; } int main(void) { int n, a[100], key; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } scanf("%d", &key); int *p = find(a, n, key); if (p == NULL) { printf("Não encontrado\n"); } else { printf("Posição: %d\n", (int)(p - a)); } return 0; }
p - a entre dois ponteiros para o mesmo array não dá o número de bytes, e sim quantos elementos de distância há entre eles (por isso é o índice). O ponteiro retornado aponta para o array a da main, então continua válido depois que a função termina. Por outro lado, retornar o endereço de uma variável local da função é um erro (ela deixa de existir quando a função termina).void sort3(int *a, int *b, int *c), que reorganiza os valores de três variáveis int de modo que *a ≤ *b ≤ *c. Para as trocas, você pode usar a função swap já fornecida. A função main já está pronta (ela lê três inteiros e, depois de sort3, mostra-os separados por espaços)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 6 entradas preparadas.
*a > *b, troca", "se *b > *c, troca" e "de novo, se *a > *b, troca". Como a já é um ponteiro, passe-o para swap sem &: swap(a, b).#include <stdio.h> void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } void sort3(int *a, int *b, int *c) { if (*a > *b) swap(a, b); if (*b > *c) swap(b, c); if (*a > *b) swap(a, b); } int main(void) { int x, y, z; scanf("%d %d %d", &x, &y, &z); sort3(&x, &y, &z); printf("%d %d %d\n", x, y, z); return 0; }
*c, mas a ordem entre *a e *b ainda não está definida, por isso o terceiro passo é necessário (dá para conferir com a entrada 2 3 1). Escrever swap(&a, &b) passaria um int **, e os tipos não batem. O ponto-chave é que o ponteiro recebido pode ser repassado como está.malloc espaço para N ints e leia N inteiros (cada um entre −1000 e 1000). Mostre a média com 2 casas decimais e, na linha seguinte, os valores maiores que a média, na ordem de entrada e separados por espaços (se não houver nenhum, não mostre nada depois de "Maiores que a média:"). Se a alocação falhar, mostre "Falha ao alocar memória" e termine; no final, sempre faça free."Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
int *a = malloc(sizeof(int) * n);; se a == NULL, falhou. Depois de alocado, dá para usar a[i] como um array comum. Para "maior que a média", não compare com decimais: comparando com inteiros, a[i] * n > sum, não há erro de arredondamento.#include <stdio.h> #include <stdlib.h> int main(void) { int n; scanf("%d", &n); int *a = malloc(sizeof(int) * n); if (a == NULL) { printf("Falha ao alocar memória\n"); return 1; } long long sum = 0; for (int i = 0; i < n; i++) { scanf("%d", &a[i]); sum += a[i]; } printf("Média: %.2f\n", (double)sum / n); printf("Maiores que a média:"); for (int i = 0; i < n; i++) { if ((long long)a[i] * n > sum) { printf(" %d", a[i]); } } printf("\n"); free(a); return 0; }
malloc apenas o necessário. A memória alocada deve sempre ser liberada com free depois do uso (se esquecer, há vazamento de memória). malloc retorna NULL quando falha, então confira antes de usar. Em C, o retorno de malloc (void *) pode ser atribuído a um int * sem cast. Se você esquecer de multiplicar por sizeof(int) e escrever malloc(n), só N bytes são alocados, e a escrita sai dos limites.char *concat(const char *a, const char *b), que monta, em uma área alocada com malloc, a string formada por a seguida de b, e retorna um ponteiro para o início dela. Se a alocação falhar, retorna NULL. A função main já está pronta (ela lê duas strings sem espaços, de letras e dígitos (cada uma com 1 a 19 caracteres), mostra o resultado e seu tamanho e depois faz free). Você pode usar as funções de string.h."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
strlen(a) + strlen(b) + 1 bytes (o +1 é para o '\0' final). Depois de alocar, copie a com strcpy(s, a); e junte b com strcat(s, b);.#include <stdio.h> #include <stdlib.h> #include <string.h> char *concat(const char *a, const char *b) { char *s = malloc(strlen(a) + strlen(b) + 1); if (s == NULL) { return NULL; } strcpy(s, a); strcat(s, b); return s; } int main(void) { char a[20], b[20]; scanf("%19s %19s", a, b); char *s = concat(a, b); if (s == NULL) { printf("Falha ao alocar memória\n"); return 1; } printf("%s (%d caracteres)\n", s, (int)strlen(s)); free(s); return 0; }
char s[40];, e retornar o endereço dele é um erro. Quando a função termina, o array deixa de existir e o ponteiro retornado fica inválido. A área alocada com malloc continua existindo até o free, então pode ser retornada. Em compensação, quem recebe (a main) fica responsável pelo free. Se você esquecer o +1, o '\0' é escrito fora da área alocada.strcmp). O array de nomes names em si não é mexido: só é reordenado o conteúdo do array p de ponteiros que apontam para cada nome. Escreva as duas funções a seguir.void swap_ptr(char **x, char **y): troca o conteúdo (os ponteiros) de duas variáveis char *void sort_names(char *p[], int n): faz um bubble sort usando swap_ptr"Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
char * dentro da função, recebemos o endereço dela (char **). O corpo de swap_ptr tem a mesma forma do swap de int; só o tipo da variável temporária passa a ser char *. Na ordenação, quando strcmp(p[j], p[j + 1]) > 0, chame swap_ptr(&p[j], &p[j + 1]);.#include <stdio.h> #include <string.h> void swap_ptr(char **x, char **y) { char *tmp = *x; *x = *y; *y = tmp; } void sort_names(char *p[], int n) { for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - 1 - i; j++) { if (strcmp(p[j], p[j + 1]) > 0) { swap_ptr(&p[j], &p[j + 1]); } } } } int main(void) { int n; char names[10][20]; char *p[10]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%19s", names[i]); p[i] = names[i]; } sort_names(p, n); printf("Ordenados:"); for (int i = 0; i < n; i++) printf(" %s", p[i]); printf("\nOrdem original:"); for (int i = 0; i < n; i++) printf(" %s", names[i]); printf("\n"); return 0; }
swap_ptr(char *x, char *y), só as cópias dentro da função seriam trocadas. Diferente de trocar o conteúdo das strings com strcpy, aqui só os ponteiros são trocados, então nenhum caractere é copiado. strcmp segue a ordem dos códigos dos caracteres, então as maiúsculas (K) vêm antes das minúsculas (a). Escrever p[j] > p[j + 1] compararia endereços.