Let’s see...
Keep in mind the following:
A pointer is a variable that stores an address instead of a known type value. If accessed, the saved address may contain another address or a known type value;
Every variable has its own address. Thus, a "traditional" variable has its own address and a pointer variable as well. Let’s work with equality - always!
The name of a variable is nothing more than a mnemonic to her address. That is, a synonym.
Looking closely at the problem
Consider the following generic representation code:
#include <stdio.h>
#include <stdlib.h>
typedef struct meu { int valor; struct minha *prox; } tipo;
void incluir(tipo *lista){
tipo *temp = (tipo *) malloc(...);
temp->valor = 5;
temp->prox = lista;
lista = temp;
}
void imprimir(tipo *lista){
while(temp != NULL){
printf("%d ", lista->valor);
temp = temp->prox;
}
}
int main(){
tipo *lista = NULL;
incluir(lista);
imprimir(lista);
return(0);
}
Now let us narrate the events that follow:
- creates a pointer called
lista
of a given tipo
;
- give the address pointed by the pointer
lista
for the inclusion function;
- in the inclusion function, a temporary pointer is created for a new data entry;
- stands in the
prox
from the new entry the address pointed by the pointer lista
;
- pointer
lista
point to the address of the new entry;
- call the print function to print the contents of the list;
- fails miserably and inquires about the craft of Dennis Ritchie’s mother;
In order to save the honor of the poor lady mother of this computer genius, we must mitigate the problem. Let’s go!
Case analysis
Consider that the pointer address lista
be it 0x02
. Pay attention: it is his address and not his content; that he points out! In case, lista
points to NULL
. then we have something like 0x02 -> NULL
in memory.
Consider the memory table to assist in the explanation:
+===================================+
| Tabela de Memória |
+----------+------------------------+
| Endereço | Valor |
+===================================+
| 0x01 | 5 |
+----------+------------------------+
| 0x02 | NULL |
+----------+------------------------+
| 0x03 | 0x30 |
+----------+------------------------+
| 0x04 | livro k&r download pdf |
+----------+------------------------+
| 0x05 | NULL |
+----------+------------------------+
| 0x06 | ab..$5%ab asd/ |
+----------+------------------------+
+ ... +
As we passed lista
as an argument for incluir()
, we passed the address he points to. We passed NULL
. Remember that a variable always passes its value in any normal instance and not its address.
Within the function incluir()
, we hope that lista
is at the address 0x02
with the value NULL
. OK...
THERE! Trickster of the rascal!
This is completely wrong! What we have in lista
(in incluir()
) is the value pointing the pointer and not the address of the pointer. The variable lista
(in incluir()
) is actually another variable at another address (say 0x05
). Only the amount it points to lista
in incluir()
is the same as lista
in main()
.
The direct consequence of this is that the reference is lost. That explains why we failed to print.
Solution
To deal with this problem, we need the value pointed out by lista
and the address of lista
in itself. This is easily done by passing &lista
for the functions instead of lista
. This way, our memory would be like this:
+===================================+
| Tabela de Memória |
+----------+------------------------+
| Endereço | Valor |
+===================================+
| 0x01 | 5 |
+----------+------------------------+
| 0x02 | NULL |
+----------+------------------------+
| 0x03 | 0x30 |
+----------+------------------------+
| 0x04 | livro k&r download pdf |
+----------+------------------------+
| 0x05 | 0x02 |
+----------+------------------------+
| 0x06 | ab..$5%ab asd/ |
+----------+------------------------+
+ ... +
Our jobs would look like this:
void incluir(tipo **lista){ ...
void imprimir(tipo **lista){ ...
Function calls would be as follows:
incluir( &lista );
imprimir( &lista );
Concluding: list within incluir()
will point to the address of lista
inside main()
which in turn will point to the known type. Thus, you can also track lista
and not only the content to which it points.
Fixing the program
Ideally, try to tidy it up yourself. If you can’t, take a look at this functional version of it.
The code below contains some visual modifications I made to better understand your program. This includes how the information is displayed. Change it as you wish.
Libraries:
#include <stdio.h>
#include <stdlib.h>
Structures:
typedef struct cadastro {
char nome[30];
char matricula[30];
char Disciplinas[30];
char notas[30];
struct cadastro *proxno;
} alunos;
Job statements:
int inserir_aluno_inicio(alunos **lista);
int menu(void);
void opcoes(alunos **lista, int opc);
void imprimir(alunos **lista);
alunos *remover_aluno(alunos **lista);
alunos *liberar();
alunos *inicializar();
Function main()
:
int main() {
int opcao;
alunos *lista = (alunos *)malloc(sizeof(alunos));
lista = inicializar();
do {
opcao = menu();
opcoes(&lista, opcao);
} while (opcao < 4);
return 0;
}
Function inicializar()
:
alunos *inicializar() { return NULL; }
Function menu()
:
int menu() {
int ale;
puts("\n M E N U E S C O L A R V I N G A D O R E S \n");
puts(" ===============================================\n");
puts(" = [ 0 ] INSERIR ALUNO =\n");
puts(" = [ 1 ] REMOVER ALUNO =\n");
puts(" = [ 2 ] IMPRIMIR INFORMACOES DO ALUNO =\n");
puts(" = [ 3 ] LIMPAR LISTA DE ALUNOS =\n");
puts(" = [ 4 ] SAIR DA LISTA =\n");
puts(" ===============================================\n");
printf(" COMANDO > ");
scanf("%d", &ale);
return ale;
}
Function inserir_aluno_inicio()
:
int inserir_aluno_inicio(alunos **lista) {
alunos *novo = (alunos *) malloc( sizeof( alunos ) );
if (novo == NULL)
{
puts(" Sem memória!");
return 1;
}
printf("\n Digite o nome do aluno ou da aluna: ");
scanf(" %s", novo->nome);
printf(" Digite a matricula do aluno ou aluna [5 numeros ou letras]: ");
scanf(" %s", novo->matricula);
printf(" Digite a disciplina do aluno ou aluna: ");
scanf(" %s", novo->Disciplinas);
printf(" Digite a nota da aluna ou do aluno: ");
scanf(" %s", novo->notas);
puts("");
novo->proxno = *lista;
*lista = novo;
return 0;
}
Function opcoes()
:
void opcoes(alunos **lista, int opc) {
switch (opc) {
case 0:
inserir_aluno_inicio(lista);
break;
case 1:
break;
case 2:
imprimir(lista);
break;
case 3:
break;
case 4:
puts("\n Ate a proxima!\n");
break;
default:
puts(" Nao existe essa opcao tente novamente!");
}
}
Function imprimir()
:
void imprimir(alunos **lista) {
alunos *aux = *lista;
while (aux != NULL){
printf("\n\tO nome da aluna(o): %s\n", aux->nome);
printf("\tA matricula do aluno(a) e: %s\n", aux->matricula);
printf("\tA disciplina da aluna(o) e: %s\n",aux->Disciplinas);
printf("\tA nota do aluno (a): %s\n", aux->notas);
aux = aux->proxno;
}
}
The code is also found in Github. If you find it easier, look at it in one file there.
If you still don’t understand, find another source. I recommend this answer from Lucas Virgili.
Thank you. You killed the answer.
– Guilherasmin silva
It worked, see! I will post the code fixed or leave the above error and your resolution comment?
– Guilherasmin silva
The platform works as follows: you ask a question and one or more people answer. The best answer among those who solve the problem, you mark as correct and give a positive: the actions serve to thank those who helped you. A correct answer also serves to help others with similar problems. In cases where no one answers or solves the problem, if you find the solution you can write an answer and mark your own answer as correct. The question is only edited to be improved, never to answer. If my answer helped, you can mark as correct. :)
– José