#  > Desenvolvimento >  > Linguagens de Programação >  >  Agenda telefonica com funções e ponteiros...

## c0dek's

E ai povu, fmz, entaum, eu toh aprendendo a programar em C, dai eu toh fazendo uma agenda telefonica com estruturas e ponteiros, por enquanto eh soh um prototipo, mais mesmo esse prototipo num funciona, já li o código milhares de vezes e não entendo, ele pula alguna scanf, e na parte de listar está muito estranho, compilem e vejam...

XX --------- INICIO DO CÓDIGO ------------ XX
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

struct reg{
char nome[40];
char tel[10];
char end[50];
struct reg *next; /* Ponteiro que corresponde ao proximo registro */
struct reg *back; /* Pomteiro que corresponde ao registro anterior */
} lista;
struct reg *last; /* Ultimo registro */
struct reg *first; /* Primeiro */
struct reg *null; /* Ponteiro NULL */

main(){
system("clear");
null = (struct reg *) malloc(sizeof(lista));
int opcao;
printf ("\nAgenda Telefica v0.1 by c0dek\n----------\n\nDigite o numero correspondente a sua opção: \n\n");
printf ("\n1. Inserir");
printf ("\n2. Listar");
printf ("\n3. Sair deste programa");
printf ("\n----------\n");
printf("\nSua opção: ");
puts(" ");
do{ scanf("%d", &opcao);
switch(opcao){
case 1:
inserir();
break;
case 2:
listar();
break;
case 3:
exit(0);
default: printf("\nOpção invalida!");
} 
} while (1);
}

inserir(){
char opcao;
struct reg *this;
this =(struct reg *) malloc(sizeof(lista));
do{if (this == 0){
printf("\nMemória insuficiente para alocação!");
return (0);
}
inputs("\nInsira o nome do contato: ", this->nome, 40);
inputs("\nInsira o telefone do contato: ", this->tel, 10);
inputs("\nInsira o endereço do contato: ", this->end, 50);

if(first!=0){
last->next = this;
this->back = last;
last = this;
this->next = null;
} else {
first = this;
last = this;
this->next = null;
this->back = null;
}
printf("\nInserir mais um registro?[y/n]");
scanf("%c", &opcao);
}while (opcao != 'n' && opcao != 'N');
printf("\nDesalocando memória...");
free(this);
main();
}

listar(){
int opcao;
struct reg *this;
this = first;
do{
system("clear");
display(this);
printf("\n1. Proximo Registro - 2. Registro Anterior - 3. Voltar para o Menu");
scanf("%d", &opcao);
switch(opcao){
case 1:
if(this->next == null){
printf("\nUltima entrada...");
sleep(1);
}
this = this->next; 
case 2:
if(this->back == null){
printf("\nPrimeira entrada...");
sleep(1);
main();
}
this = this->back;
case 3:
main();
}
} while (1); 
return;
}

display(this)
struct reg *this;
{
printf("\n\n\n-- Inicio do contato --");
printf("\nNome: %s", this->nome);
printf("\nTelecone: %s", this->tel);
printf("\nEndereço: %s", this->end);
printf("\n-- Fim do contato --\n\n\n");
return;
}




inputs(pergunta, var, tam)
char *pergunta;
char *var;
int tam;
{
char value[255];
printf("%s", pergunta);
scanf("%s", value);
if(strlen(value) > tam)
printf("\nOs dados inseridor superam o limite de caracteres..."); return;
strcpy(var, value);
}

XX ------------------ FIM DO CÓDIGO ----------------- XX

----------


## c0deks

pow ninguem sabe, eu dei uma lida e ouvi dizer que isso eh problema de buffer, tentei usar um fflush(stdin), mais num adiantou, ninguem tem alguma pista sobre como resolver???

----------


## serrato

que erro está dando???

----------


## c0dek's

Os erros saum os seguinter, por exemplo no registrar ele pula o scanf em que pergunta se que registrar outro contato, e no listar ele entra em loop infinito, ou simplesmente naum funciona...

