2

As the title says I need to write a function which fill a list with int typed by the user, and later on print them, but i'm having troubles with the insert function, which does not actually put the values typed in the list. Here's the code:

the typedefs:

typedef struct list_element {
    int value;
    struct list_element *next;
} item;

typedef item *list;

and the functions:

list lins(list l)
{
    int i;
    list root = NULL;
    printf("inserire dati ('0' per terminare):\n");
    do
    {
        scanf("%d", &i);
        l = (list)malloc(sizeof(item)); 
        l->value = i;
        l->next = root;
        root = l;
    } while (i != 0);
    return l;
}

void showlist(list l)
{
    printf("lista completa:\n");
    while (l != NULL)
    {
        printf("%d ", l->value);
        l = l->next;
    }
    printf("\n");
}

Sorry if my code is poorly written but I'm having a hard time understanding the concept of lists.

Edit: added functions calls

main()
{
    lins(l);
    showlist(l);
}

Edit 2: here's the output of the code:

output

Edit 3: Here's the sample of code my professor give us to work with lists:

http://www.mediafire.com/file/wj152pw1ojkxf1j/10a_-Liste-_2018.pdf

m4mmt
  • 33
  • 1
  • 6
  • 4
    As a quick advice, don't hide pointers behind typedefs – machine_1 Mar 24 '18 at 20:48
  • @machine_1 This could be an advice, but partly opinion based, though I agree with you. – llllllllll Mar 24 '18 at 20:50
  • Does this code compile? What errors do you get if any (compile-time or run-time or misbehaviours). If you want to read an explanantion of the code, checkout [GeeksForGeeks](https://www.geeksforgeeks.org/generic-linked-list-in-c-2/) – udiboy1209 Mar 24 '18 at 20:56
  • 1
    Since you're just starting out, you might spend time learning to use your debugger. Single-stepping through your code and watching variables change can help you understand how things work, and why they don't work the way you expect them to. Logging / trace statements also help with this. – Dave S Mar 24 '18 at 20:58
  • @machine_1 can you explain in details why it's better to not use pointers? – m4mmt Mar 24 '18 at 21:02
  • @udiboy1209 the code compiles without errors or warnings. – m4mmt Mar 24 '18 at 21:03
  • @machine_1 added the main at the end of the post, it's quite simple lol – m4mmt Mar 24 '18 at 21:05
  • @m4mmt machine_1 is saying to not hide your pointers. Have `list` be the struct itself, not a pointer to the struct. Use `list*` when you need a pointer. It makes it easier to understand what's going on. – Kevin Mar 24 '18 at 21:06
  • don't know how you don't get any errors when you use uninitialized variable l... – sstefan Mar 24 '18 at 21:07
  • If the code compiles, what doesn't work as expected @m4mmt ? The code looks correct enough to me. It should prepend inserted numbers to the linked list. – udiboy1209 Mar 24 '18 at 21:07
  • Please read [Is it a good idea to typedef pointers?](https://stackoverflow.com/questions/750178/) The TL;DR is "no, except perhaps for function pointers". – Jonathan Leffler Mar 24 '18 at 21:08
  • It is also a good idea to check the return value from `scanf()` before you try using what was read. Your code adds the `0` that marks the end of input to the list — is that what you intended? You ignore (overwrite) the value of `l` that is passed to the function. That isn't a good idea. Either you don't need the parameter, or you should preserve — probably by using `item *root = l;`. – Jonathan Leffler Mar 24 '18 at 21:09
  • @udiboy1209 when i print the list it prints... well, nothing. Since the code looks fine to me I though that it was a problem with the returning of the function to the main. edit: I added a screen shot of the output at the end of the post. – m4mmt Mar 24 '18 at 21:10
  • I do use typedefs for pointers, but I always make it obvious, eg: 'Item', 'pItem'. – Martin James Mar 24 '18 at 21:14
  • Your main function is written to archaic C standards. All this millennium, the standards say "thou shalt use `int main(void)` (or perhaps `int main()`)", with the explicit return type being necessary. You've not shown how `l` is defined in `main()` — which means you've probably made it into a global variable, which is a bad idea for multiple reasons. However, it is not being changed by `lins()` and you're ignoring the list returned by `lins()` so it isn't surprising that there's nothing for `showlist()` to show. – Jonathan Leffler Mar 24 '18 at 21:16
  • @JonathanLeffler Yes I know that global variables are bad, I changed it as an extreme attempt to make the code working. can you explain more in details what is wrong with lins function? edit: answering also your first comment: the zero is intended to stop the program to read typed ints. And what do you mean with "overwriting the value of l that is passed to the function?" – m4mmt Mar 24 '18 at 21:21
  • You now have two answers doing a reasonable job of explaining what's wrong and how to do it better. Neither program is perfect — no program is perfect (there's always room for improvement) — but they are huge steps in the right direction. I've not compiled them, but they look plausible. – Jonathan Leffler Mar 24 '18 at 21:26

4 Answers4

2

Your insertion function inserts in reverse order. That is because you assign root to l->next and l to root. Also the number 0 is included in the list when the user tries to end the insertion process.

In main(), you don't seem to assign the return value of the function lins() to a variable, and if you passed l declared as List l = NULL; to the function lins(), then a copy of it will be used, and so, the original variable won't be altered. What you really need is something like:

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

typedef struct list_element {
    int value;
    struct list_element *next;
} item;

typedef item *list;


list lins(void)
{
    list node = NULL;
    list root = NULL;
    list tail = NULL;

    printf("inserire dati ('0' per terminare):\n");

    int i;
    scanf("%d", &i);
    while(i != 0)
    {
        node = (list)malloc(sizeof(item));
        node->value = i;
        node->next = NULL;

        if (!root)
            root = node;
        else
            tail->next = node;
        tail = node;
        scanf("%d", &i);
    }
    return root;
}

void showlist(list l)
{
    printf("lista completa:\n");
    while (l != NULL)
    {
        printf("%d ", l->value);
        l = l->next;
    }
    printf("\n");
}


int main(void)
{
    list head = lins();
    showlist(head);

    system("pause");
    return 0;
}

Of course, I should point out that you should free the list once you are done with it.

machine_1
  • 4,266
  • 2
  • 21
  • 42
  • @m4mmt You are welcome. I performed a slight edit to the code in my answer if you are interested. I changed the `do-while()` loop to just a `while()` loop; it is better this way. – machine_1 Mar 24 '18 at 21:50
  • to better specify what I'm trying to do, the insert function have to put now elements in the head of the list, so I think that the reverse order is exactly what the professor wants. Well the next step is tail insert, so thanks anyway – m4mmt Mar 24 '18 at 21:58
1

First of, I see no point in passing item *l as an argument to lins function.

The root or better, head of the list should not be changed once you assign something to it, unless you want to delete the list.

void lins(item **head){
    item *new_node = malloc(sizeof(item));
    int i;

    if(!new_node){
        printf("Memory allocation failed!\n");
        exit(1);
    }

    scanf("%d", &i);

    new_node->value = i;
    new_node->next = NULL;

    node *temp = *head;

    if(!temp)
        *head = new_node;
    else{
        while (temp->next != NULL){
            temp = temp->next;
        }
        temp->next = new_node;
    }
    return ;
}

After you write lins like this, showlist can look as follow:

void showlist(item *head){
    printf("List is: \n");
    do{
        printf("%d", head->value);
        head=head->next;
    }while(head!=NULL);
}

As for the main function you need to declare the head first.

int main(){
    item *head = NULL;
    lins(&head);
    showlist(head);
    return 0;
}

more detailed explanation to follow...

sstefan
  • 385
  • 4
  • 15
  • The original design had `lins()` return the new head; that's not a bad design. I agree that the original code did not make good (any) use of the argument it was passed — it should have done, though. What you've got looks plausible (I've not compiled it), but `item *head = lins(NULL); showlist(head);` might work, and is more along the lines of what I'd do. – Jonathan Leffler Mar 24 '18 at 21:23
  • @JonathanLeffler I agree. It looks cleaner that way. Although it is not exactly as the OP designed it, I thought I'd give another possible way to implement linked list. I guess there is no harm in that. – sstefan Mar 24 '18 at 21:34
1

So from what I understand, you want to prepend to your linked-list. I will try to use your typedefs, though many comments have given better options to use, you could change the implementation later.

Realise that lins(list l) is never utilising the value of the parameter l passed to it. That is overriden by the malloc. It is prepending elements to the list, and finally returns the new head of your list. That new head has to be passed to showlist() for printing. What you might be doing is initialising one element of the list in main, and passing that to lins and showlist. lins doesnt bother with the parameter and returns a completely new list, but when you pass that old list to showlist it is interpreted as an empty list.

So you can simply change usage of lins to be used as a creator of linked-lists.

So declaring list lins() {...} and using it in main() like this should work:

int main() {
    list l;
    l = lins();
    showlist(l);
    return 0;
}
udiboy1209
  • 1,472
  • 1
  • 15
  • 33
0
struct list_element {
int value;
struct list_element *next;};
typedef struct list_element * list;

void lins(list *l){
list tmp = NULL;
list last = *l;
int i;
if (last){
    while(last->next){ // go to last child of list
        last = last->next;
    }
}else{
    last = (list)malloc(sizeof(struct list_element));
}

printf("inserire dati ('0' per terminare):\n");
do
{
    scanf("%d", &i);
    last->value = i; 
    last->next = (list)malloc(sizeof(struct list_element));
    last = last->next;
} while (i != 0);}

void show(list li){
list tmp = li;
if(li){
    while(tmp){
    printf("%d at %p\n",tmp->value, tmp);
    tmp = tmp->next;
    }
}}

int main(){
list a = (list)malloc(sizeof(struct list_element));
lins(&a);
show(a);
return 0;}
juancarlos
  • 593
  • 3
  • 9