paulo1205
(usa Ubuntu)
Enviado em 16/04/2016 - 22:42h
Sr. F escreveu:
Mas deixa eu te perguntar, qual a diferença entra as duas funções abaixo?
struct no *inserir (struct no *lista, int n) {
struct no *novo = (struct no*) malloc(sizeof(struct no));
novo->chave = n;
novo->prox = lista;
return novo;
}
struct no inserir (struct no *lista, int n) {
struct no *novo = (struct no*) malloc(sizeof(struct no));
novo->chave = n;
novo->prox = lista;
return novo;
}
Desculpe por não ter terminado os blocos “A ser escrito”, mas existe um mundo real fora da Internet, que demanda um bocado de atenção também, e eu não quero sair escrevendo coisas on-line de qualquer maneira, e tentar caprichar na explicação toma muito tempo.
Especificamente sobre a pergunta de agora, parece-me que você cometeu um erro no segundo exemplo, pois você declarou a função retornando um dado do tipo “struct no”, mas mandou retornar um valor cujo tipo é “ponteiro para struct no”. Vou supor, então, que o comando
return do segundo exemplo seja “
return *no; ”, de modo a compatibilizar os tipos, e responder de acordo.
Ao contrário de algumas outras linguagens, C não possui referências. Sempre que você passa parâmetros para uma função ou recebe um valor de retorno de função, você está na verdade recebendo cópias de valores. Veja, por exemplo, o código abaixo.
int f(int n){
return n*n;
}
int main(void){
int a, b;
a=5;
b=f(a);
}
No código acima, quando a função
f () é invocada, ela recebe uma cópia do valor do parâmetro
a , e esse valor copiado é armazenado no argumento
n . Semelhantemente, o valor calculado
n*n dentro da função não é diretamente guardado na variável
b que espera recebê-lo(*), mas sim copiado para ela após a função terminar.
Sabendo disso, olhe para as duas funções. A primeira função aloca dinamicamente memória para um novo dado do tipo “struct no”, coloca nele os valores passados como parâmetros, e retorna
uma cópia do endereço alocado para o novo dado (ou seja: uma cópia do ponteiro para o novo dado). Como você retorna o valor do endereço alocado, quem receber o valor retornado terá, depois, condições de acesso ao dado alocado (e ao restante da lista original, que passou a ser apontada pelo campo
prox do novo nó).
A segunda função (com o reparo que eu mencionei acima) também aloca memória dinamicamente para dado do tipo “struct no” e preenche tais dados com valores recebidos pela função como parâmetros. Entretanto, ela retorna
uma cópia de dado , não do seu endereço -- quem quer que receba o valor retornado vai copiar os campos internos da estrutura em outra região de memória. O ponteiro que faz referência ao novo dado dinamicamente alocado deixa de existir quando a função acaba, de modo que não será possível desalocá-lo (para desalocar memória dinamicamente alocada, o valor do endereço tem de ser o mesmo daquele recebido na hora da alocação).
---------
(*) Quando falo sobre não haver atribuição direta, refiro-me ao comportamento esperado da linguagem e de uma possível tradução direta para código executável. É possível que compiladores que realizam otimização de código até consigam minimizar o número de cópias. Se o fizerem, no entanto, devem fazê-lo de um modo que não interfira na semântica esperada pelo programador em C.