Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

mahbitt

ponteiro para ponteiro

Recommended Posts

ola pessoal! bem, estou fazendo um exercicio simples da faculdade onde tenho que cadastrar um cliente de um banco, so que nao estou conseguindo acessar corretamente o ponteiro que declarei na main.

entao, eu passo o ponteiro da main para a funcao menu, que passa para a funcao cadastro. estou meia perdida na passagem desses ponteiros.

 

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

typedef struct t_cliente{
    char *nome;
    int conta;
    float saldo;
}cliente;
void cadastro(cliente **p, int i);
void menu(cliente *p, int *i);


int main()
{
    cliente *p;
    int i;
    printf("\t\t\t*** Sistema de Conta Bancaria ***");
    p=NULL;
    i=0;
    menu(p, &i);
    printf("\nmain %s",(p+i)->nome);
    return 0;
}
void menu(cliente *p,int *i)
{
    int op;
    do{
        printf("\n\n\tMenu\n\nEscolha uma das opcoes:\n1-Cadastro\n2-Deposito\n3-Retirada\n4-Sair\n\nOpcao: ");
        scanf("%i%*c",&op);
        if (op==1)
        {
            cadastro(&p, *i);
            printf("\nmenu %s",(p+*i)->nome);
        }
    }while(op!=4);
}
void cadastro(cliente **p, int i)
{
    char aux_nome[20];
    printf("\n\t Cadastro de Cliente ");
    if ((*p=(cliente*)realloc(*p, (i+1)*sizeof(cliente)))==NULL)
    {
        printf("Erro");
        return 0;
    }

    printf("\n\nDigite o nome do cliente: ");
    fgets(aux_nome, 20, stdin);
    (*p+i)->nome=(char*)realloc((*p+i)->nome,(strlen(aux_nome))*sizeof(char));
    strcpy((*p+i)->nome,aux_nome);
    printf("\ncadastro %s",(*p+i)->nome);
}

 

no comeco alocava, cadastrava e exibia o cliente no cadastro. tentei dai acessar o cliente cadastrado no menu, pois ja tinha a duvida se estava correto e vi que estava fazendo errado. dai parei o projeto e resolvi estudar sobre o comportamento desses ponteiros. percebi que como estava na funcao cadastro apontando para um ponteiro em menu teria que usar um ponteiro que apontava um ponteiro, e ai deu certo alocar em cadastro e exibir no menu. porem tentei fazer o mesmo na main e naum deu certo, ainda nao to conceguindo utilizar corretamente esses ponteiros. entao para dar certo teria que usar um ***p?? estou confusa quanto a isso porque os professores nao falaram nada quanto a isso ainda...

gente o que eu estou fazendo de errado?

qualquer coisa mesmo que nao tiver haver com o erro, mas acham importante eu saber, dicas e sugestoes me avisem por favor!

obrigado

Compartilhar este post


Link para o post
Compartilhar em outros sites

ola pessoal

depois de muito tempo e acredito que conseguindo entender ponteiros fiz dessa forma e parece que esta certo

 

 

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

typedef struct t_cliente{
    char *nome;
    int conta;
    float saldo;
}cliente;
void cadastro(cliente **p, int i);
void menu(cliente **p, int *i);


int main()
{
    cliente *p;
    int i;
    printf("\t\t\t*** Sistema de Conta Bancaria ***");
    p=NULL;
    i=0;
    menu(&p, &i);
    printf("\nmain %s",(p+i)->nome);
    return 0;
}
void menu(cliente **p,int *i)
{
    int op;
    do{
        printf("\n\n\tMenu\n\nEscolha uma das opcoes:\n1-Cadastro\n2-Deposito\n3-Retirada\n4-Sair\n\nOpcao: ");
        scanf("%i%*c",&op);
        if (op==1)
        {
            cadastro(p, *i);
            printf("\nmenu %s",(*p+*i)->nome);
        }
    }while(op!=4);
}
void cadastro(cliente **p, int i)
{
    char aux_nome[20];
    printf("\n\t Cadastro de Cliente ");
    if ((*p=(cliente*)realloc(*p, (i+1)*sizeof(cliente)))==NULL)
    {
        printf("Erro");
        return 0;
    }

    printf("\n\nDigite o nome do cliente: ");
    fgets(aux_nome, 20, stdin);
    (*p+i)->nome=(char*)realloc((*p+i)->nome,(strlen(aux_nome))*sizeof(char));
    strcpy((*p+i)->nome,aux_nome);
    printf("\ncadastro %s",(*p+i)->nome);
}

 

sei que ninguem me respondeu mas caso eu ainda esteja errando e alguem quiser me avisar...

tbm fica ai pra quem estiver com a mesma duvida que eu!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Justamente p/ evitar essas complicações de argumentos eu deixo os ponteiros como globais ou evito enfiar muita coisa nas funções. Tipo, a minha função menu só exibe as opções, e todo o trabalho é feito no main chamando as funções e o loop infinito, sem passar o ponteiro como argumento.

Compartilhar este post


Link para o post
Compartilhar em outros sites

é entao antes so usava esses ponteiros como global

mas os professores insistem em usar assim...

 

Tipo, a minha função menu só exibe as opções, e todo o trabalho é feito no main chamando as funções e o loop infinito, sem passar o ponteiro como argumento.

 

nao entendi. http://forum.imasters.com.br/public/style_emoticons/default/ermm.gif

Compartilhar este post


Link para o post
Compartilhar em outros sites

Com o tempo você aprende a ignorar o que os professores falam. Normalmente eles colocam travas porque senão vira um zonão, todo mundo programando do jeito que quer e eles tem que se virar pra corrigir (novamente, preguiça rlz)

 

Eu faria assim o programa:


#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#define MAX_NOME 20

