23
#include <stdio.h>

typedef struct node
{
      int i;
      struct node *next;
}node;

node getnode(int a)
{
      struct node n;
      n.i=a;
      n.next=NULL;
      return n;
}

main()
{
     int i;
     node newtemp,root,temp;

     scanf("%d",&i);
     root=getnode(i);
     temp=root;

     while(i--)
     {
         newtemp=getnode(i);

         temp.next=&newtemp;
         if(root.next==NULL)
         {
            root=temp;
         }
        temp=*(temp.next);
     }


     temp=root;

     while( temp.next != NULL )
     {
         printf(" %d ",temp.i);
         temp=*(temp.next);
     }
}

I am trying to create a linked-list without using malloc. The programming is printing only the root and no nodes following it. I couldn`t find the bug. Had there been any memory issue, the gcc compiler would have thrown a segmentation fault.(?) Please ignore the poor programming style..

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
letsc
  • 2,075
  • 5
  • 24
  • 43
  • 7
    A linked list without using `malloc`? Is that even possible? – gablin Oct 04 '10 at 14:46
  • Why?? I am not sure but why cant it possible when we have stack allocation and well defined copy constructor??? – letsc Oct 04 '10 at 14:49
  • Welcome to SO :) You can, and should, use the "010101"-button or 4-space indent to have your code snippets marked up as code. I did it for you just now. – Magnus Hoff Oct 04 '10 at 14:49
  • Thanx Magnus. I didnt know. m new here. :) – letsc Oct 04 '10 at 14:56
  • @smartmuki: You tagged this question C, then you go asking about "well defined copy constructor"? C has no such thing as a copy constructor, or any constructors at all. – R.. GitHub STOP HELPING ICE Oct 04 '10 at 15:02
  • Ahhhh!! I wasnt getting the right word. I meant member-wise copy.. Incovenience regretted.. – letsc Oct 04 '10 at 15:05
  • Have a look at http://stackoverflow.com/questions/3002764/using-c-is-a-linked-list-implementation-without-using-pointers-possible-or-not/3002805#3002805, which is a **very** special case of creating an immutable list in C++ without using malloc. (It doesn't work in straight C) – Ken Bloom Oct 04 '10 at 15:05
  • You could use `alloca` I suppose? http://www.kernel.org/doc/man-pages/online/pages/man3/alloca.3.html http://msdn.microsoft.com/en-us/library/5471dc8s.aspx Or you could create large memory pool with a single alloc / local char[] and handle your own allocation within that. – Rup Oct 04 '10 at 15:21
  • 8
    @gablin: Sure. You could declare an array of nodes statically, and use that as your memory pool. It assumes you have an idea of what the upper bound for the number of nodes will be, but it's a perfectly valid method (and when I was doing Fortran 77 in college, it was the *only* method). `malloc()/free()` give you more flexibility, but they're not strictly necessary. – John Bode Oct 04 '10 at 19:34
  • @John Bode: Yes, this is true as long as you have a bounded list. I was referring to an unbounded list but forgot to mention it. ^^ – gablin Oct 04 '10 at 20:10
  • 1
    This is all about unwillingness to check the malloc() return value for zero and implement out-of-memory logic, isn't it? :) – Seva Alekseyev Oct 05 '10 at 15:51

8 Answers8

21

When you initialise temp.next, what is the value of the pointer that you assign to it?

temp.next=&newtemp;

Why, it's the same one every time! (Draw a picture if you are unconvinced.)

Give it up. If you need an indeterminate amount of memory (which, with an indeterminate number of nodes, you do), then you need to allocate memory.

John Marshall
  • 6,815
  • 1
  • 28
  • 38
14

You can avoid malloc but not for free:

  • On Linux/UNIX you could call brk() and write your own memory allocator.
  • On every system you can write your own allocator using a fixed size array as a memory source.
  • I do do not see what the alternatives would buy over just malloc/free directly. They're there for a reason.
  • Returning local variables to be used outside would be simple but is an error and does not work.
Peter G.
  • 14,786
  • 7
  • 57
  • 75
  • 29
    "You can avoid malloc but not for free" makes a very bad pun :D – Matteo Italia Oct 04 '10 at 15:15
  • The main reason to write your own allocator is when you have specific needs from it. That way you can get an allocator atht is perfectly suited for your program. Most times, though, it isn't worth it. – Vatine Oct 08 '10 at 11:05
6

You only have two memory spaces that you can use to store nodes, and those are root and newtemp. When you assign a new node to newtemp the old node doesn't exist anymore.

Assuming you entered the number 5 at the scanf, before first iteration of the loop, you have:

5 -> NULL

After the first iteration of the loop, you have

5 -> 4 -> NULL

After the second iteration of the loop, you have

5 -> 3 -> NULL

(The node containing 4 has been completely replaced by the node containing 3).

The only solution is to use malloc, and make getnode return a node*.

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
  • 1
    Strictly speaking, you could put an array of nodes on the stack or declare them static, and make your function pull the next one from the array instead of using `malloc`. – R.. GitHub STOP HELPING ICE Oct 04 '10 at 15:29
  • @R. You are right. Some of the same tricks I came up with for http://stackoverflow.com/questions/3002764/using-c-is-a-linked-list-implementation-without-using-pointers-possible-or-not/3002805#3002805 could be used here as well. – Ken Bloom Oct 05 '10 at 01:09
6

You can statically declare an array of node structures and pick new nodes from that array. But then you would've implemented a lame, woefully specialized custom allocator. And the maximum number of nodes available will be the size of that array.

Alternatively, you can use recursion as an allocation mechanism, and do things to the list on the bottom of the recursion stack.

Both approaches are about equally cludgey.

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
6

Of course you can build a linked list or any other data structure without dynamic memory allocation. You can't, no matter how hard you try, though, build it allocating no memory at all.

Alternative:

Create a global or static memory pool where you can put your objects, imitating the heap/malloc/free. FreeRTOS does something like. In this situation, you will have a big memory chunk allocated statically since the begining of your program and will be responsible for managing it, returning the correct pointers when a new node is needed and marking that memory as used.

P.S.: I won't question why you want to avoid malloc. I supose you have a good reason for it.

In you program, when you do, in line 20:

     node newtemp,root,temp; 

You are allocatin thre nodes, one of them, "newtemp". Then you do in line 28:

     newtemp=getnode(i); 

It just copies the contents of the returned node over your old "newnode" (controversal, isn't?)

So you do, just bellow:

     temp.next=&newtemp; 

That sets a pointer that initially comes from "root.next" to your "newnode".

     if(root.next==NULL) 

Will be "NULL" at first pass, but then, only replace the same contents.

    temp=*(temp.next); 
     { 
        root=temp; 
     } 

Is, again, copying data from a single allocated object, "*(temp.next)", to another, "temp". It does not create any new node.

It will work if you do like this:

#include <stdio.h>

typedef struct node 
{ 
    int i; 
    struct node *next; 
}
    node; 

#define MAX_NODES   10

node    *create_node( int a )
{ 
    // Memory space to put your nodes. Note that is is just a MAX_NODES * sizeof( node ) memory array.
    static node node_pool[ MAX_NODES ];
    static int  next_node = 0;

    printf( "[node  *create_node( int a )]\r\tnext_node = %d; i = %d\n", next_node, a );
    if ( next_node >= MAX_NODES )
    {
        printf( "Out of memory!\n" );
        return ( node * )NULL;
    }

    node    *n = &( node_pool[ next_node++ ] );

    n->i = a;
    n->next = NULL;

    return n; 
} 

int main( )
{ 
    int i; 
    node    *newtemp, *root, *temp; 

    root = create_node( 0 ); 
    temp = root; 

    for ( i = 1; ( newtemp = create_node( i ) ) && i < MAX_NODES; ++i )
    { 
        temp->next = newtemp; 

        if ( newtemp )
        {
            printf( "temp->i = %d\n", temp->i );
            printf( "temp->next->i = %d\n", temp->next->i );
            temp = temp->next;
        }
    }


    for ( temp = root; temp != NULL; temp = temp->next )
        printf( " %d ", temp->i );

    return  0;
}

The output:

    $ gcc -Wall -o list_no_malloc list_no_malloc.c 

$ ./list_no_malloc
[node   next_node = 0; i = 0)]
[node   next_node = 1; i = 1)]
temp->i = 0
temp->next->i = 1
[node   next_node = 2; i = 2)]
temp->i = 1
temp->next->i = 2
[node   next_node = 3; i = 3)]
temp->i = 2
temp->next->i = 3
[node   next_node = 4; i = 4)]
temp->i = 3
temp->next->i = 4
[node   next_node = 5; i = 5)]
temp->i = 4
temp->next->i = 5
[node   next_node = 6; i = 6)]
temp->i = 5
temp->next->i = 6
[node   next_node = 7; i = 7)]
temp->i = 6
temp->next->i = 7
[node   next_node = 8; i = 8)]
temp->i = 7
temp->next->i = 8
[node   next_node = 9; i = 9)]
temp->i = 8
temp->next->i = 9
[node   next_node = 10; i = 10
Out of memory!
 0  1  2  3  4  5  6  7  8  9 
fljx
  • 151
  • 1
  • 2
2

A linked list is something of indeterminate length, and anything of indeterminate length cannot be created without malloc.

I suggest you simply use malloc to allocate the next link in the chain.

Platinum Azure
  • 45,269
  • 12
  • 110
  • 134
Alexander Rafferty
  • 6,134
  • 4
  • 33
  • 55
  • yeah that is the normal stuff we do. I was trying to implement it without using malloc. Are our lives gonna be impossible without malloc?? Please help. – letsc Oct 04 '10 at 14:56
  • 2
    Yes, it's gonna be impossible without malloc. – Ken Bloom Oct 04 '10 at 15:06
2

When malloc is used, the 'pointer' to that location is passed on to the variable (which is a pointer).

node* new = (node*)malloc(sizeof(node));

Every time this code is used a "new" location is pointed to. On the contrary, you are using normal variables, which have 'statically' allocated memory. That implies, whenever you refer to 'temp' or 'newtemp', you are referring to the same location EACH TIME.

Now you tell me how can you store a 10 element long list using just 3 (root, temp, newtemp) memory locations. You might want to draw out memory locations to imagine what is happening. But remember, each time you call 'temp' its the SAME memory location. For that we must use malloc (or calloc), for dynamically allocating memory.

In that case, we can make do with few pointers (far lesser than the memory used by the list).

rajatkhanduja
  • 974
  • 1
  • 9
  • 28
-1

Since nobody yet answered this question about the malloc part in the spirit of modern C (aka C99). If your compiler is conforming to that you have variable length arrays:

node myNodes[n];

where n has some value that is only determined at run time. You probably shouldn't overdo it with this approach since this is limited to the size of the stack, and otherwise you might encounter a stackoverflow.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • Still, the amount of available nodes is limited to the value of n at array initialization time. These VLA's are not dynamically growing, are they? It's just a syntactic sugar around a malloc() call, isn't it? – Seva Alekseyev Oct 05 '10 at 15:48
  • @Seva: no, they are not dynamically growing, but that wasn't the question. No they are not sugar around `malloc` but usually allocated on the stack and not the heap. – Jens Gustedt Oct 05 '10 at 17:40
  • Syntax sugar around alloca(), then :) – Seva Alekseyev Oct 05 '10 at 19:40
  • @Seva: no not exactly either, since first the scope of such an allocation is, well, the scope and not the function. And then `alloca` is not part of standard C, thus even less portable than assuming VLA and C99 ;) – Jens Gustedt Oct 05 '10 at 19:44
  • Um, the scope of allocation is an implementation detail, isn't it? One can be sure that the VLA is not allocated until the moment of initialization (since the desired size is only known then), but how do you know that it's not freed together with the rest of the stack frame when the function returns? That's how alloca() behaves IIRC. – Seva Alekseyev Oct 06 '10 at 14:16
  • @Seva: It *is* freed when you leave the scope of its validity, maybe even before you leave the function. This is the idea of scoping variables. On the other hand if the scope is `main` you can do all stuff you want with it, call functions whatever, until you exit from there. As someone said "You can avoid `malloc` but not for free" or coined in other terms the compiler has to determine the scope of your allocations somehow. – Jens Gustedt Oct 06 '10 at 14:33
  • Provably wrong. I just compiled (with GCC on Mac) a small snippet with a VLA inside an arbitrary scope, and on the exit of the scope, there was a big fat nothing. Like I said, the moment of actual freeing is an implementation detail. Since the VLA is not lexically visible outside of its scope, you cannot tell if it still occupies the memory. And freeing stack variables comes for free (pun intended) with the function exit, since you have to increase the SP in the epilogue anyway. – Seva Alekseyev Oct 06 '10 at 15:11
  • @Seva: I am not sure that I understand what you are trying to prove and in what your findings contradict what I was saying. What I simply tried to say is that you should not use a stack variable when it has fallen out of scope. In terms of VLA this is even more dangerous than for other types of variables, since the stack layout may have changed when you re-enter the scope, `for`-loops, `goto`, `longjmp` must be done quite carefully. But I also think that this discussion deviates too much from the original question. – Jens Gustedt Oct 06 '10 at 15:39
  • True, this went way into off-topic territory. I took an exception to your statement that VLAs allocation/freeing behavior is somehow different from that of alloca(). It's the same. – Seva Alekseyev Oct 06 '10 at 15:45