----------


## a2gs

Ola,
Na funcao inputs(), linhas:
....
if(strlen(value) > tam)
printf("\nOs dados inseridor superam o limite de caracteres..."); return;
strcpy(var, value);
} 
....

O if() esta faltando chaves. Pelo q vi, vc quer algo assim:
.....
if(strlen(value) > tam){ /* ABRE */
printf("\nOs dados inseridor superam o limite de caracteres...");
return;
} /* FECHA */
strcpy(var, value);
}
....

Isso pode resolver alguma coisa (o use de chaves eh desnecessario para 1 comando, nao p/ 1 linha).

Sobre a funcao listar(), acho melhor vc repensar sua logica (dica: nao chame main(), NUNCA (dê uma olhada/lida sobre Stack e Recursividade)).

De resto, tah blz! Tah indo muito bem. Umas pequenas dicas:
- crie prototipos de funcoes, sempre! (funcoes q sao usadas somente no mesmo '.c', no inicio do arquivo '.c'(com a palavra 'static'). Funcoes chamadas por outro modulos, devem ter prototipos em '.h')
- especifique o tipo de retorno nas funcoes (todas as suas sao int por DEFAULT de compilacao. Isso da uma grande margem a erros! Principalmente se vc nao tiver compilando com -Wall)
- K&R nao recomendam na Biblia a sintax: func(var) varType var { ... }. Logo, se Eles falam isso, eu presciso falar alguma coisa??? :)
- evite (mesmo nao sendo c++) usar palavras como 'this' p/ variaveis... entre outras ('null', nao sei como vc nao teve erro com isso, mesmo minusculo) . Use nomes estranhos como 'thisVar'
- limpar a tela com system("clear") eh bem engenhoso p/ quem tah iniciando. Quando achar a hora certa, leia sobre ncurses (3n), vc nao tera problemas.
- A declaraçao da sua struct esta certa. Mas tente com typedef, o codigo fica mais limpo.

(inputs() ainda possui um bufferoverflow, tente achar. Depois veja nscanf(), ou fgets() ... algo assim)

Falow

----------


## mistymst

No Livro C Completo e Total tem um bom exemplo de listas duplamentes encadeadas. De uma olhada nele.

----------


## c0deks

pow vlw mesmo, eh bom saber que a gende dacomunidade linux sempre tem alguem com quem contar quando não souber mais oq fazer, vou tentar fazer algumas alterações aki, quando a função listar, oq eu gostaria mesmo de fazer era um menu de navegação entre os contatos, se eu fazer soh com a opção de avançar, vai dah certo, eu jah fiz assim, mais assim eu num quero naum...vo raxa a cuca aki pra tenta acha um jeito, outra coisa, onde eu acho o livro C Completo e Total, só comprando???

----------


## c0deks

a2gs, suas dicas foram muito uteis, corrigi os problemas que você mencionou, mas mesmo assim continua naum funcionando, eu num sei mais oq fazer...

----------


## jweyrich

1. Re-faça seu código, utilizando protótipos para as funções.
2. Não invoque a função main de qualquer parte do seu código, isto é errado. Crie outra função com a mesma finalidade, assim poderá chamá-la de qualquer outra função do escopo global do mesmo arquivo fonte.
3. Tente utilizar parâmetros nas funções para interação, e não variáveis globais.
4. Evite utilizar keywords conhecidas (null) para nomear variáveis, mesmo que seja com case diferente.
5. Utilize uma indentação de no mínimo 4 espacos (ou 1 tab) para cada escopo.
6. Evite utilizar funções sujeitas a overflows (strcat, sprintf, strcpy), sempre há outra função correspondente, com checagem de tamanho (strncat, snprintf, strncpy), ou então, crie você mesmo.
7. Invocar funções para execução de programas externos no sistema (system, exec**, etc) não é seguro.
8. Antes de finalizar a aplicação você deve liberar a memória alocada no HEAP (alocações feitas com malloc).
9. A função main deve ser declarada conforme a convenção padrão da linguagem (ela sempre deve retornar um valor int).

