Element removal at the beginning of C chained list

Asked

Viewed 1,153 times

0

In this C program, I’m trying to create a function that removes the first element of a chained dynamic list...

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

struct no {
    int dado;
    struct no *prox;
};

The functions of the simply chained list I implemented are as follows::

Imprime Lista

void imprimir(struct no *prim){
    struct no * atual;
    atual = prim;
    system("clear");
    printf("\nLista: ");

    while(atual != (struct no*)NULL)
    {
        printf("%d-> ",atual -> dado);
        atual = atual -> prox;
    }
}

Insert widget at start.

struct no * insere_inicio(struct no *prim){
    int num;
    struct no *novo;

    printf("\nInsira o elemento no inicio da lista: ");
    scanf("%d", &num);

    novo = (struct no*) malloc(sizeof(struct no*));
    novo -> dado = num;
    novo -> prox = prim;

    prim = novo;

    return prim;
}

Remove element from start. Here is my problem, because instead of releasing memory and decrementing an element the function is just erasing the data from memory and returning the first node as 0 (zero).

Can anyone tell me what’s wrong?

All the rest of the code works.

struct no * remove_inicio(struct no *prim){

    struct no *aux = prim;

    if(prim == NULL){
        printf("Lista Vaia!");
    }

    prim = prim -> prox;
    free(aux);

    return prim;
}

Insert element at end.

struct no * insere_final(struct no *prim){
    int num;
    struct no *novo;
    struct no *atual;

    printf("Insira o elemento no final da lista: ");
    scanf("%d",&num);

    novo = (struct no*) malloc(sizeof(struct no*));
    novo -> dado = num;
    novo -> prox = NULL;

    atual = prim;

    while(atual -> prox != NULL){
        atual = atual -> prox;
    }

    atual -> prox = novo;
}

Remove element at the end.

struct no * remove_fim(struct no *prim){
    struct no *atual = prim;
    struct no *anterior;

    if(prim == NULL){
        printf("Lista Vaia!");
    }

    if(prim -> prox == NULL){
        prim = NULL;
        free(atual);
        printf("Removido do final!");
    }else{
        while(atual -> prox != NULL){
            anterior = atual;
            atual = atual -> prox;
        }
        anterior -> prox = NULL;
        free(atual);
        printf("Removido do final!");
    }
}

Function main.

int main(){
    int op;
    struct no *prim;
    prim = (struct no*) NULL;

    do{
        system("clear");
        printf("\n<1> - Inserir no inicio");
        printf("\n<2> - Inserir no final");
        printf("\n<3> - Remover no inicio");
        printf("\n<4> - Remover no final");
        printf("\n<5> - Imprimir");
        printf("\n<10> - Sair do programa\n\n");
        printf("Digite sua opcao: ");
        scanf("%d",&op);

        switch (op)
        {
            case 1 : prim = insere_inicio(prim);
            break;

            case 2 : insere_final(prim);
            break;

            case 3 : remove_inicio(prim);
            break;

            case 4 : remove_fim(prim);
            break;

            case 5 : imprimir(prim);
            break;

        };
    }while(op != 10);

    return 0;

}

1 answer

1

I’ve revised your code. Below:

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

struct no {
    int dado;
    struct no *prox;
};

void imprimir(struct no *prim) {
    struct no *atual = prim;
    system("clear");
    printf("\nLista: ");

    while (atual != NULL) {
        printf("%d -> ", atual->dado);
        atual = atual->prox;
    }
    printf("NULL");
}

struct no *insere_inicio(struct no *prim) {
    int num;

    printf("\nInsira o elemento no inicio da lista: ");
    scanf("%d", &num);

    struct no *novo = (struct no *) malloc(sizeof(struct no *));
    novo->dado = num;
    novo->prox = prim;

    return novo;
}

struct no *insere_final(struct no *prim) {
    int num;

    printf("Insira o elemento no final da lista: ");
    scanf("%d", &num);

    struct no *novo = (struct no *) malloc(sizeof(struct no *));
    novo->dado = num;
    novo->prox = NULL;

    if (prim == NULL) return novo;

    struct no *ultimo = prim;

    while (ultimo->prox != NULL) {
        ultimo = ultimo->prox;
    }

    ultimo->prox = novo;
    return prim;
}

struct no *remove_fim(struct no *prim) {
    if (prim == NULL) {
        printf("Lista Vazia!");
        return NULL;
    }
    if (prim->prox == NULL) {
        printf("Removido do final!");
        free(prim);
        return NULL;
    }

    struct no *penultimo = prim;
    struct no *ultimo = prim->prox;

    while (ultimo->prox != NULL) {
        penultimo = ultimo;
        ultimo = ultimo->prox;
    }

