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..

11
  • 7
    A linked list without using malloc? Is that even possible? Commented Oct 4, 2010 at 14:46
  • Why?? I am not sure but why cant it possible when we have stack allocation and well defined copy constructor??? Commented Oct 4, 2010 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. Commented Oct 4, 2010 at 14:49
  • 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. Commented Oct 4, 2010 at 19:34
  • 1
    This is all about unwillingness to check the malloc() return value for zero and implement out-of-memory logic, isn't it? :) Commented Oct 5, 2010 at 15:51

8 Answers 8

22

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.

Sign up to request clarification or add additional context in comments.

Comments

15

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.

2 Comments

"You can avoid malloc but not for free" makes a very bad pun :D
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.
7

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.

2 Comments

You are actually missing one, which is easier to use than both of these: VLA.
@Nathan: sorry, variable length array, please see my answer
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*.

2 Comments

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. You are right. Some of the same tricks I came up with for stackoverflow.com/questions/3002764/… could be used here as well.
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 

1 Comment

Two words - "custom allocator" - would've sufficed. That avoids malloc() in letter but not in spirit.
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.

2 Comments

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.
Yes, it's gonna be impossible without malloc.
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).

Comments

-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.

9 Comments

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: 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.
Syntax sugar around alloca(), then :)
@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 ;)
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.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.