#define CADASTRO 1
#define DEPOSITO 2
#define RETIRADA 3
#define SAIR 4

typedef struct t_cliente{
   char *nome;
   unsigned int conta;
   float saldo;
   struct t_cliente *proximo;
}cliente;

int tamanho_lista = 0;

int main()
{
   cliente *p = NULL;
   int opcao = 0;

   do {
       menu();
       scanf("%d", &opcao);
       if (opcao == CADASTRO) {
          cadastro(p);
       } else if (opcao == DEPOSITO) {

       } else if (opcao == RETIRADA) {

       } else if (opcao != SAIR) {
           puts("Opção inválida.");
       }
   } while (opcao != SAIR);

   free(p);
   p = NULL;

   return 0;
}

void menu()
{
   puts("\t\t\t*** Sistema de Conta Bancaria ***");
   puts("Escolha uma das opcoes:");
   puts("1-Cadastro");
   puts("2-Deposito");
   puts("3-Retirada");
   puts("4-Sair");
   printf("\n\nOpcao: ");
}

void cadastro(cliente *p)
{

   char nome_cliente[MAX_NOME] = "";
   unsigned int conta_cliente = 0;

   puts("\n\t Cadastro de Cliente ");

   printf("\n\nDigite o nome do cliente: ");
   fgets(nome_cliente, MAX_NOME, stdin);

   printf("\n\nDigite o número da conta do cliente: ");
   scanf("%ud", &conta_cliente);

   if (!tamanho_lista) {

      p = (cliente *)malloc(sizeof(cliente));

      if (p == NULL) {

          printf("%m\n");
          exit(1);

      } else {
          p->saldo = 0F;
          p->conta = conta_cliente;
          p->proximo = NULL;
          strcpy(p->nome, nome_cliente);
          tamanho_lista++;
      }
   } else {

      cliente *aux = (cliente*)malloc(sizeof(cliente));
      if (aux == NULL) {
          printf("%m\n");
          free(p);
          p = NULL;
          exit(1);
      } else {

          aux->saldo = 0F;
          aux->conta = conta_cliente;
          aux->proximo = NULL;
          strcpy(aux->nome, nome_cliente);

          p[tamanho_lista-1]->proximo = aux;
          tamanho_lista++;
      }
   }
}

 

 

O %m evita que você fique criando mensagens de erros p/ tudo quando é coisa. Tem um monte de função que define uma variável externa errno e a mensagem de erro pode ser impressa baseada nesse valor usando o printf ou perror.

Só veja a necessidade de usar realloc num negócio desse, porque a princípio, você pode ter posições de memórias separadas referenciando outras posições, mesmo que internamente isso vire uma bagunça. O que o realloc faz é alocar um espaço maior p/ o que está sendo passado como argumento, copiando tudo o que existe nele e 'removendo' a área anterior. Como você só está criando um registro só não sei se vale a pena fazer isso (pense em ter 2000 registros). Por outro lado não faço a menor idéia se a impressão da lista de cadastrados fica comprometida (sei lá...talvez algum endereço se perca porque não está numa área de memória contígua reservada...coisas assim).

Compartilhar este post


Link para o post
Compartilhar em outros sites

obrigado por ter me respondido isis! http://forum.imasters.com.br/public/style_emoticons/default/clap.gif

quando eu fiz esse exercicio na aula eu deixei o menu na main, dai la jah escolhia a opcao e mandava para a funcao de cadastro o ponteiro sem ter que usar ponteiro pra ponteiro. mas quaria fazer as funcoes separadas e senti a necessidade de aprender melhor sobre isso. nossa gostei muito do jeito que voce resolveu o exercicio parece que foi de uma forma muito mais facil.

sempre quando eu recebia a opcao do usuario usava %i, nao sabia que podia usar %d e tambem naum gostava de usar char! sempre que digitava uma letra por exemplo ele entrava em loop infinito... muito bom saber que com %d isso nao acontece! nao conhecia tambem o %m, mas quando eu testei ele aqui, apareceu o m e por causa do exit ele finalizou o programa! é isso mesmo que acontece?

no uso do malloc tambem pensei como seria na hora de imprimir, porque sempre que imprimia com o realloc, adicionava o contador correspendente do registro ao ponteiro. nao sei se eu entendi direito, o *proximo na estrutura vai guardar o endereço do proximo registro cadastrado neh? sera que o primeiro nao vai perder o endereço dele? nao sei se estou pensando certo

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não é que com %d não acontece. Uma hora ou outra vai ficar um \n preso na entrada (e é por isso que é pulado o passo de digitar alguma coisa). O que tem de diferente no %i e no %d:

 

d Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of strtol() with the value 10

for the base argument. In the absence of a size modifier, the application shall ensure that the corresponding argument is a pointer to int.

 

i Matches an optionally signed integer, whose format is the same as expected for the subject sequence of strtol() with 0 for the base argu-

ment. In the absence of a size modifier, the application shall ensure that the corresponding argument is a pointer to int.

 

 

 

O %m é uma extensão da libc. Veja se no Windows dá p/ usar perror ou strerror. Isso ajuda muito quando se trabalha com arquivos, processos, threads, pipes...Porque o próprio sistema já tem uma mensagem preparada e você não precisa ficar adivinhando o que deu errado.

Compartilhar este post


Link para o post
Compartilhar em outros sites

oi isis

o %d eu pensei que dava certo se por exemplo, declarasse uma variavel inteira e recebesse com %d, caso o usuario digitasse um alfanumerico, pensei que nao dava problema! mas do mesmo jeito ele entra em loop...

 

o perror eu vi como usa, mas o strerror retorna um ponteiro nao eh? dai nao entendi como ele da a menssagem de erro

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ele retorna um char *. É uma string.

A mensagem é associada ao valor da variável errno.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.