Reunimos 11 exercícios com structs, do nível iniciante ao avançado. Na maioria deles, a definição da struct e parte da função main já estão prontas, e você escreve a parte 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.
struct point, que representa coordenadas (membros x e y), já está definida. Leia os inteiros x e y (cada um entre −10000 e 10000), guarde-os nos membros da variável p, mostre-os no formato "(x, y)" e, na linha seguinte, mostre o quadrado da distância até a origem (x² + y²)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
.), como em p.x. Para o scanf, passe &p.x, como faria com uma variável comum (o . se liga antes do &, então isso significa &(p.x)).#include <stdio.h> struct point { int x; int y; }; int main(void) { struct point p; scanf("%d %d", &p.x, &p.y); printf("(%d, %d)\n", p.x, p.y); printf("Quadrado da distância à origem: %d\n", p.x * p.x + p.y * p.y); return 0; }
struct point inteiro, então na declaração da variável não dá para omitir o struct (para omitir, use typedef). É comum esquecer o ponto e vírgula de }; no fim da definição da struct; preste atenção.struct student, com nome e nota, já está definida. Leia o nome (letras sem espaços, 1 a 19 caracteres) e a nota (0 a 100), guarde-os na variável s e mostre o nome, a nota e o resultado ("Aprovado" se a nota for 60 ou mais, "Reprovado" caso contrário)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
scanf("%19s", s.name) não se coloca & (o nome do array já é o endereço do início). Para a nota, use &s.score.#include <stdio.h> struct student { char name[20]; int score; }; int main(void) { struct student s; scanf("%19s %d", s.name, &s.score); printf("Nome: %s\n", s.name); printf("Nota: %d\n", s.score); if (s.score >= 60) { printf("Resultado: Aprovado\n"); } else { printf("Resultado: Reprovado\n"); } return 0; }
%19s significa "ler no máximo 19 caracteres", deixando espaço para o '\0' para não estourar o array (20 elementos). Note também que não dá para atribuir a um membro string com s.name = "sato"; (fora da inicialização, use strcpy).int to_seconds(struct time t), que recebe por valor a struct struct time (horas, minutos e segundos) e retorna o total de segundos desde 0h00min00s. A função main já está pronta (ela lê horas (0 a 23), minutos (0 a 59) e segundos (0 a 59) e mostra no formato "hh:mm:ss = total s")."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
t.h, t.m e t.s.#include <stdio.h> struct time { int h; int m; int s; }; int to_seconds(struct time t) { return t.h * 3600 + t.m * 60 + t.s; } int main(void) { struct time t; scanf("%d %d %d", &t.h, &t.m, &t.s); printf("%02d:%02d:%02d = %d s\n", t.h, t.m, t.s, to_seconds(t)); return 0; }
t.h = 0; dentro da função, o t da main não muda. Para uma função que só lê os dados, a passagem por valor basta. %02d significa "largura 2, completando com 0 se faltar".Student (nome e nota), nomeada com typedef (a primeira parte da main já está pronta). Continue o código: mostre a média com 1 casa decimal e, na linha seguinte, o nome e a nota de quem tirou a maior nota. Se houver mais de um com a maior nota, mostre quem foi lido primeiro."Executar" roda seu código com a entrada acima. "Corrigir" testa com 5 entradas preparadas.
best, e não pela nota, consegue pegar o nome junto. Comece com best = 0 e atualize só quando s[i].score > s[best].score (com >=, passaria a ser o último).#include <stdio.h> typedef struct { char name[20]; int score; } Student; int main(void) { int n; Student s[50]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%19s %d", s[i].name, &s[i].score); } int sum = 0, best = 0; for (int i = 0; i < n; i++) { sum += s[i].score; if (s[i].score > s[best].score) { best = i; } } printf("Média: %.1f\n", (double)sum / n); printf("Maior nota: %s (%d pts)\n", s[best].name, s[best].score); return 0; }
typedef struct { ... } Student;, dá para usar só Student como nome do tipo, sem escrever struct. O membro de um elemento de um array de structs é escrito na ordem "índice do array → ponto", como em s[i].score. Para a média, se um dos lados não for double, como em (double)sum / n, a divisão é entre inteiros e a parte decimal é descartada.Account (titular e saldo), que representa uma conta.void deposit(Account *a, int amount): aumenta o saldo em amountint withdraw(Account *a, int amount): se houver saldo suficiente, diminui amount e retorna 1; senão, não faz nada e retorna 0+ valor" (depósito) ou "- valor" (saque), e mostra o resultado de cada operação). Os valores e o saldo inicial estão entre 0 e 100000, e Q entre 1 e 20."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
a é escrito como a->balance (o mesmo que (*a).balance). No saque, fica mais fácil se você sair primeiro no caso de saldo insuficiente, com if (a->balance < amount) return 0;.#include <stdio.h> typedef struct { char name[20]; int balance; } Account; void deposit(Account *a, int amount) { a->balance += amount; } int withdraw(Account *a, int amount) { if (a->balance < amount) { return 0; } a->balance -= amount; return 1; } int main(void) { Account acc; int q; scanf("%19s %d", acc.name, &acc.balance); scanf("%d", &q); for (int i = 0; i < q; i++) { char op; int amount; scanf(" %c %d", &op, &amount); if (op == '+') { deposit(&acc, amount); } else if (!withdraw(&acc, amount)) { printf("Saldo insuficiente\n"); } printf("Saldo de %s: %d\n", acc.name, acc.balance); } return 0; }
void deposit(Account a, int amount)), só a cópia é alterada e o saldo da main não aumenta. Para alterar, passe por ponteiro e use . com uma variável struct e -> com um ponteiro para struct. Escrever a.balance dá erro de compilação, e *a.balance é interpretado como *(a.balance); por isso use (*a).balance, com parênteses, ou a->balance.Point midpoint(Point a, Point b), que recebe duas structs Point (coordenadas, com membros x e y do tipo double) e retorna como struct o ponto médio entre elas. A função main já está pronta (ela lê as coordenadas dos dois pontos, x1 y1 x2 y2 (inteiros entre −1000 e 1000), e mostra o ponto médio com 1 casa decimal)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
m.x = (a.x + b.x) / 2;, guarde em m e devolva com return m;.#include <stdio.h> typedef struct { double x; double y; } Point; Point midpoint(Point a, Point b) { Point m = {0.0, 0.0}; m.x = (a.x + b.x) / 2; m.y = (a.y + b.y) / 2; return m; } int main(void) { Point a, b; scanf("%lf %lf %lf %lf", &a.x, &a.y, &b.x, &b.y); Point m = midpoint(a, b); printf("Ponto médio: (%.1f, %.1f)\n", m.x, m.y); return 0; }
return, mas com uma struct dá para devolver vários membros de uma vez. A struct retornada é copiada para quem chamou, então não há problema em retornar a variável local m (é diferente de retornar o endereço de uma variável local). Se os membros fossem int, (0 + 3) / 2 daria 1; por isso aqui eles são double. Para ler um double com scanf, use %lf.Student com um nome e um array de notas de 3 matérias. Escreva a função void print_report(const Student *s), que mostra o total e a média de um aluno. A saída é uma linha por aluno: "nome total média" (média com 1 casa decimal). A função main já está pronta (ela lê N (1 ≤ N ≤ 20) e N linhas "nome nota1 nota2 nota3" (notas de 0 a 100) e chama print_report para cada aluno)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 3 entradas preparadas.
s->score[j]. Calcule o total com for (int j = 0; j < 3; j++) e a média com total / 3.0.#include <stdio.h> typedef struct { char name[20]; int score[3]; } Student; void print_report(const Student *s) { int total = 0; for (int j = 0; j < 3; j++) { total += s->score[j]; } printf("%s %d %.1f\n", s->name, total, total / 3.0); } int main(void) { int n; Student st[20]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%19s", st[i].name); for (int j = 0; j < 3; j++) { scanf("%d", &st[i].score[j]); } } for (int i = 0; i < n; i++) { print_report(&st[i]); } return 0; }
const Student * faz com que uma alteração acidental seja apontada como erro de compilação. Se você dividir entre inteiros com total / 3, a parte decimal é descartada e, além disso, um int é passado para %.1f, o que estraga a exibição.Point (x e y int) e o retângulo Rect, que tem o canto inferior esquerdo corner (do tipo Point), a largura w e a altura h (uma struct dentro de outra struct). Escreva a função int contains(const Rect *r, Point p), que retorna 1 se o ponto p estiver dentro do retângulo (incluindo as bordas) e 0 caso contrário. Estar dentro significa que x está entre corner.x e corner.x + w, e y está entre corner.y e corner.y + h (inclusive). A função main já está pronta (ela lê x y w h do retângulo, o número de pontos Q e os Q pontos, e mostra "dentro" ou "fora" para cada ponto). As coordenadas estão entre −1000 e 1000, e w e h entre 1 e 1000."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
r, fica r->corner.x (r é ponteiro, então ->; corner é a própria struct, então .). Junte as 4 condições com &&.#include <stdio.h> typedef struct { int x; int y; } Point; typedef struct { Point corner; int w; int h; } Rect; int contains(const Rect *r, Point p) { return r->corner.x <= p.x && p.x <= r->corner.x + r->w && r->corner.y <= p.y && p.y <= r->corner.y + r->h; } int main(void) { Rect r; int q; scanf("%d %d %d %d", &r.corner.x, &r.corner.y, &r.w, &r.h); scanf("%d", &q); for (int i = 0; i < q; i++) { Point p; scanf("%d %d", &p.x, &p.y); printf("(%d, %d): %s\n", p.x, p.y, contains(&r, p) ? "dentro" : "fora"); } return 0; }
-> e . segue a regra: "se o lado esquerdo é um ponteiro, ->; se é uma struct, .". r->corner é uma struct do tipo Point, então o que vem depois é .x. Escrever r->corner->x dá erro. O resultado da comparação (0 ou 1) pode ser retornado diretamente com return. Como as bordas contam, use <=.void sort_by_score(Student *s, int n), que ordena os nomes e notas de N alunos (1 ≤ N ≤ 50) da maior nota para a menor. Alunos com a mesma nota devem manter a ordem de entrada. A função main já está pronta (ela lê os dados e, depois de ordenar, mostra uma linha "posição nome nota" por aluno; a posição é simplesmente contada a partir de 1)."Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
s[j].score < s[j + 1].score. Structs podem ser atribuídas inteiras, como em Student tmp = s[j]; s[j] = s[j + 1]; s[j + 1] = tmp;.#include <stdio.h> typedef struct { char name[20]; int score; } Student; void sort_by_score(Student *s, int n) { for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - 1 - i; j++) { if (s[j].score < s[j + 1].score) { Student tmp = s[j]; s[j] = s[j + 1]; s[j + 1] = tmp; } } } } int main(void) { int n; Student s[50]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%19s %d", s[i].name, &s[i].score); } sort_by_score(s, n); for (int i = 0; i < n; i++) { printf("%d %s %d\n", i + 1, s[i].name, s[i].score); } return 0; }
= entre structs, todos os membros são copiados (inclusive o array de caracteres name). Se você trocar só as notas, os pares nome–nota ficam desencontrados, então troque a struct inteira. Se a comparação for <=, a troca acontece também em caso de empate, e os alunos com a mesma nota deixam de ficar na ordem de entrada (teste 4). O bubble sort que troca vizinhos "só quando é menor" é uma ordenação estável, que preserva a ordem de valores iguais.Fraction com numerador num e denominador den. Escreva as duas funções a seguir (a função gcd, que calcula o máximo divisor comum, já está pronta).Fraction reduce(Fraction f): retorna a fração simplificada. Deixe o denominador positivo e, se o numerador for 0, use 0/1Fraction add(Fraction a, Fraction b): retorna a + b simplificadaa/b + c/d = resultado"; as frações de entrada são mostradas como foram lidas, sem simplificar). O numerador está entre −1000 e 1000, e o denominador entre 1 e 1000. Mesmo que o denominador do resultado seja 1, mostre no formato "2/1"."Executar" roda seu código com a entrada acima. "Corrigir" testa com 6 entradas preparadas.
a/b + c/d = (a×d + c×b) / (b×d). Em add, guarde isso em c e faça return reduce(c);. Em reduce, calcule g = gcd(f.num, f.den) e divida numerador e denominador por g (se o numerador for 0, o gcd é o próprio denominador, e o resultado vira 0/1).#include <stdio.h> typedef struct { int num; int den; } Fraction; int gcd(int a, int b) { if (a < 0) a = -a; if (b < 0) b = -b; while (b != 0) { int r = a % b; a = b; b = r; } return a; } Fraction reduce(Fraction f) { if (f.den < 0) { f.num = -f.num; f.den = -f.den; } int g = gcd(f.num, f.den); f.num /= g; f.den /= g; return f; } Fraction add(Fraction a, Fraction b) { Fraction c = {0, 1}; c.num = a.num * b.den + b.num * a.den; c.den = a.den * b.den; return reduce(c); } int main(void) { Fraction a, b; scanf("%d %d %d %d", &a.num, &a.den, &b.num, &b.den); Fraction c = add(a, b); printf("%d/%d + %d/%d = %d/%d\n", a.num, a.den, b.num, b.den, c.num, c.den); return 0; }
reduce segue o padrão de receber a struct por valor e retornar a versão corrigida. O f recebido é uma cópia, então alterá-lo não afeta quem chamou; só o valor devolvido com return f; é usado. Por isso, se você só chamar reduce(c); sem usar o retorno, a fração não é simplificada (use c = reduce(c); ou return reduce(c);). Nas entradas deste exercício o denominador é positivo, então o ajuste de sinal é só uma precaução, mas ao lidar com frações negativas, a regra "deixar o denominador sempre positivo" deixa a exibição consistente.Item (nome, preço unitário e quantidade em estoque), escreva duas funções que processam pedidos.Item *find_item(Item *items, int n, const char *name): retorna um ponteiro para o produto cujo nome é igual a name, ou NULL se não houverint order(Item *items, int n, const char *name, int qty): processa um pedido e retorna o valor da venda. Se o produto não existir, mostra "nome: produto não encontrado" e retorna 0. Se o estoque for menor que qty, mostra "nome: estoque insuficiente (restam k unid.)" e retorna 0. Se houver estoque, diminui o estoque, mostra "nome: qty unid. x R$ preço = R$ valor" e retorna o valor"Executar" roda seu código com a entrada acima. "Corrigir" testa com 4 entradas preparadas.
==; use strcmp(items[i].name, name) == 0. Em find_item, quando encontrar, retorne &items[i] (items + i dá no mesmo). Em order, receba com Item *it = find_item(items, n, name); e use it->stock e it->price.#include <stdio.h> #include <string.h> typedef struct { char name[20]; int price; int stock; } Item; Item *find_item(Item *items, int n, const char *name) { for (int i = 0; i < n; i++) { if (strcmp(items[i].name, name) == 0) { return &items[i]; } } return NULL; } int order(Item *items, int n, const char *name, int qty) { Item *it = find_item(items, n, name); if (it == NULL) { printf("%s: produto não encontrado\n", name); return 0; } if (it->stock < qty) { printf("%s: estoque insuficiente (restam %d unid.)\n", name, it->stock); return 0; } it->stock -= qty; int amount = it->price * qty; printf("%s: %d unid. x R$ %d = R$ %d\n", name, qty, it->price, amount); return amount; } int main(void) { int n, q; Item items[20]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%19s %d %d", items[i].name, &items[i].price, &items[i].stock); } int total = 0; scanf("%d", &q); for (int i = 0; i < q; i++) { char name[20]; int qty; scanf("%19s %d", name, &qty); total += order(items, n, name, qty); } printf("Total de vendas: R$ %d\n", total); for (int i = 0; i < n; i++) { printf("%s: restam %d unid.\n", items[i].name, items[i].stock); } return 0; }
find_item retorna é um ponteiro para um elemento do array da main, então it->stock -= qty; diminui o estoque de verdade. Se você copiar a struct com Item it = items[i]; e diminuir o estoque, só a cópia muda, e o estoque do array continua o mesmo. Ler it->stock quando o retorno é NULL pode derrubar o programa, então sempre verifique antes. items[i].name == name compara endereços, então não dá igual mesmo que as strings sejam iguais.