----------


## jweyrich

Se você está ingressando nesse mundo, tente fazer aplicações um pouco mais simples para entender o porque de não utilizar system(), sprintf, strcat, strcpy, etc.
Entenda como funcionam valores passados como parâmetros e os valores de retorno das funções.
Dominando isto, você fará essa aplicação parecer muito fácil, e quem olhar seu código, provavelmente vai entender sem perder horas.

Outra coisa que vi:


```
char value[255];
printf("%s", pergunta);
scanf("%s", value);
if(strlen(value) > tam)
```

 
este if não vai ajudar em nada, se alguém digitar 600 caracteres, o programa irá sobrescrever parte de si mesmo, pois a função scanf não limita o buffer de leitura (entrada) que será armazenado na variável, logo, posso digitar 600 caracteres, assim o programa tentará salvar o que eu digitei na variável onde só cabem 255, isto vai gerar um buffer-overflow, ou seja, seu programa está com uma falha de segurança crítica e fácil de explorar.

----------


## jweyrich

Você está programando para ambientes Microsoft ?
Se sim, "clear" não é um programa nativo dos sistemas Microsoft (Windows Family), logo, a chamada da função system irá gerar um warning do sistema operacional em runtime.

Se estiver programando para ambientes Linux/Unix, estude também como funcionam os debuggers. Aliás, uma boa ajuda para você descobrir o problema do seu programa é colocar alguns "printf"s para mostrar o conteudo das variaveis em todo o programa, assim saberá quais as funções que o programa chamou, o que ele executou ou não. Esta é a maneira fácil de achar um problema, caso você não saiba utilizar um debugger.

Você está utilizando alguma IDE (KDevelop, Eclipse, C++Builder, DevC++, etc) para programar ? Se sim, todas elas possuem um debugger interno, que economiza MUITO tempo para resolver problemas de lógica. Você pode parar o programa em tempo de execução, em uma determinada linha, assim poderá ver o valor das variáveis, sem precisar colocar "printf"s.

Qualquer coisa, posta aí denovo.

----------


## c0deks

Estou programando para Linux-Unix
Não esto usando nenguma IDE
Eu fiz algumas alterações, conforme as dicas que foram dadas, o problema eh que agora ao digitar o nome para cadastrar, eu obtenho um Segmentation Fail, jah tentei resolve-lo e mesmo assim nada, segue o codigo alterado:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* ## Declaração da estrutura ## */
struct registros{
char nome[50];
char tel[10];
char endereco[50];
struct registros *proximo; /* Ponteiro que corresponde ao proximo registro */
struct registros *anterior; /* Pomteiro que corresponde ao registro anterior */
} lista;
struct registros *ultimo; /* Ultimo registro */
struct registros *primeiro; /* Primeiro */
struct registros *vazio; /* Ponteiro NULL */


/* ## Prototipos das funções ## */
void menu(void);
void inserir(void);
void listar(void);
void mostrar(struct registros *este);
void inserirvalor(char *pergunta, char *var, int tam);



/* ## Função MAIN */
int main(){
menu(); /* Chama o menu */
}
/* --------------------*/


/* ## Função MENU */
void menu(void)
{
system("clear");
vazio = (struct registros *) malloc(sizeof(lista));
int opcao;
printf ("\nAgenderecoa Telefica v0.1 by c0dek\n----------\n\nDigite o numero correspondente a sua opção: \n\n");
printf ("\n1. Inserir");
printf ("\n2. Listar");
printf ("\n3. Sair deste programa");
printf ("\n----------\n");
printf("\nSua opção: ");
puts(" ");
do{ scanf("%d", &opcao);
switch(opcao){
case 1:
inserir();
break;
case 2:
listar();
break;
case 3:
exit(0);
default: printf("\nOpção invalida!");
} 
} while (1);
}
/* --------------------*/

