String-populated chained list(Linked list)

Asked

Viewed 149 times

-4

Hello, I’m trying to create a list that is populated with strings but when I try to print it nothing appears. I appreciate any help available.

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

typedef struct tipoNo {
    char* info;
    struct tipoNo *prox;    
} no;

void iniLista(no **L) {
    *L = NULL;
}

void print(no **L) {
    no *P;
    P = *L;

    while(P != NULL) {
        printf("%c", P->info);
        P = P->prox;
    }
}
//insere        
void push(no **L, char* x) {
    no *P, *N;

    N = (no *) malloc (sizeof(no));
    N->info = x;

    if(*L == NULL) {
        *L = N;
    }
    else {
        P = *L;

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

int main() {
    no *L;

    push(&L, "asasas");
    push(&L, "basasa");
    print(&L);

    return 0;
}
  • Study carefully what will result from: N->info = x; within the push function.

2 answers

2


This is a node from your list:

typedef struct tipoNo 
{
    char*           info;
    struct tipoNo*  prox;

}   no;

And it shouldn’t be your list. A linked list is a collection of nodes and not a node. Every time you use one Node as if it were a list will get more work and less result. The structure has metadata, things to keep the list working. If you control this out of it it becomes difficult and insecure. Imagine if you have several of these lists in the same program for example: How will you control the variables that refer to each list?

Compare it to something like that

struct a_propria_lista
{
    char*     nome;
    unsigned  quantos;
    unsigned  maximo;
    Node*     inicio;
    Node*     fim;
};
typedef struct a_propria_lista Lista;

And understand that every thing declared

    Lista    lista;
    Lista*   coisas[4];

as Lista has its own size, limits and pointers. And it all goes together in the declaration. , Much more comfortable. It’s the casting thing. And you can use or not all fields, you can create new fields without touching the arguments, and life goes on. Consider this.

Back to your show

Another problem is memory allocation: you can’t just write

    N->info = x;

having declared

    void push(no **L, char* x); 

and using

    no *L;
    push(&L, "asasas");
    push(&L, "asasas"); // sim, o mesmo
    push(&L, "asasas"); // e de novo

As I said above, no is a node and not a list. And it should have been initialized. But the real problem is that "asasas" is not exactly char*. You should copy the data to the allocated area and not copy the pointer. Imagine for example if push() is called from within another function.

  • return of function all function variables cease to exist. As is your list?
  • a literal "asasas" is const char[7]. Imagine what your program would look like if you tried to remove any of them from the list
  • these constants can be optimized by the compiler, since they are constant and have the same value, and there will be elements in the list pointing to the same address
  • any of these reasons would serve to cancel your program
  • strings in C are null-terminated so you have to reserve a position also for the string terminator, zero at the end
  • use main() ALWAYS as the first function of your program. It is best for you and for whoever will read your program...
  • use const char* in cases like this where it may be that the function is called with a constant argument, so you protect yourself from this type of error
  • avoid using void. In general it is a waste and is often a mistake even. Almost always have something useful to return. In these cases of List for example you can return the pointer to the beginning of the list instead of always passing no**. Let me show you an example in a hypothetical function apaga()

As it still works, it only takes more work

An example of push() that would work


void push(no** L, const char* x)
{
    no* novo = (no*)malloc(sizeof(no));
    // aloca a string do tamanho certo
    novo->prox = NULL;
    novo->info = (char*)malloc(1 + strlen(x));
    // copia os dados nao o ponteiro
    strcpy(novo->info, x);
    // push(): essa versao insere novos elementos
    // no final da lista
    if (*L == NULL)
    {
        *L = novo;
        return;
    };
    no* p = *L;
    while (p->prox != NULL)
        p = p->prox;
    p->prox = novo;
    return;

a test program

This program creates these two elements that used and then some more using sprintf() to number a string

int main(void)
{
    char string[20];
    no* L = NULL;

    push(&L, "asasas");
    push(&L, "basasa");
    for (int i = 1; i < 10; i += 1)
    {
        sprintf(string, "Teste %02d", i);
        push(&L, string);
    };  // for()
    print(&L);

    // apaga tudo
    L = apaga(L);

    return 0;
};  // main()

exit

asasas
basasa
Teste 01
Teste 02
Teste 03
Teste 04
Teste 05
Teste 06
Teste 07
Teste 08
Teste 09
Lista apagada

the whole program

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

typedef struct tipoNo 
{
    char*           info;
    struct tipoNo*  prox;

}   no;

no*     apaga(no*);
void    iniLista(no**);
void    print(no**);
void    push(no**, const char* x);

int main(void)
{
    char string[20];
    no* L = NULL;

    push(&L, "asasas");
    push(&L, "basasa");
    for (int i = 1; i < 10; i += 1)
    {
        sprintf(string, "Teste %02d", i);
        push(&L, string);
    };  // for()
    print(&L);

    // apaga tudo
    L = apaga(L);

    return 0;
};  // main()

no* apaga(no* lista)
{
    // apaga as strings primeiro
    if (lista == NULL) return NULL;
    no* p = NULL;
    do
    {
        p = lista->prox; // salva esse
        free(lista);
        lista = p;

    } while (p->prox != NULL);
    printf("Lista apagada\n");
    return NULL;
}

void iniLista(no** L) { *L = NULL; }

void print(no** L)
{
    no* p = *L;
    while (p != NULL)
    {
        printf("%s\n", p->info);
        p = p->prox;
    }
};  // print()

void push(no** L, const char* x)
{
    no* novo = (no*)malloc(sizeof(no));
    // aloca a string do tamanho certo
    novo->prox = NULL;
    novo->info = (char*)malloc(1 + strlen(x));
    // copia os dados nao o ponteiro
    strcpy(novo->info, x);
    // push(): essa versao insere novos elementos
    // no final da lista
    if (*L == NULL)
    {
        *L = novo;
        return;
    };
    no* p = *L;
    while (p->prox != NULL)
        p = p->prox;
    p->prox = novo;
    return;

};  // push()

  • Boy, you were an angel now! What you said of N->info = x; was compromising all my code where I implement this list, your program really saved me, thank you very much

  • I’m glad it worked. When have a while watch out for those other things I listed, as the byte throw more, the case of returning the address as in apaga() and the separate structure for Lista, prototypes for functions at the start of the programme

0

The problem is relatively obvious and observable.

while(P != NULL) {
        printf("%c", P->info);
        P = P->prox;

Pay attention to the printf and the parameter who passes it. The structure has a value defined as a char pointer (string), but the print function is only printing a character.

Change from "%c" to "%s".

  • That’s exactly what it was and I wasn’t starting the list on main either. Thank you very much!

  • There are more problems. I recommend reading what I wrote and compare with the example I left in the post

Browser other questions tagged

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