I changed the original example a little bit because I had posted wrong and
to show the lack it makes Lista
not to be a complete structure,
but only one knot.
I will leave an example at the end with your code and that creates a
list with some elements and shows on the screen. But I think should incorporate the
I’m writing next before continuing with your program - @arfneto
struct no //cria uma estrutura do tipo no
{
int num;
struct no *prox;
struct no *ant;
} *node;
Write your program around the data. Always. And everything gets simpler.
Understand that a linked list NAY is a node and whenever programming a list as if it were a node will take more work without need.
Imagine this structure:
typedef struct
{
unsigned size;
unsigned limit;
Node* inicio;
Node* fim;
} Lista;
By declaring something like Lista
will already have a size, a limit, a pointer to the end and another to the beginning. And even if you have 25 lists in the same program each one will have their values preserved WITHIN the structure. This is the concept of encapsulation.
Understand that prototypes should be OUT of main()
And maybe in a header file --- or such . h for example --- separate. The way you wrote it is wrong.
It’s nice to use comments in your code, but maybe you could avoid these so obvious:
void criar_lista(int n); //mostra que foi criado uma função criar_lista
void imprimir_lista(); //mostra que foi criado uma função imprimir_lista
void imprimir_lista_inverso();
And how to invert a list?
You’re the one who’s creating the list.
You can always enter at the beginning, always at the end or in some order.
Let’s imagine that will always insert at the beginning:
Then when going through the list to print the values will appear in reverse chronological order, of course: the last inserted will be the first.
When you list the last guy, he will be pointing to NULL. And that will be the pointer to the end of the list. I guess you figured there should be an updated pointer to the bottom of the list, right? And then do exactly the same thing you did to list the elements, but just show the last element, point to his previous one and continue until he doesn’t have a previous one and you will have listed the elements in the reverse order, the insertion order.
These classifications are generically called LIFO and FIFO in literature, of Last In First Out and First In First Out.
list()
Create list should return the address of a List. Avoid returning void: in general it is a waste and often an error. In this case both of you. but what matters is the error: the address of your new list will die there within the function.
Do the simple and create a function too that inserts a value in the list and returns its address for the same reason. Something simple like
Lista* insere( int item, node lista);
You don’t need a function to create the list
avoid creating pointer types
This is very problematic and will always fall on your head. In your example, what kind of node
? struct no*
. What’s the point? How will you know when you read the program a month from now?
Maybe you should use a convention, as I showed in the example, writing the types you define with an uppercase initial, or all uppercase, or an underline on the front, at the end, a prefix, a suffix, anything but.
Understand that only declares variables, so if a node in the list is Node
a pointer to it ALWAYS is Node*
, a pointer to a pointer to it is Node**
and so on. The asterisk speaks for itself in C. In his example node
no. you’ll have to remember at all times that Node is a pointer and that’s not good: it’s bad. Well bad.
Don’t read anything from the keyboard
As long as your program is not ready in terms of list do not read anything from the keyboard. It will only delay you and will not be little. It also makes it difficult to repeat tests with the same data.
Always read from a file. It’s much easier. You can type files into the IDE itself. Reading from the keyboard is hell and will only slow you down...
And before reading from a file use constants in your program and test a little.
An example with your code
Like I said, I think you should write the list structure better.
Consider that you don’t actually need a routine to create the list. And that imprimir_lista()
should be the first routine running in your program. See this version of main()
int main(void)
{
setlocale(LC_ALL, "Portuguese");
Node* teste = NULL;
imprimir_lista(teste);
for (int i = 1; i <= 10; i += 1)
teste = inserir_no_inicio(i, teste);
Node* ultimo = imprimir_lista(teste);
Node* primeiro = imprimir_lista_inverso(ultimo);
// so para fechar o circulo
ultimo = imprimir_lista(primeiro);
return 0;
}
You may agree that it is much simpler to read. And test. Since your data is just one int
. Call imprimir_lista()
at the beginning is an obvious test because has that works with the pointer NULL
.
Then a for
inserts some elements and imprimir_lista()
must show the same
As I said at the beginning, this is not a good representation of a list. The simple thing is to have a structure with metadata to control the list, as I showed you. It’s much easier.
Anyway, I changed the routines that print the list to be more cooperative: you can call the routines from anywhere on the list, and imprimir_lista()
prints to the end and returns the last one’s address. And imprimir_lista_inverso()
prints from position to start, but returns the address of the first.
So you can call one after the other and the circle is complete :D
shows what is expected
imprimir_lista()
imprimir_lista()
Dado = 10
Dado = 9
Dado = 8
Dado = 7
Dado = 6
Dado = 5
Dado = 4
Dado = 3
Dado = 2
Dado = 1
imprimir_lista_inverso()
Dado = 1
Dado = 2
Dado = 3
Dado = 4
Dado = 5
Dado = 6
Dado = 7
Dado = 8
Dado = 9
Dado = 10
imprimir_lista()
Dado = 10
Dado = 9
Dado = 8
Dado = 7
Dado = 6
Dado = 5
Dado = 4
Dado = 3
Dado = 2
Dado = 1
The program, almost the same
Run and compare the program. I suggest to put the pointer to the end and make all the changes as listed. If you have more questions write and I complete the example with something...
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
struct no
{
int num;
struct no* prox;
struct no* ant;
} *node;
typedef struct no Node;
typedef struct
{
unsigned size;
unsigned limit;
Node* inicio;
Node* fim;
} Lista;
Node* criar_lista(int n); //mostra que foi criado uma função criar_lista
Node* imprimir_lista(Node*);
Node* imprimir_lista_inverso(Node*);
Node* inserir_no_inicio(int, Node*);
int main(void)
{
setlocale(LC_ALL, "Portuguese");
Node* teste = NULL;
imprimir_lista(teste);
for (int i = 1; i <= 10; i += 1)
teste = inserir_no_inicio(i, teste);
Node* ultimo = imprimir_lista(teste);
Node* primeiro = imprimir_lista_inverso(ultimo);
// so para fechar o circulo
ultimo = imprimir_lista(primeiro);
return 0;
}
Node* criar_lista(int n) //função criar lista que puxa um valor do tipo inteiro 'n'
{
/*
Node* novo = (Node*) malloc ( sizeof(Node) );
if (node == NULL) return NULL;
node->num = num;
node->ant = NULL; //estrutura node na variável ant recebe o valor de NULL
node->prox = NULL; //estrutura node na variável prox recebe o valor de NULL
}
printf("Digite dados para nó 1: ");
scanf(" %d", &num);
node->num = num; //estrutura node na variável num recebe o valor de num
node->ant = aux; //estrutura node na variável prox recebe o valor de NULL
node->prox = NULL; //estrutura node na variável prox recebe o valor de NULL
aux = node;
for (i = 2; i <= n; ++i)
{
fim_no = (struct no*)malloc(sizeof(struct no));
if (fim_no == NULL)
{
printf("Erro no 'for' em criar lista ");
break;
}
else
{
printf("Digite dados para nó %d: ", i);
scanf(" %d", &num);
fim_no->num = num;
fim_no->prox = NULL;
aux->prox = fim_no;
aux = aux->prox;
}
}
*/
return NULL;
};
Node* imprimir_lista(Node* L)
{
// imprime a lista a partir de L
// e retorna o endereco do ultimo cara
printf("imprimir_lista()\n");
if (L == NULL) return NULL;
Node* p = L;
Node* ultimo = NULL;
while (p != NULL)
{
printf("Dado = %d\n", p->num);
ultimo = p;
p = p->prox;
};
return ultimo; // retorna o total de itens
};
Node* imprimir_lista_inverso(Node* L)
{
// imprime a lista a partir de L, para tras,
// e retorna o endereco do primeiro cara
printf("imprimir_lista_inverso()\n");
if (L == NULL) return NULL;
Node* p = L;
Node* primeiro = NULL;
while (p != NULL)
{
printf("Dado = %d\n", p->num);
primeiro = p;
p = p->ant;
};
return primeiro; // retorna o total de itens
}
Node* inserir_no_inicio(int n, Node* L)
{
// a lista existe, mas pode estar vazia
// vai inserir sempre no inicio nesse exemplo
Node* novo = (Node*)malloc(sizeof(Node));
novo->num = n;
novo->ant = NULL; // vai ficar no inicio
novo->prox = L; // vai apontar para o que estava na frente
if (L != NULL) L->ant = novo;
return novo;
};
// fim
Since it’s a double-chained list, just run it backwards. I think it would be very useful for you to have pointers for both the first and the last node of the list.
– anonimo