/* ## Função INSERIR */
void inserir(void)
{
char opcao;
char value[255];
struct registros *este; /* Ponteiro este apontando para a estrutura registros */
este =(struct registros *) malloc(sizeof(lista)); /* Allocando memória */
if (este == 0){
printf("\nMemória insuficiente para alocação!");
return;
}
do{
inserirvalor("\nQual o nome do contato: ", "este->nome", 50); /* O Olho do furacão, passo os valores para a função inserirvalor */
inserirvalor("\nQual o tel do contato: ", "este->tel", 50);
inserirvalor("\nQual o endereco do contato: ", "este->endereco", 50);

if(primeiro!=0){
ultimo->proximo = este;
este->anterior = ultimo;
ultimo = este;
este->proximo = vazio;
} else {
primeiro = este;
ultimo = este;
este->proximo = vazio;
este->anterior = vazio;
}
printf("\nInserir mais um registro?[y/n]"); /* Pergunta se deseja inserir outro registro */
opcao=getchar(); 
fflush(stdin);
}while (opcao != 'n' && opcao != 'N');
printf("\nDesalocando memória...");
free(este);
main();
}
/* --------------------*/

/* ## Função LISTAR */
void listar(void)
{
int opcao;
struct registros *este;
este = primeiro;
do{
system("clear");
mostrar(este);
printf("\n1. Proximo Registro - 2. Registro Anterior - 3. Voltar para o Menu");
scanf("%d", &opcao);
fflush(stdin);
switch(opcao){
case 1:
if(este->proximo == vazio){
printf("\nUltima entrada...");
sleep(1);
return;
}
este = este->proximo; 
case 2:
if(este->anterior == vazio){
printf("\nPrimeira entrada...");
sleep(1);
return;
}
este = este->anterior;
case 3:
return;
}
} while (1); 
return;
}
/* --------------------*/

/* ## Função mostrar */
void mostrar(struct registros *este)
{
printf("\n\n\n-- Inicio do contato --");
printf("\nNome: %s", este->nome);
printf("\nTelecone: %s", este->tel);
printf("\nenderecoereço: %s", este->endereco);
printf("\n-- Fim do contato --\n\n\n");
return;
}
/* --------------------*/


/* ## Função inserirvalor */
void inserirvalor(char *pergunta, char *var, int tam)
{
struct registros *este; /*Ponteiro este apontando para a estrutura registros */
char value[200]; /* Variavel que guarda o valor temporário */
printf("%s", var); /* Imprime a variavel de destino soh pra garantir... */
printf("%s", pergunta); /* Imprime a pergunta */
scanf("%s", value); /* Escaneia seu valor */
strncpy(var, value, tam); /* Passa para a variavel de destino */
}

/* --------------------*/

----------


## jweyrich

Está errado utilizar aspas duplas no buffer de destino:


```
inserirvalor("\nQual o nome do contato: ", "este->nome", 50); 
inserirvalor("\nQual o tel do contato: ", "este->tel", 50);
inserirvalor("\nQual o endereco do contato: ", "este->endereco", 50);
```

 
Você precisa passar o buffer onde será armazenado o que você digitou, ficaria sem as aspas duplas:


```
inserirvalor("\nQual o nome do contato: ", este->nome, 50);
inserirvalor("\nQual o tel do contato: ", este->tel, 50);
inserirvalor("\nQual o endereco do contato: ", este->endereco, 50);
```

----------


## c0deks

ph0enix, vlw pela ajuda, mais se eu deixar sem aspas, a função inputs não recebe o valor da variavel corretamente ( eu acho ), pq se eu dexar sem aspas o printf que tem na função inputs que retorna a variavel de destino como garantia não retorna nada, ah num sei veio tah mto confuso eu acho que eu deveria deixar este projeto de lado por enquanto e partir pra outra, quando chegar a hora eu mexo nessa agenda denovo c num acha naum ph0enix?

----------


## a2gs

e vc acha q encontrarah problemas diferentes desses?

char msg[]="Welcome to the Jungle!";

