Projeto Agenda de Contatos
A Ana quer uma agenda no computador: digitar nome e telefone, listar todo mundo, achar um contato pelo nome (sem se importar com maiúsculas) e apagar quem saiu da vida dela. E, o mais importante, que a agenda não suma quando ela fechar o programa. É o projeto para juntar structs, funções, texto e arquivos num programa de verdade, com um menu que se repete.
- Guardar nome e telefone juntos numa struct e ter um array de contatos.
- Ler linhas com espaço usando fgets e tirar o
\ndo fim. - Um menu que se repete com
whileeswitch(veja Sobre os Projetos). - Buscar sem diferenciar maiúsculas, passando o texto por
tolower(ctype.h). - Remover um item de um array deslocando os seguintes para trás.
- Gravar e ler um arquivo de texto com
fprintfesscanf, para a agenda sobreviver ao fechar o programa.
O que vamos construir
A agenda pronta, no terminal da Ana. Ela adiciona dois contatos, lista, busca por "ana", remove a Ana Paula e lista de novo:
$ ./agenda === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 1 Nome: Ana Paula Telefone: 555-1234 Contato adicionado. === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 1 Nome: Bruno Costa Telefone: 555-9000 Contato adicionado. === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 2 Nome Telefone Ana Paula 555-1234 Bruno Costa 555-9000 === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 3 Buscar: ana Ana Paula 555-1234 === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 4 Remover (nome exato): Ana Paula Contato removido. === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 2 Nome Telefone Bruno Costa 555-9000 === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 0 Até logo!
- A struct, o array e o menu (adicionar e listar).
- Buscar sem diferenciar maiúsculas.
- Remover um contato (deslocando o array).
- Gravar e carregar o arquivo de texto.
Antes de começar
Você precisa ter visto Structs, Funções, fgets e, para a versão 4, Arquivos. O arquivo vai se chamar agenda.c:
$ mkdir -p c/agenda $ cd c/agenda
fgets?
Nomes têm espaço ("Ana Paula"), e o scanf("%s") para no primeiro espaço (veja o Boletim de Notas). Por isso a agenda lê cada campo com fgets, que pega a linha inteira. Até a opção do menu é lida com fgets: assim não sobra nenhum \n atrapalhando a próxima leitura — o problema clássico de misturar scanf e fgets.
Versão 1 · A struct, o array e o menu
Primeiro, a base: uma struct Contato com nome e telefone, um array de contatos, e um menu que se repete com duas opções — adicionar e listar. Duas funções ajudam: tirar_novalinha (tira o \n que o fgets deixa) e ler_linha (mostra o rótulo, lê a linha e limpa o \n).
#include <stdio.h>
#include <string.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
void adicionar(struct Contato agenda[], int *n) {
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void listar(const struct Contato agenda[], int n) {
if (n == 0) {
printf("Agenda vazia.\n");
return;
}
printf("\n%-20s %s\n", "Nome", "Telefone");
for (int i = 0; i < n; i++) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
}
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 2. Listar 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); break;
case '2': listar(agenda, n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
- struct Contato { char nome[TAM_NOME]; char telefone[TAM_TEL]; };
- A "ficha" de um contato: nome (até 49 letras + o
'\0') e telefone. Os tamanhos têm nome (#define), como manda as boas práticas. - s[strcspn(s, "\n")] = '\0';
- O
fgetsguarda o Enter como\nno fim. Ostrcspn(s, "\n")dá a posição do\n(ou do fim); pôr um'\0'ali corta o Enter (veja fgets). - int ler_linha(const char *rotulo, char *destino, int tam)
- Uma função só para ler um campo com segurança: mostra o rótulo, chama
fgetscom o tamanho do destino (nunca estoura, veja Segurança) e tira o\n. Devolve 0 se a entrada acabou. - agenda[*n] = c; (*n)++;
- Guarda o novo contato na primeira posição livre e aumenta a contagem. O
nvem por ponteiro porque a função precisa mudar ondomain. - printf("%-20s %s\n", ...)
%-20spõe o nome numa coluna de 20, à esquerda, para a lista ficar alinhada (veja Formatos do printf).- switch (opcao[0])
- A opção é lida como texto;
opcao[0]é a primeira tecla ('1','2','0'). Comparar o caractere evita o problema do\ndoscanf.
$ gcc -std=c23 -Wall -Wextra agenda.c -o agenda $ ./agenda === Agenda da Ana === 1. Adicionar 2. Listar 0. Sair Opção: 1 Nome: Ana Paula Telefone: 555-1234 Contato adicionado. === Agenda da Ana === 1. Adicionar 2. Listar 0. Sair Opção: 2 Nome Telefone Ana Paula 555-1234 === Agenda da Ana === 1. Adicionar 2. Listar 0. Sair Opção: 0 Até logo!
Missão (versão 1): a função listar mostra o cabeçalho, mas não os contatos. Escreva o for que percorre agenda[0] até agenda[n - 1] e mostra cada um com printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);. A entrada adiciona Ana Paula e Bruno Costa e lista.
#include <stdio.h>
#include <string.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
void adicionar(struct Contato agenda[], int *n) {
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void listar(const struct Contato agenda[], int n) {
if (n == 0) {
printf("Agenda vazia.\n");
return;
}
printf("\n%-20s %s\n", "Nome", "Telefone");
// escreva aqui o for que mostra cada contato (use agenda[i].nome e agenda[i].telefone)
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 2. Listar 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); break;
case '2': listar(agenda, n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
#include <stdio.h>
#include <string.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
void adicionar(struct Contato agenda[], int *n) {
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void listar(const struct Contato agenda[], int n) {
if (n == 0) {
printf("Agenda vazia.\n");
return;
}
printf("\n%-20s %s\n", "Nome", "Telefone");
for (int i = 0; i < n; i++) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
}
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 2. Listar 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); break;
case '2': listar(agenda, n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
Versão 2 · Buscar sem diferenciar maiúsculas
A Ana digita "ana" e quer achar "Ana Paula". Para isso, a busca não pode diferenciar maiúsculas de minúsculas. A ideia: passar os dois textos para minúsculas (com tolower) e ver se um está dentro do outro com strstr (veja Funções de String). A função contem_ignorando_caso faz isso; a buscar a usa em cada contato.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
int contem_ignorando_caso(const char *texto, const char *parte) {
char t[TAM_NOME];
char p[TAM_NOME];
int i;
for (i = 0; texto[i] != '\0' && i < TAM_NOME - 1; i++) {
t[i] = (char) tolower((unsigned char) texto[i]);
}
t[i] = '\0';
for (i = 0; parte[i] != '\0' && i < TAM_NOME - 1; i++) {
p[i] = (char) tolower((unsigned char) parte[i]);
}
p[i] = '\0';
return strstr(t, p) != NULL;
}
void adicionar(struct Contato agenda[], int *n) {
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void buscar(const struct Contato agenda[], int n) {
char alvo[TAM_NOME];
ler_linha("Buscar: ", alvo, TAM_NOME);
int achou = 0;
for (int i = 0; i < n; i++) {
if (contem_ignorando_caso(agenda[i].nome, alvo)) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
achou = 1;
}
}
if (!achou) {
printf("Nenhum contato com \"%s\".\n", alvo);
}
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 3. Buscar 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); break;
case '3': buscar(agenda, n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
- tolower((unsigned char) texto[i])
- Transforma a letra em minúscula. O
(unsigned char)evita um problema com acentos e valores negativos (veja ctype.h). - strstr(t, p) != NULL
strstr("string in string") procura o textopdentro dete devolve onde ele começa, ouNULLse não achar. Assim a busca acha parte do nome: "cost" acha "Bruno Costa".- if (contem_ignorando_caso(agenda[i].nome, alvo))
- Para cada contato, pergunta "o nome contém o que a Ana procura?". Se sim, mostra e marca
achou = 1.
$ ./agenda === Agenda da Ana === 1. Adicionar 3. Buscar 0. Sair Opção: 3 Buscar: ANA Ana Paula 555-1234 === Agenda da Ana === 1. Adicionar 3. Buscar 0. Sair Opção: 3 Buscar: zeca Nenhum contato com "zeca".
"ANA" em maiúsculas achou "Ana Paula": a busca não liga para o tamanho das letras. E um nome que não existe dá uma mensagem clara, em vez de silêncio.
Missão (versão 2): a função buscar tem o laço, mas não compara. Dentro do for, se contem_ignorando_caso(agenda[i].nome, alvo) for verdadeiro, mostre o contato com printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone); e faça achou = 1;. A entrada busca "ana" e deve achar a Ana Paula.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
int contem_ignorando_caso(const char *texto, const char *parte) {
char t[TAM_NOME];
char p[TAM_NOME];
int i;
for (i = 0; texto[i] != '\0' && i < TAM_NOME - 1; i++) {
t[i] = (char) tolower((unsigned char) texto[i]);
}
t[i] = '\0';
for (i = 0; parte[i] != '\0' && i < TAM_NOME - 1; i++) {
p[i] = (char) tolower((unsigned char) parte[i]);
}
p[i] = '\0';
return strstr(t, p) != NULL;
}
void adicionar(struct Contato agenda[], int *n) {
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void buscar(const struct Contato agenda[], int n) {
char alvo[TAM_NOME];
ler_linha("Buscar: ", alvo, TAM_NOME);
int achou = 0;
for (int i = 0; i < n; i++) {
// se o nome do contato i contém "alvo" (sem diferenciar maiúsculas),
// mostre-o e faça achou = 1
}
if (!achou) {
printf("Nenhum contato com \"%s\".\n", alvo);
}
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 3. Buscar 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); break;
case '3': buscar(agenda, n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
int contem_ignorando_caso(const char *texto, const char *parte) {
char t[TAM_NOME];
char p[TAM_NOME];
int i;
for (i = 0; texto[i] != '\0' && i < TAM_NOME - 1; i++) {
t[i] = (char) tolower((unsigned char) texto[i]);
}
t[i] = '\0';
for (i = 0; parte[i] != '\0' && i < TAM_NOME - 1; i++) {
p[i] = (char) tolower((unsigned char) parte[i]);
}
p[i] = '\0';
return strstr(t, p) != NULL;
}
void adicionar(struct Contato agenda[], int *n) {
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void buscar(const struct Contato agenda[], int n) {
char alvo[TAM_NOME];
ler_linha("Buscar: ", alvo, TAM_NOME);
int achou = 0;
for (int i = 0; i < n; i++) {
if (contem_ignorando_caso(agenda[i].nome, alvo)) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
achou = 1;
}
}
if (!achou) {
printf("Nenhum contato com \"%s\".\n", alvo);
}
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 3. Buscar 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); break;
case '3': buscar(agenda, n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
Versão 3 · Remover um contato
Remover de um array é mais sutil do que parece: não basta "apagar" a posição, porque ficaria um buraco no meio. O jeito certo é deslocar todos os contatos seguintes uma posição para trás, tampando o buraco, e depois diminuir a contagem.
Antes (remover o índice 0): [Ana Paula][Bruno Costa][Diego] n = 3 Desloca para trás: [Bruno Costa][Diego][Diego] « cada um copia o seguinte Diminui a contagem: [Bruno Costa][Diego] n = 2
#include <stdio.h>
#include <string.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
void adicionar(struct Contato agenda[], int *n) {
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void listar(const struct Contato agenda[], int n) {
if (n == 0) {
printf("Agenda vazia.\n");
return;
}
printf("\n%-20s %s\n", "Nome", "Telefone");
for (int i = 0; i < n; i++) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
}
}
void remover(struct Contato agenda[], int *n) {
char alvo[TAM_NOME];
ler_linha("Remover (nome exato): ", alvo, TAM_NOME);
for (int i = 0; i < *n; i++) {
if (strcmp(agenda[i].nome, alvo) == 0) {
for (int j = i; j < *n - 1; j++) {
agenda[j] = agenda[j + 1];
}
(*n)--;
printf("Contato removido.\n");
return;
}
}
printf("Contato \"%s\" não encontrado.\n", alvo);
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 2. Listar 4. Remover 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); break;
case '2': listar(agenda, n); break;
case '4': remover(agenda, &n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
- if (strcmp(agenda[i].nome, alvo) == 0)
- Acha o contato com o nome exato. O
strcmpdevolve 0 quando os textos são iguais (veja Funções de String). - for (int j = i; j < *n - 1; j++) agenda[j] = agenda[j + 1];
- O coração da remoção: cada contato, do achado em diante, recebe o seguinte. Uma struct inteira é copiada de uma vez com
=. - (*n)--;
- Agora há um contato a menos. A última posição tem uma cópia velha, mas ela está fora da contagem e nunca é mostrada.
- return;
- Para no primeiro que casa: remove um contato por vez.
$ ./agenda === Agenda da Ana === 1. Adicionar 2. Listar 4. Remover 0. Sair Opção: 4 Remover (nome exato): Ana Paula Contato removido. === Agenda da Ana === 1. Adicionar 2. Listar 4. Remover 0. Sair Opção: 2 Nome Telefone Bruno Costa 555-9000
Missão (versão 3): a remover acha o contato e diminui a contagem, mas esqueceu de deslocar os seguintes — então o removido continua na lista. Escreva o for interno que, de j = i até *n - 2, faz agenda[j] = agenda[j + 1];. A entrada adiciona Ana Paula e Bruno Costa, remove a Ana Paula e lista: só deve sobrar o Bruno Costa.
#include <stdio.h>
#include <string.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
void adicionar(struct Contato agenda[], int *n) {
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void listar(const struct Contato agenda[], int n) {
if (n == 0) {
printf("Agenda vazia.\n");
return;
}
printf("\n%-20s %s\n", "Nome", "Telefone");
for (int i = 0; i < n; i++) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
}
}
void remover(struct Contato agenda[], int *n) {
char alvo[TAM_NOME];
ler_linha("Remover (nome exato): ", alvo, TAM_NOME);
for (int i = 0; i < *n; i++) {
if (strcmp(agenda[i].nome, alvo) == 0) {
// desloque cada contato seguinte uma posição para trás,
// de j = i até *n - 2: agenda[j] = agenda[j + 1];
(*n)--;
printf("Contato removido.\n");
return;
}
}
printf("Contato \"%s\" não encontrado.\n", alvo);
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 2. Listar 4. Remover 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); break;
case '2': listar(agenda, n); break;
case '4': remover(agenda, &n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
#include <stdio.h>
#include <string.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
void adicionar(struct Contato agenda[], int *n) {
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void listar(const struct Contato agenda[], int n) {
if (n == 0) {
printf("Agenda vazia.\n");
return;
}
printf("\n%-20s %s\n", "Nome", "Telefone");
for (int i = 0; i < n; i++) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
}
}
void remover(struct Contato agenda[], int *n) {
char alvo[TAM_NOME];
ler_linha("Remover (nome exato): ", alvo, TAM_NOME);
for (int i = 0; i < *n; i++) {
if (strcmp(agenda[i].nome, alvo) == 0) {
for (int j = i; j < *n - 1; j++) {
agenda[j] = agenda[j + 1];
}
(*n)--;
printf("Contato removido.\n");
return;
}
}
printf("Contato \"%s\" não encontrado.\n", alvo);
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 2. Listar 4. Remover 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); break;
case '2': listar(agenda, n); break;
case '4': remover(agenda, &n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
Versão 4 · Gravar e carregar o arquivo
Até aqui a agenda vivia só na memória: ao fechar o programa, tudo sumia. A versão final grava os contatos num arquivo de texto, agenda.txt, e o lê de volta quando abre. Duas funções novas:
salvarabre o arquivo para escrita ("w") e grava cada contato numa linhanome;telefonecomfprintf(veja Escrever Arquivos).carregarabre o arquivo para leitura ("r"), lê cada linha comfgetse separa o nome do telefone comsscanf(veja Ler Arquivos).
O main chama carregar logo no começo e salvar depois de toda mudança (adicionar e remover). O menu ganha as quatro opções.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
#define ARQUIVO "agenda.txt"
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
int contem_ignorando_caso(const char *texto, const char *parte) {
char t[TAM_NOME];
char p[TAM_NOME];
int i;
for (i = 0; texto[i] != '\0' && i < TAM_NOME - 1; i++) {
t[i] = (char) tolower((unsigned char) texto[i]);
}
t[i] = '\0';
for (i = 0; parte[i] != '\0' && i < TAM_NOME - 1; i++) {
p[i] = (char) tolower((unsigned char) parte[i]);
}
p[i] = '\0';
return strstr(t, p) != NULL;
}
void adicionar(struct Contato agenda[], int *n) {
if (*n >= MAX_CONTATOS) {
printf("Agenda cheia.\n");
return;
}
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void listar(const struct Contato agenda[], int n) {
if (n == 0) {
printf("Agenda vazia.\n");
return;
}
printf("\n%-20s %s\n", "Nome", "Telefone");
for (int i = 0; i < n; i++) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
}
}
void buscar(const struct Contato agenda[], int n) {
char alvo[TAM_NOME];
ler_linha("Buscar: ", alvo, TAM_NOME);
int achou = 0;
for (int i = 0; i < n; i++) {
if (contem_ignorando_caso(agenda[i].nome, alvo)) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
achou = 1;
}
}
if (!achou) {
printf("Nenhum contato com \"%s\".\n", alvo);
}
}
void remover(struct Contato agenda[], int *n) {
char alvo[TAM_NOME];
ler_linha("Remover (nome exato): ", alvo, TAM_NOME);
for (int i = 0; i < *n; i++) {
if (strcmp(agenda[i].nome, alvo) == 0) {
for (int j = i; j < *n - 1; j++) {
agenda[j] = agenda[j + 1];
}
(*n)--;
printf("Contato removido.\n");
return;
}
}
printf("Contato \"%s\" não encontrado.\n", alvo);
}
void salvar(const struct Contato agenda[], int n) {
FILE *f = fopen(ARQUIVO, "w");
if (f == NULL) {
perror(ARQUIVO);
return;
}
for (int i = 0; i < n; i++) {
fprintf(f, "%s;%s\n", agenda[i].nome, agenda[i].telefone);
}
fclose(f);
}
void carregar(struct Contato agenda[], int *n) {
FILE *f = fopen(ARQUIVO, "r");
if (f == NULL) {
return;
}
char linha[TAM_NOME + TAM_TEL];
while (*n < MAX_CONTATOS && fgets(linha, sizeof linha, f) != NULL) {
if (sscanf(linha, "%49[^;];%19[^\n]", agenda[*n].nome, agenda[*n].telefone) == 2) {
(*n)++;
}
}
fclose(f);
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
carregar(agenda, &n);
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); salvar(agenda, n); break;
case '2': listar(agenda, n); break;
case '3': buscar(agenda, n); break;
case '4': remover(agenda, &n); salvar(agenda, n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
- FILE *f = fopen(ARQUIVO, "w");
- Abre
agenda.txtpara escrita; o"w"cria o arquivo (ou apaga o conteúdo antigo). Sefopenfalhar, devolveNULL— por isso oiflogo depois, com perror. - fprintf(f, "%s;%s\n", ...)
- Grava
nome;telefonee um Enter. O;separa os dois campos; por isso o telefone não pode ter;. - fopen(ARQUIVO, "r")
- Abre para leitura. Se o arquivo ainda não existe (primeira vez), devolve
NULLecarregarsimplesmente volta: a agenda começa vazia. - sscanf(linha, "%49[^;];%19[^\n]", ...)
- O
%49[^;]lê até 49 caracteres que não sejam;(o nome, com espaços e tudo); o;casa o separador; o%19[^\n]lê o resto da linha (o telefone). As larguras 49 e 19 protegem os arrays. Se vierem os dois campos (== 2), o contato entra. - salvar(agenda, n); depois de adicionar e remover
- A agenda é gravada a cada mudança, então nunca se perde nada, mesmo que o programa feche sem querer.
Agora a prova dos nove: adicionar, fechar o programa e abrir de novo. O contato continua lá, porque veio do arquivo:
$ ls agenda.txt ls: não foi possível acessar 'agenda.txt': Arquivo ou diretório inexistente $ ./agenda «… a Ana adiciona a Ana Paula e escolhe 0 para sair …» Até logo! $ cat agenda.txt Ana Paula;555-1234 $ ./agenda « abre de novo, sem readicionar ninguém === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 2 Nome Telefone Ana Paula 555-1234
O arquivo agenda.txt é texto puro: você pode abri-lo em qualquer editor e ver os contatos. Essa é a graça de um formato de texto — simples de gravar, de ler e de conferir.
Missão final (versão 4): o agenda.txt já tem dois contatos (está na aba ao lado), mas a função carregar não os lê — ao listar, aparece "Agenda vazia". Complete o laço de carregar: para cada linha, use sscanf(linha, "%49[^;];%19[^\n]", agenda[*n].nome, agenda[*n].telefone) e, se ele devolver 2, faça (*n)++. A entrada só lista (opção 2) e sai; devem aparecer os dois contatos do arquivo.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
#define ARQUIVO "agenda.txt"
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
int contem_ignorando_caso(const char *texto, const char *parte) {
char t[TAM_NOME];
char p[TAM_NOME];
int i;
for (i = 0; texto[i] != '\0' && i < TAM_NOME - 1; i++) {
t[i] = (char) tolower((unsigned char) texto[i]);
}
t[i] = '\0';
for (i = 0; parte[i] != '\0' && i < TAM_NOME - 1; i++) {
p[i] = (char) tolower((unsigned char) parte[i]);
}
p[i] = '\0';
return strstr(t, p) != NULL;
}
void adicionar(struct Contato agenda[], int *n) {
if (*n >= MAX_CONTATOS) {
printf("Agenda cheia.\n");
return;
}
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void listar(const struct Contato agenda[], int n) {
if (n == 0) {
printf("Agenda vazia.\n");
return;
}
printf("\n%-20s %s\n", "Nome", "Telefone");
for (int i = 0; i < n; i++) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
}
}
void buscar(const struct Contato agenda[], int n) {
char alvo[TAM_NOME];
ler_linha("Buscar: ", alvo, TAM_NOME);
int achou = 0;
for (int i = 0; i < n; i++) {
if (contem_ignorando_caso(agenda[i].nome, alvo)) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
achou = 1;
}
}
if (!achou) {
printf("Nenhum contato com \"%s\".\n", alvo);
}
}
void remover(struct Contato agenda[], int *n) {
char alvo[TAM_NOME];
ler_linha("Remover (nome exato): ", alvo, TAM_NOME);
for (int i = 0; i < *n; i++) {
if (strcmp(agenda[i].nome, alvo) == 0) {
for (int j = i; j < *n - 1; j++) {
agenda[j] = agenda[j + 1];
}
(*n)--;
printf("Contato removido.\n");
return;
}
}
printf("Contato \"%s\" não encontrado.\n", alvo);
}
void salvar(const struct Contato agenda[], int n) {
FILE *f = fopen(ARQUIVO, "w");
if (f == NULL) {
perror(ARQUIVO);
return;
}
for (int i = 0; i < n; i++) {
fprintf(f, "%s;%s\n", agenda[i].nome, agenda[i].telefone);
}
fclose(f);
}
void carregar(struct Contato agenda[], int *n) {
FILE *f = fopen(ARQUIVO, "r");
if (f == NULL) {
return;
}
char linha[TAM_NOME + TAM_TEL];
while (*n < MAX_CONTATOS && fgets(linha, sizeof linha, f) != NULL) {
// separe a linha "nome;telefone" com sscanf e, se vierem os 2 campos,
// guarde em agenda[*n] e faça (*n)++
}
fclose(f);
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
carregar(agenda, &n);
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); salvar(agenda, n); break;
case '2': listar(agenda, n); break;
case '3': buscar(agenda, n); break;
case '4': remover(agenda, &n); salvar(agenda, n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
Ana Paula;555-1234 Bruno Costa;555-9000
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
#define ARQUIVO "agenda.txt"
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
int contem_ignorando_caso(const char *texto, const char *parte) {
char t[TAM_NOME];
char p[TAM_NOME];
int i;
for (i = 0; texto[i] != '\0' && i < TAM_NOME - 1; i++) {
t[i] = (char) tolower((unsigned char) texto[i]);
}
t[i] = '\0';
for (i = 0; parte[i] != '\0' && i < TAM_NOME - 1; i++) {
p[i] = (char) tolower((unsigned char) parte[i]);
}
p[i] = '\0';
return strstr(t, p) != NULL;
}
void adicionar(struct Contato agenda[], int *n) {
if (*n >= MAX_CONTATOS) {
printf("Agenda cheia.\n");
return;
}
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void listar(const struct Contato agenda[], int n) {
if (n == 0) {
printf("Agenda vazia.\n");
return;
}
printf("\n%-20s %s\n", "Nome", "Telefone");
for (int i = 0; i < n; i++) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
}
}
void buscar(const struct Contato agenda[], int n) {
char alvo[TAM_NOME];
ler_linha("Buscar: ", alvo, TAM_NOME);
int achou = 0;
for (int i = 0; i < n; i++) {
if (contem_ignorando_caso(agenda[i].nome, alvo)) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
achou = 1;
}
}
if (!achou) {
printf("Nenhum contato com \"%s\".\n", alvo);
}
}
void remover(struct Contato agenda[], int *n) {
char alvo[TAM_NOME];
ler_linha("Remover (nome exato): ", alvo, TAM_NOME);
for (int i = 0; i < *n; i++) {
if (strcmp(agenda[i].nome, alvo) == 0) {
for (int j = i; j < *n - 1; j++) {
agenda[j] = agenda[j + 1];
}
(*n)--;
printf("Contato removido.\n");
return;
}
}
printf("Contato \"%s\" não encontrado.\n", alvo);
}
void salvar(const struct Contato agenda[], int n) {
FILE *f = fopen(ARQUIVO, "w");
if (f == NULL) {
perror(ARQUIVO);
return;
}
for (int i = 0; i < n; i++) {
fprintf(f, "%s;%s\n", agenda[i].nome, agenda[i].telefone);
}
fclose(f);
}
void carregar(struct Contato agenda[], int *n) {
FILE *f = fopen(ARQUIVO, "r");
if (f == NULL) {
return;
}
char linha[TAM_NOME + TAM_TEL];
while (*n < MAX_CONTATOS && fgets(linha, sizeof linha, f) != NULL) {
if (sscanf(linha, "%49[^;];%19[^\n]", agenda[*n].nome, agenda[*n].telefone) == 2) {
(*n)++;
}
}
fclose(f);
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
carregar(agenda, &n);
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); salvar(agenda, n); break;
case '2': listar(agenda, n); break;
case '3': buscar(agenda, n); break;
case '4': remover(agenda, &n); salvar(agenda, n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
O que aconteceu: quase sempre o programa foi rodado de uma pasta diferente da do agenda.txt. O fopen("agenda.txt", ...) procura o arquivo na pasta em que o programa roda, não na pasta do código.
Como resolver: rode o programa de dentro da pasta onde está o agenda.txt (cd ~/c/agenda). No editor do guia, o arquivo é a aba agenda.txt e fica sempre junto.
O programa completo
A versão final, igual à versão 4. Compile com gcc -std=c23 -Wall -Wextra agenda.c -o agenda:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_CONTATOS 100
#define TAM_NOME 50
#define TAM_TEL 20
#define ARQUIVO "agenda.txt"
struct Contato {
char nome[TAM_NOME];
char telefone[TAM_TEL];
};
void tirar_novalinha(char *s) {
s[strcspn(s, "\n")] = '\0';
}
int ler_linha(const char *rotulo, char *destino, int tam) {
printf("%s", rotulo);
if (fgets(destino, tam, stdin) == NULL) {
return 0;
}
tirar_novalinha(destino);
return 1;
}
int contem_ignorando_caso(const char *texto, const char *parte) {
char t[TAM_NOME];
char p[TAM_NOME];
int i;
for (i = 0; texto[i] != '\0' && i < TAM_NOME - 1; i++) {
t[i] = (char) tolower((unsigned char) texto[i]);
}
t[i] = '\0';
for (i = 0; parte[i] != '\0' && i < TAM_NOME - 1; i++) {
p[i] = (char) tolower((unsigned char) parte[i]);
}
p[i] = '\0';
return strstr(t, p) != NULL;
}
void adicionar(struct Contato agenda[], int *n) {
if (*n >= MAX_CONTATOS) {
printf("Agenda cheia.\n");
return;
}
struct Contato c = {0};
ler_linha("Nome: ", c.nome, TAM_NOME);
ler_linha("Telefone: ", c.telefone, TAM_TEL);
agenda[*n] = c;
(*n)++;
printf("Contato adicionado.\n");
}
void listar(const struct Contato agenda[], int n) {
if (n == 0) {
printf("Agenda vazia.\n");
return;
}
printf("\n%-20s %s\n", "Nome", "Telefone");
for (int i = 0; i < n; i++) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
}
}
void buscar(const struct Contato agenda[], int n) {
char alvo[TAM_NOME];
ler_linha("Buscar: ", alvo, TAM_NOME);
int achou = 0;
for (int i = 0; i < n; i++) {
if (contem_ignorando_caso(agenda[i].nome, alvo)) {
printf("%-20s %s\n", agenda[i].nome, agenda[i].telefone);
achou = 1;
}
}
if (!achou) {
printf("Nenhum contato com \"%s\".\n", alvo);
}
}
void remover(struct Contato agenda[], int *n) {
char alvo[TAM_NOME];
ler_linha("Remover (nome exato): ", alvo, TAM_NOME);
for (int i = 0; i < *n; i++) {
if (strcmp(agenda[i].nome, alvo) == 0) {
for (int j = i; j < *n - 1; j++) {
agenda[j] = agenda[j + 1];
}
(*n)--;
printf("Contato removido.\n");
return;
}
}
printf("Contato \"%s\" não encontrado.\n", alvo);
}
void salvar(const struct Contato agenda[], int n) {
FILE *f = fopen(ARQUIVO, "w");
if (f == NULL) {
perror(ARQUIVO);
return;
}
for (int i = 0; i < n; i++) {
fprintf(f, "%s;%s\n", agenda[i].nome, agenda[i].telefone);
}
fclose(f);
}
void carregar(struct Contato agenda[], int *n) {
FILE *f = fopen(ARQUIVO, "r");
if (f == NULL) {
return;
}
char linha[TAM_NOME + TAM_TEL];
while (*n < MAX_CONTATOS && fgets(linha, sizeof linha, f) != NULL) {
if (sscanf(linha, "%49[^;];%19[^\n]", agenda[*n].nome, agenda[*n].telefone) == 2) {
(*n)++;
}
}
fclose(f);
}
int main(void) {
struct Contato agenda[MAX_CONTATOS];
int n = 0;
carregar(agenda, &n);
char opcao[10];
int rodando = 1;
while (rodando) {
printf("\n=== Agenda da Ana ===\n");
printf("1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n");
printf("Opção: ");
if (fgets(opcao, sizeof opcao, stdin) == NULL) {
break;
}
switch (opcao[0]) {
case '1': adicionar(agenda, &n); salvar(agenda, n); break;
case '2': listar(agenda, n); break;
case '3': buscar(agenda, n); break;
case '4': remover(agenda, &n); salvar(agenda, n); break;
case '0': rodando = 0; break;
default: printf("Opção inválida.\n");
}
}
printf("Até logo!\n");
return 0;
}
O que o projeto juntou: structs, um array e um contador, funções com passagem por ponteiro, fgets para texto com espaço, tolower e strstr/strcmp para a busca, o deslocamento do array na remoção e os arquivos para a agenda durar.
Desafios extras
- Editar um contato. Acrescente a opção "5. Editar": busca pelo nome exato e deixa a Ana trocar o telefone.
- Ordem alfabética. Antes de listar, ordene o array por nome com qsort e
strcmp. - Confirmar a remoção. Antes de remover, pergunte "Tem certeza? (s/n)" e só remova se a resposta for
s. - Agenda de qualquer tamanho. Troque o array fixo de 100 por um array que cresce com realloc quando enche (veja Array que Cresce).
- Telefone com
;. Pense no que acontece se um nome tiver;e escolha outro separador, ou grave em outro formato.
Exercícios
1. Por que a agenda lê os nomes com fgets em vez de scanf("%s")?
2. Para remover o contato da posição i de um array de n contatos, o que o programa faz?
3. O que a busca faz para não diferenciar maiúsculas?
4. Por que a agenda chama salvar depois de adicionar e remover?
5. Complete o modo do fopen para escrever (criar/sobrescrever) o arquivo:
6. Complete a função que compara dois nomes e vale 0 quando são iguais:
Resumo
- Uma struct junta os dados de um contato; um array de structs e um contador guardam a agenda.
- Ler tudo com fgets (inclusive a opção do menu) aceita nomes com espaço e evita o
\nperdido doscanf. - Buscar sem diferenciar maiúsculas: passar os textos por
tolowere usarstrstr. - Remover de um array é deslocar os seguintes para trás e diminuir a contagem.
- Gravar com
fprintfe ler comfgets+sscanf(com larguras) faz a agenda durar depois de fechar o programa.
Próximo projeto: Estoque da Lojinha (binário).