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.