[DUVIDA] Parametro por referencia

9 respostas
R

Quero alterar um dos atributos de uma struct utilizando ponteiros. Mas ao utilizar o código como está abaixo sou “obrigado” a retornar a struct com ponteiro (Aluno*). Consequentemente todos os outros locais do sistema onde utilizo essa função também precisam ter a variavel com o ponteiro.

Código:

Aluno* criarAluno()
{
	Aluno *novoAluno;
	lerNome(novoAluno);
	return novoAluno;
}

void lerNome(Aluno *aluno)
{
	printf("Nome: ");
	fflush(stdin);
	gets(aluno.nome);
}

Tem como eu receber um parametro por referencia e retornar a struct sem o ponteiro?

9 Respostas

E

Isso é C ou C++? Em C++ não se abusa de ponteiros. Usa-se referências (&) mesmo, mas quero saber o que você quer fazer.

R

C. É um programa tipo CRUD (para faculdade).

Como preciso fazer inclusão e alteração. Para não repetir a leitura da informação centralizo isso em uma função.

Exemplo:

void novoAluno()
{
   Aluno *novoAluno;
   lerNome(novoAluno);
}

ou entao:

void alterarAluno()
{
    //tenho um menu que o usuario escolhe qual atributo quer alterar
    //se escolhe alterar o nome
    lerNome(novoAluno);
}

É uma funcao que serve apenas para fazer a leitura de um dos atributos da estrutura.
Pensei que ponteiros fosse a melhor maneira para o C.

Outra solução seria fazer a leitura sem utilizar ponteiros. De uma maneira mais parecida com o Java :smiley:

Aluno lerNome(Aluno aluno)
{
  printf("Nome: ");  
  fflush(stdin);  
  gets(aluno.nome);
  return aluno;
}

Mas nessa segunda opção precisaria atribuir o retorno. Exemplo: aluno = lerNome(aluno);
Por isso vim até o fórum para saber se tinha uma maneira melhor de fazer isso.

Obs: Nao sei se poderei utilizar ponteiro. Pois, é um programa que deve armazenar as informacoes em um arquivo binario. E tive problemas para ler do arquivo utilizando estrutura com ponteiro.

Exemplo:

  1. Aluno *aluno; fread( &aluno, sizeof(Aluno), 1, arquivo );

O aluno é carregado com atributos estranhos.

  1. Aluno aluno; fread( &aluno, sizeof(Aluno), 1, arquivo );

Sem o ponteiro a estrutura é carregada corretamente. Nao posso passar um parametro por referencia para a funcao fread?

E

Como o ViniGodoy mencionou anteriormente, fazer isto aqui:

Aluno *aluno;  
 fread( &aluno, sizeof(Aluno), 1, arquivo );

é só um pouco pior que um NullPointerException. É que um ponteiro (não referência, que é uma outra coisa) em C não é inicializado, ou melhor, é inicializado com lixo. E se você pega o endereço desse endereço (que é o que você fez) e copia algum valor nele, vai ter algo mais nojento ainda.

R

Ponteiros me confundem bastante. Porque aprendi a programar com Java que não tem ponteiros.

Resumindo: Sempre que possível evitar ponteiros?

E

Em C você não pode evitar os ponteiros.
Mas você sempre deve ser capaz de olhar um ponteiro em um programa e sempre saber dizer: “que valor contém esse ponteiro”?

No seu caso:

Aluno *novoAluno; /* neste ponto o valor de novoAluno é indeterminado, ou melhor, é lixo */
lerNome (novoAluno); /* aqui o método lerNome vai receber lixo e portanto vai acabar fazendo besteira */
Aluno novoAluno; /* você agora tem um objeto de verdade, não só um ponteiro */
lerNome (&novoAluno);  /* aqui você passou o endereço do objeto de verdade */
E

Normalmente em C você escreveria:

void lerNome(Aluno* aluno)  
{  
    printf("Nome: ");    
    fflush(stdin);    
    gets(aluno->nome);  
}

(Excetuando o fato que não sei a definição do campo “nome” de sua classe Aluno. )

R

Obrigado. Era esse “truque” que estava esperando como resposta.

Então, se o parametro de uma função exigir uma variável com ponteiro.

Posso passar (sem o compilador reclamar):

Aluno *aluno; funcao(aluno);

ou

Aluno aluno; funcao(&aluno);

Eu havia aprendido/entendido que só poderia passar referencia de ponteiro se fosse criada uma variavel com o ponteiro (*). Mas isso faz sentido. Agora entendi porque no scanf,fread, fwrite,… é exigido o & junto com a variavel.

Só pra finalizar nas dúvidas sobre ponteiros:

Então quando eu crio a variavel: Aluno aluno; fica alocado um espaço na memória para a variavel, como voce falou: o objeto foi criado. Se eu passar para a função o parametro &aluno. A função vai alterar os atributos desse aluno direto no endereço da memória. Esse endereço na memória é o ponteiro para o objeto criado.

Agora se eu criar uma variável Aluno *aluno; ela é apenas um ponteiro para algum endereço de memória. Como nenhum endereço foi atribuido ela não está apontando para nada (inclusive da esse erro se tentar olhar o valor do endereço da memória desse ponteiro: Must take address of a memory location).

No entanto, se eu tiver as funções como escrevi no inicio desse post ambas funcionam.

Por isso, fiz o seguinte teste:

Aluno *aluno;    
fread( aluno, sizeof(Aluno), 1, arquivo );

E funcionou a leitura. (então tenho como usar daquela maneira com ponteiro a função fread, mas a maneira como você citou parece mais elegante).

Então ambas as soluções produzem o mesmo resultado?

Quanto ao lixo da variável criada com o ponteiro. Criei duas estruturas(com uma variavel do tipo inteiro dentro) uma com o ponteiro outra sem.

Na variavel sem ponteiro valor = -29147
Na variavel com ponteiro valor = 767

Não seriam ambos os valores lixo? (considerando que no Java o valor inteiro tem por padrão 0. O valor inteiro padrão no C é -29147? )

E

Amigo, o compilador C não lhe ajuda nem um pouco. Ele aceita quase tudo sem reclamar. Quando você faz isso:

/* C */
 Aluno *aluno;  
 funcao(aluno);

ele não sai gritando, como no Java, que a variável “aluno” não está inicializada.

// Java
Aluno aluno;
objeto.metodo (aluno);

Na verdade, você teve sorte (ou azar) de o seu programa não ter dado um erro de execução.

R

Ok. Obrigado pela explicação.

Por não ter experiência com o uso de ponteiros tomei como base para as conclusões apenas os testes que realizei. Como eles tiveram o mesmo resultado, achei que ambas situações produzissem o mesmo resultado.

Agradeço novamente a sua explicação e a sua disponibilidade para tirar minhas dúvidas.

Criado 23 de novembro de 2010
Ultima resposta 23 de nov. de 2010
Respostas 9
Participantes 2