    penultimo->prox = NULL;
    free(ultimo);
    printf("Removido do final!");
    return prim;
}

int main() {
    int op;
    struct no *prim = NULL;

    do {
        system("clear");
        printf("\n<1> - Inserir no inicio");
        printf("\n<2> - Inserir no final");
        printf("\n<3> - Remover no inicio");
        printf("\n<4> - Remover no final");
        printf("\n<5> - Imprimir");
        printf("\n<10> - Sair do programa\n\n");
        printf("Digite sua opcao: ");
        scanf("%d", &op);

        switch (op) {
            case 1:
                prim = insere_inicio(prim);
                break;

            case 2:
                prim = insere_final(prim);
                break;

            case 3:
                prim = remove_inicio(prim);
                break;

            case 4:
                prim = remove_fim(prim);
                break;

            case 5:
                imprimir(prim);
                break;
        }
    } while (op != 10);

    return 0;
}

The changes I made were:

  • Never forget to assign the output of the functions to the prim. So use prim = remove_fim(prim); instead of just remove_fim(prim);.

  • Its functions remove_fim and insere_final were forgetting to return the pointer from the top of the list.

  • Its functions remove_inicio, insere_final and remove_fim would not work if prim for NULL. In particular in the case of insere_final and remove_fim, you even detect the condition, but let it proceed the same way.

  • The function remove_fim was able to be greatly simplified, but I simplified other things as well.

It seems that you think changing the value of the pointer of the parameter will be reflected in a change of the value of the pointer passed in the function. This is not true. The fact that you change the address pointed out by prim within the call function will not do the prim outside (in the main) change. Change is reflected only when you change something in the value or structure that is pointed out, not in the pointer itself. Therefore, another possible solution to this would be to use pointers to pointers (which eliminates the need to assign the returned pointers to the main):

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

struct no {
    int dado;
    struct no *prox;
};

void imprimir(struct no *prim) {
    struct no *atual = prim;
    system("clear");
    printf("\nLista: ");

    while (atual != NULL) {
        printf("%d -> ", atual->dado);
        atual = atual->prox;
    }
    printf("NULL");
}

void insere_inicio(struct no **prim) {
    int num;

    printf("\nInsira o elemento no inicio da lista: ");
    scanf("%d", &num);

    struct no *novo = (struct no *) malloc(sizeof(struct no *));
    novo->dado = num;
    novo->prox = *prim;
    *prim = novo;
}

void insere_final(struct no **prim) {
    int num;

    printf("Insira o elemento no final da lista: ");
    scanf("%d", &num);

    struct no *novo = (struct no *) malloc(sizeof(struct no *));
    novo->dado = num;
    novo->prox = NULL;

    if (*prim == NULL) {
        *prim = novo;
        return;
    }

    struct no *ultimo = *prim;

    while (ultimo->prox != NULL) {
        ultimo = ultimo->prox;
    }

    ultimo->prox = novo;
}

void remove_fim(struct no **prim) {
    if (*prim == NULL) {
        printf("Lista Vazia!");
        return;
    }
    if ((*prim)->prox == NULL) {
        printf("Removido do final!");
        free(*prim);
        *prim = NULL;
        return;
    }

    struct no *penultimo = *prim;
    struct no *ultimo = (*prim)->prox;

    while (ultimo->prox != NULL) {
        penultimo = ultimo;
        ultimo = ultimo->prox;
    }

    penultimo->prox = NULL;
    free(ultimo);
    printf("Removido do final!");
}

int main() {
    int op;
    struct no *prim = NULL;

    do {
        system("clear");
        printf("\n<1> - Inserir no inicio");
        printf("\n<2> - Inserir no final");
        printf("\n<3> - Remover no inicio");
        printf("\n<4> - Remover no final");
        printf("\n<5> - Imprimir");
        printf("\n<10> - Sair do programa\n\n");
        printf("Digite sua opcao: ");
        scanf("%d", &op);

        switch (op) {
            case 1:
                insere_inicio(&prim);
                break;

            case 2:
                insere_final(&prim);
                break;

            case 3:
                remove_inicio(&prim);
                break;

            case 4:
                remove_fim(&prim);
                break;

            case 5:
                imprimir(prim);
                break;
        }
    } while (op != 10);

    return 0;
}

Finally, I recommend that you review the name of some things, for the sake of coherence. You have insere_final and remove_fim instead of insere_final and remove_final or of insere_fim and remove_fim.

  • It is worth remembering that the use of pointer pointer facilitates life in other types of structures such as binary trees, when it is necessary to know who is the father of that element

Browser other questions tagged

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