Problem removing the first node from the double-chained list

Asked

Viewed 406 times

0

Good night,

I am trying to solve a question that asked to remove students whose CR is less than 5. My biggest problem is to remove the first node (first student) from a doubly chained list when there is only one node. I just gave free on the node that contains the CR with value less than 5, and made the head of the list point to NULL, which would be the address of the successor node to which will be deleted, nothing else. The result is that when printing the list, the node remained intact, but with random values after the free() call. Follow print and source code for better analysis.

I count on everyone’s help!

inserir a descrição da imagem aqui

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

typedef struct{
    long matricula;
    char nome[51];
    float CR;

}DADOS_ALUNO;


typedef struct {

    DADOS_ALUNO dados; //Dados do aluno
    void* pProximoAluno; //Ponteiro para o próximo aluno
    void* pAlunoAnterior; //Ponteiro para aluno anterior

}ELEMENTO;


ELEMENTO* criaLista(){
    return NULL;
}


ELEMENTO* cadastraAlunos(ELEMENTO* lista, DADOS_ALUNO novo_aluno){

    ELEMENTO* novo = (ELEMENTO*)malloc(sizeof(ELEMENTO));

    //Inicialmente os ponteiros ini e fim apontam para NULL
    ELEMENTO* ini = lista;
    ELEMENTO* fim = lista;

    if(novo == NULL){
        printf("Memoria insuficiente\n");
        exit(1);

    } else if(lista == NULL){ //Se a lista estiver vazia, insere o primeiro nó

        novo->dados = novo_aluno;
        novo->pProximoAluno = fim;
        novo->pAlunoAnterior = ini;

        fim = ini = novo;

        return ini;

    } else { //Caso a lista tenha pelo menos um nó

        novo->dados = novo_aluno;
        novo->pProximoAluno = fim;
        novo->pAlunoAnterior = NULL;
        fim->pAlunoAnterior = novo;
        ini = novo;

        return ini;

    }

}

//a)Retornar a quantidade de alunos com coeficiente de rendimento maior ou igual a 7.
int numAlunosCrAlto(ELEMENTO* pLista){

    int quantidade = 0;

    ELEMENTO* p = pLista; //Ponteiro que aponta para o início da lista para percorrê-lo


    if(pLista == NULL){
        printf("Lista vazia\n");
        exit(1);

    } else {

        while(p != NULL){

            if(p->dados.CR >= 7){
                quantidade++;
            }

            p = p->pProximoAluno;
        }

        return quantidade;  
    }   
}

void imprimeAluno(ELEMENTO* lista){

    ELEMENTO* p = lista;

    if(lista == NULL){
        printf("Lista vazia\n");
        exit(1);

    } else {

    for(; p != NULL; p = p->pProximoAluno){
        printf("Matricula: %ld - Nome: %s - CR: %.2f\n", p->dados.matricula, p->dados.nome, p->dados.CR);
    }

    printf("\n\n");

    }
}


//b)Excluir da lista todos os alunos com coeficiente de rendimento menor que 5.
void excluirAlunosCrBaixo(ELEMENTO* pLista){

    ELEMENTO* p = pLista; //Ponteiro que aponta para o primeiro nó da lista para percorrê-la
    ELEMENTO* ant = NULL; //Ponteiro para guardar o nó antecessor ao que será excluído

    if(pLista == NULL){
        printf("Lista vazia\n");
        exit(1);

    } else {

        while(p != NULL){

            if(p->dados.CR < 5 && p->pAlunoAnterior == NULL){ //Se for primeiro da lista

            if(p->pProximoAluno == NULL){ //Se não houver mais elementos na lista, a mesma fica vazia

                ant = p; /*Usando o ponteiro ant para apontar ao p e chamar o free() sobre ele para 
                         não perder a referência de p, pois este será utilizado para percorrer a lista*/

                pLista = ant->pProximoAluno; //A cabeça da lista aponta para NULL, indicando que está vazia
                free(ant); 

            } else { //Caso ainda exista mais elementos na lista, o segundo elemento passa a ser o primeiro

                ant = p;
                p = p->pProximoAluno;
                free(ant);
                p->pAlunoAnterior = NULL;
            }


            } else if(p->dados.CR < 5 && p->pAlunoAnterior != NULL && p->pProximoAluno != NULL){ //Se o elemento estiver no meio da lista

                ELEMENTO* aux; //Ponteiro que irá apontar para o nó antecessor ao nó que será excluído
                ant = p;
                aux = ant->pAlunoAnterior;  
                p = p->pProximoAluno;
                p->pAlunoAnterior = aux;
                aux->pProximoAluno = p;
                free(ant);

            } else if(p->dados.CR < 5 && p->pProximoAluno == NULL){ //Se for o último da lista


                ant = p->pAlunoAnterior;
                ant->pProximoAluno = NULL;
                free(p);

            }

            p = p->pProximoAluno;       
        }
    }   
}


int main(int argc, char *argv[]) {


    ELEMENTO* Lista = (ELEMENTO*)malloc(sizeof(ELEMENTO));

    if(Lista == NULL){
        printf("Memoria insuficiente\n");
        exit(1);

    } else {

        Lista = criaLista();

//      DADOS_ALUNO a1 = {201311, "Teste 01", 8.5};
//      DADOS_ALUNO a2 = {201412, "Teste 02", 6.3};
//      DADOS_ALUNO a3 = {201211, "Teste 03", 6.2};
        DADOS_ALUNO a4 = {201511, "Teste 04", 1.0};

//      Lista = cadastraAlunos(Lista, a1);
//      Lista = cadastraAlunos(Lista, a2);
//      Lista = cadastraAlunos(Lista, a3);
        Lista = cadastraAlunos(Lista, a4);

        imprimeAluno(Lista);

        excluirAlunosCrBaixo(Lista);

        imprimeAluno(Lista);

        printf("Total de alunos com CR maior ou igual a 7: %d", numAlunosCrAlto(Lista));

    }

    return 0;
}

1 answer

0


On line 132 make a call from your print list function, you will see that your code is actually deleting, however, it is not updating the pointer to NULL (this is very recurrent in list implementations on C).

What happens is that although you are sending your parameters by memory address, in C, you cannot change the memory address within the scope of the function (in other words, it would be as if the address of the variable were passed by value). To illustrate better follow an example:

#include <stdio.h>

void change(int *v ,int *b){
    v=b;
    printf("Dentro da fução\n");
    printf("%d\n", *v);
}

int main(){
    int *v1;

    int a=10;
    int b=5;
    *v1=a;

    change(v1,&b);
    printf("Fora da função\n");
    printf("%d\n", *v1);
 return 0;
}

inserir a descrição da imagem aqui

Possible solutions you could be implementing are lists with headers (structures that hold the position of the beginning of your list and the end), so you could send pointers to their functions solving the problem or change their functions to the return type ELEMENT*

  • I already solved the problem. It would really be better to declare one more struct containing a pointer that stores the first and the last, and it worked. In exercise I asked for the functions to be void even. Anyway, thanks for the suggestion.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.