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()
Study carefully what will result from:
N->info = x;
within the push function.– anonimo