Problem with chained list in C

Asked

Viewed 499 times

2

I am doing a college job where basically the Program should be done in C language using chained lists and have 3 options:

  1. Add music (beginning, middle or end of list) with name, band and duration;
  2. Option to display the playlist;
  3. Quit the program.

I created the code below, but when I add a new song, the pointer is pointing to itself, rather than pointing to the new element. And when I list the songs, it happens that it displays a list where all the songs in the list are equal to the last song added.

Code:

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

int menu();
void Listar();
void InserirInicio(char* nome, char* banda, char* duracao);

struct Musica {
    char* nome;
    char* banda;
    char* duracao;
    Musica *prox;
} *Head;

int main() {
    int op;
    char nome[100], banda[100], duracao[10];

    while (1) {
    op = menu();
    switch (op) {
    case 1: //inserir no inicio da lista
        printf("Nome da musica: ");
        fflush(stdin);
        fgets(nome, 100, stdin);
        printf("Banda: ");
        fflush(stdin);
        fgets(banda, 100, stdin);
        printf("Duracao da musica: ");
        fflush(stdin);
        fgets(duracao, 10, stdin);
        InserirInicio(nome, banda, duracao);
        break;
    case 2: //Listar todas as musicas
        Listar();
        break;
    case 3: //sair do programa
        return 0;
    default:
        printf("Invalido\n");
    }
}

return 0;
system("pause");
}

int menu() {
    int opcao, c;
    system("Cls");

    printf("1. Adicionar nova musica\n");
    printf("2. Exibir todas as musicas\n");
    printf("3. Sair\n\n");
    printf("Digite sua escolha: ");

    scanf_s("%d", &opcao);
    while ((c = getchar()) != '\n' && c != EOF) {}

    system("Cls");
    return opcao;
}

void Listar() {
    Musica *ElementoVarredura;
    ElementoVarredura = (struct Musica *)malloc(sizeof(struct Musica));

    ElementoVarredura = Head;
    if (ElementoVarredura == NULL) {
        return;
    }

    int contador = 1;

    while (ElementoVarredura != NULL) {
        printf("%d.\n", contador);
        printf("Nome: %s", ElementoVarredura->nome);
        printf("Artista: %s", ElementoVarredura->banda);
        printf("Duracao: %s", ElementoVarredura->duracao);
        ElementoVarredura = ElementoVarredura->prox;
        contador++;
        printf("\n------------------------------------\n");
    }
    printf("\n");
    system("pause");
    return;
}

void InserirInicio(char* nome, char* banda, char* duracao)
{
    Musica *NovoElemento;
    NovoElemento = (struct Musica *)malloc(sizeof(struct Musica));

    NovoElemento->nome = nome;
    NovoElemento->banda = banda;
    NovoElemento->duracao = duracao;
    NovoElemento->prox = NULL;


    if (Head == NULL)
    {
        Head = NovoElemento;
    }
    else
    {
        NovoElemento->prox = Head;
        Head = NovoElemento;
    }
}

What’s wrong with it?

  • You are reading multiple strings for char arrays in the main method (allocated in stack), then you pass pointers to these arrays for the method InserirInicio and then uses these pointers in the NovoElemento. That is, all pointers point to memory addresses of the same arrays (which in turn do not live in dynamic memory as they should). What you really want is either 1) Transform the char * in character arrays or 2) Use a combination of strdup and free to respectively copy the strings to dynamic memory and then release it.

  • me ajuda https://answall.com/questions/412245/lista-encadeada-socorro

1 answer

2

The problem is not that the pointer of your structure is pointing to the structure itself, the problem is that the attributes nome, banda and duracao are pointers, and the pointer of all structures are pointing to the same memory address, so when you change the value at that address with fgets(nome, 100, stdin) for example, this reflects on all structures.

Try moving the declaration of these variables to the same function you create the instance of the structure, this way you will create new references to each structure:

void InserirInicio()
{
    char *nome = (char *)malloc(sizeof(char) * 100);
    char *banda = (char *)malloc(sizeof(char) * 100);
    char *duracao = (char *)malloc(sizeof(char) * 10);
    struct Musica *NovoElemento = (struct Musica *)malloc(sizeof(struct Musica));

    printf("Nome da musica: ");
    fflush(stdin);
    fgets(nome, 100, stdin);
    printf("Banda: ");
    fflush(stdin);
    fgets(banda, 100, stdin);
    printf("Duracao da musica: ");
    fflush(stdin);
    fgets(duracao, 10, stdin);

    NovoElemento->nome = nome;
    NovoElemento->banda = banda;
    NovoElemento->duracao = duracao;
    NovoElemento->prox = NULL;

    if (Head == NULL)
    {
        Head = NovoElemento;
    }
    else
    {
        NovoElemento->prox = Head;
        Head = NovoElemento;
    }
}
  • I tried to do as you said, but gives the following error: A value of type "void *" cannot be used to initialize an entity of type "char *"

  • You are probably using a C++ compiler. Include a cast ((char*)) in front of the malloc. Alternatively leave the reading with fgets as it was before and make a copy of the pointer at the time of assignment to struct members (e. g., NovoElemento->nome = strdup(nome);). In both cases don’t forget to free up the memory you allocated using free.

  • I’m sorry, I’m a C beginner and I couldn’t understand how it would look in the code.

  • @Miketaiki, the problem is malloc returns a data of type void*. In C you can assign this value to a variable of another type, but C++ requires you to do the casting of that return. I added this casting to compile in C++ as well.

Browser other questions tagged

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