(antes de programar em C, faça "portugues-estruturado" num editorzinho, sua vida seria muito mais alegre. E como o ph0enix disse, debug. Um simples printf("aqui 1") resolve 97,3% das vezis)

----------


## c0deks

Pronto, eu reescrevi todo o código usando alguns outros conceitos baseados em outros documentos que eu andei lendo, vo posta ai pra vcs darem umas dicas, como trocar uns comandos, usar outro metodo para fazer alguma coisa, esse tipo de coisas,...

#include <stdio.h>
#include <unistd.h>

/* Protóripos */
void menu(void);
void inserir(void);
void corrigevars(void);
void reginserido(void);
void listar(void);

/* Estrutura e ponteiros */
typedef struct regs{
char nome[50];
char tel[10];
struct regs *anterior, *proximo;
} lista;

lista *primeiro, *proximo, *anterior, *atual, *gravar;

/* MAIN */
int main(){ 
menu();
}

/* Funções */

void menu(void){
char opcao;
do{
system("clear");
printf("\nAgenda Telefônica v0.1 by c0dek\n--------------------\n");
printf("\nEscolha a sua opção no menu abaixo:");
printf(" \n(I) - Inserir novo registro");
printf(" \n(L) - Listar todos os registros");
printf(" \n(S) - Sair");
printf(" \n-----\nSua opção: [ ]\b\b");
opcao = getchar();
if(opcao == 'I' || opcao == 'i')
inserir();
if(opcao == 'L' || opcao == 'l')
listar();
if(opcao == 'S' || opcao == 's')
exit(0);
} while (1);
}


void inserir(void){
system("clear");
printf("\nAgenda Telefônica v0.1 by c0dek\nInserindo novo registro\n--------------------\n"); 
gravar = (struct regs *)malloc(sizeof(lista));
if (gravar == 0 ){
printf("\nMemória insuficiente para alocação...");
return;
}
printf("\nInsira o nome: ");
gets(gravar->nome);
gets(gravar->nome);
printf("\nInsira o tel: ");
gets(gravar->tel);
corrigevars();
return;
}

void corrigevars(void){
if (primeiro == NULL ){
primeiro = (struct regs *) malloc (sizeof(lista));
primeiro->proximo = gravar;
primeiro->anterior = gravar;
gravar->proximo = primeiro;
gravar->anterior = primeiro;
reginserido();
} else {
printf("\nJah contem entradas...");
anterior = primeiro->anterior;
proximo = primeiro;
anterior->proximo = gravar; 
gravar->anterior = anterior;
gravar->proximo = proximo;
proximo->anterior = gravar;
reginserido();
}
return;
}

void reginserido(){
char lixo;
system("clear");
printf("\nAgenda Telefônica v0.1 by c0dek\nNovo registro inserido...\n--------------------\n"); 
printf("\nSeu novo registro foi inserido com sucesso, veja abaixo:\n");
printf("\nNome: %s", gravar->nome);
printf("\nTelefone: %s", gravar->tel);
printf("\n------------------\nPressione qualquer tecla para continuar...\n");
lixo = getchar();
menu();
}

void listar(void){
char opcao;
if( primeiro == NULL ){
printf("\nNenhum registro encontrado...");
menu();
} else {
atual = primeiro->proximo;
do{
system("clear");
printf("\nAgenda Telefônica v0.1 by c0dek\nListando todos os registros\n--------------------\n");
printf("\nNome: %s", atual->nome);
printf("\nTelefone: %s\n", atual->tel);
printf("\n-------------------\nComandos: (P) para avançar | (A) para retroceder | (B) para voltar para o menu\nSua opção: [ ]\b\b");
opcao = getchar();
switch(opcao){
case 'p':{
if(atual->proximo == primeiro)
atual = primeiro->proximo;
else
atual = atual->proximo;
break;
}
case 'a':{
if(atual->anterior == primeiro)
atual = primeiro->proximo;
else
atual = atual->anterior;
break;
}
case 'm':{
menu();
break;
}
}
} while (1);
}
menu();
}

----------

