473,762 Members | 8,598 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Linked list allocation

Consider implementing a (doubly) linked list.

The simplest strategy is to provide functions
item_t add_item(item_t predecessor);
void delete_item(ite m_t item);
where add_item allocates memory for a new list item and returns it (or
NULL), and delete_item frees that memory.

However, if at startup the program immediately adds a large number of
items to a list, then all those calls to malloc() become expensive.

An alternative I thought of was that add_item should allocate a block,
say of size (100 * size-needed-by-an-item), then use pointers inside
this block until the time comes to allocate a new block for 100 items.

The problem with this is that deleting items becomes a mess - you can
only free a block when all 100 items in it have been deleted, so in the
worst case (where the programmer allocates 101 items, frees 99, adds
101, ...) you end up with for all intents and purposes a memory leak.

Is there a better solution?

Dec 17 '07 #1
8 2729
Jeff wrote:
) Consider implementing a (doubly) linked list.
)
) The simplest strategy is to provide functions
) item_t add_item(item_t predecessor);
) void delete_item(ite m_t item);
) where add_item allocates memory for a new list item and returns it (or
) NULL), and delete_item frees that memory.
)
) However, if at startup the program immediately adds a large number of
) items to a list, then all those calls to malloc() become expensive.
)
) An alternative I thought of was that add_item should allocate a block,
) say of size (100 * size-needed-by-an-item), then use pointers inside
) this block until the time comes to allocate a new block for 100 items.
)
) The problem with this is that deleting items becomes a mess - you can
) only free a block when all 100 items in it have been deleted, so in the
) worst case (where the programmer allocates 101 items, frees 99, adds
) 101, ...) you end up with for all intents and purposes a memory leak.
)
) Is there a better solution?

It's very difficult for a solution to be strictly 'better' than another
solution. So, you'll need to examine several solutions and see which best
fits your needs.

For example: With your alternative, you can reuse spots within a block if
you can mark them 'empty'. This induces an extra cost of searching for
empty blocks, however.

For another example: You can store groups of items, together with a count,
into larger blocks. This is tricky to get right, though, and you need to
move memory inside a block around when deleting or adding items.

For yet another example: You can periodically 'rehash' the list, sticking
it into one or more big blocks sequentially. Like defragmenting a filesystem.
SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
Dec 17 '07 #2
Jeff Bown <no****@nospam. invalidwrites:
Consider implementing a (doubly) linked list.

The simplest strategy is to provide functions
item_t add_item(item_t predecessor);
void delete_item(ite m_t item);
where add_item allocates memory for a new list item and returns it (or
NULL), and delete_item frees that memory.

However, if at startup the program immediately adds a large number of
items to a list, then all those calls to malloc() become expensive.
A better solution is sometimes to embed the list elements
directly in the elements being added to the list. If each
element is only on at most a fixed number of lists, this approach
is cheaper in terms of the number of necessary allocations.
--
Ben Pfaff
http://benpfaff.org
Dec 17 '07 #3
Jeff Bown wrote:
>
Consider implementing a (doubly) linked list.

The simplest strategy is to provide functions
item_t add_item(item_t predecessor);
void delete_item(ite m_t item);
where add_item allocates memory for a new list item and returns it (or
NULL), and delete_item frees that memory.

However, if at startup the program immediately adds a large number of
items to a list, then all those calls to malloc() become expensive.

An alternative I thought of was that add_item should allocate a block,
say of size (100 * size-needed-by-an-item), then use pointers inside
this block until the time comes to allocate a new block for 100 items.

The problem with this is that deleting items becomes a mess - you can
only free a block when all 100 items in it have been deleted,
so in the
worst case (where the programmer allocates 101 items, frees 99, adds
101, ...) you end up with for all intents and purposes a memory leak.

Is there a better solution?
Yes.
The solution is to realise that the problem does not exist.

The scenario that you describe
of a whole bunch of malloc at startup
to the extent that it makes a noticable difference
and also of mallocing one big object
for parts of your list to occupy,
suggests that
you have no idea of why you're using a list intsead of an array.

The best use for a list,
is when you want to grow your data format
as data becomes available to the program.

Freeing a list isn't supposed to be difficult.

typedef struct list_node {
struct list_node *next;
void *data;
} list_type;

void list_free(list_ type *node, void (*free_data)(vo id *))
{
list_type *next_node;

while (node != NULL) {
next_node = node -next;
free_data(node -data);
free(node);
node = next_node;
}
}

--
pete
Dec 17 '07 #4
On Dec 17, 1:51 pm, Jeff Bown <nos...@nospam. invalidwrote:
Consider implementing a (doubly) linked list.

The simplest strategy is to provide functions
item_t add_item(item_t predecessor);
void delete_item(ite m_t item);
where add_item allocates memory for a new list item and returns it (or
NULL), and delete_item frees that memory.

However, if at startup the program immediately adds a large number of
items to a list, then all those calls to malloc() become expensive.

An alternative I thought of was that add_item should allocate a block,
say of size (100 * size-needed-by-an-item), then use pointers inside
this block until the time comes to allocate a new block for 100 items.

The problem with this is that deleting items becomes a mess - you can
only free a block when all 100 items in it have been deleted, so in the
worst case (where the programmer allocates 101 items, frees 99, adds
101, ...) you end up with for all intents and purposes a memory leak.

Is there a better solution?
The usual idea is to maintain a free list where deleted cells are held
pending future allocations. There aren't many cases where it would pay
to return blocks to the malloc() heap. Unused free blocks will be
paged out in due course, where they consume only some swap space - of
interest only for _really_ long lists.

Pete's rather condescending suggestion that you don't need lists and
ought to use vectors instead has a flaw: O(1) time deletion of an
arbitrary element can't be accomplished with a vector. It's perfectly
reasonable to build up a big list at program startup if e.g. future
computations involve decimating the list by arbitrary deletions.
Dec 18 '07 #5
On Mon, 17 Dec 2007 19:51:32 +0100 (CET), Jeff Bown
<no****@nospam. invalidwrote:
>Consider implementing a (doubly) linked list.

The simplest strategy is to provide functions
item_t add_item(item_t predecessor);
void delete_item(ite m_t item);
where add_item allocates memory for a new list item and returns it (or
NULL), and delete_item frees that memory.

However, if at startup the program immediately adds a large number of
items to a list, then all those calls to malloc() become expensive.

An alternative I thought of was that add_item should allocate a block,
say of size (100 * size-needed-by-an-item), then use pointers inside
this block until the time comes to allocate a new block for 100 items.

The problem with this is that deleting items becomes a mess - you can
only free a block when all 100 items in it have been deleted, so in the
worst case (where the programmer allocates 101 items, frees 99, adds
101, ...) you end up with for all intents and purposes a memory leak.

Is there a better solution?
Your description is a little confusing - to me anyway, and
perhaps to others judging from the variety of answers you got.

Ordinarily a linked list (single, or double) consists of nodes,
where a node (doubly linked) looks something like this:

struct node {
node * prev; /* Link to previous node */
node * next; /* Link to next node */
void * data; /* generic pointer to data */
};

and the prototypes look something like this:

node * add_item(node * predecessor, void * datum);
void delete_item(nod e * item);

Usually you would have a few more routines but set that aside for
the moment. The point I am after is that you seem to be mixing
up nodes and data.

Now, supposing these are your prototypes, how do you go about
implementing them? I will suppose that you can write the code
for inserting and deleting nodes from linked lists. The question
at hand is: what about storage allocation and deallocation? It
is important to recognize that there are two different kinds of
things being allocated and freed, nodes and data.

A generic linked list package shouldn't be responsible for
allocating or freeing data, though there are standard techniques
that can be used.

For nodes a common technique is to (a) use a free list, and (b)
allocate blocks of nodes, link them together, and add them to the
free list. When adding items nodes are popped off the free list;
when deleting items nodes are pushed onto the free list.

HTH. HAND.

Dec 18 '07 #6
Jeff Bown wrote:
Consider implementing a (doubly) linked list.

The simplest strategy is to provide functions
item_t add_item(item_t predecessor);
void delete_item(ite m_t item);
where add_item allocates memory for a new list item and returns it (or
NULL), and delete_item frees that memory.

However, if at startup the program immediately adds a large number of
items to a list, then all those calls to malloc() become expensive.

An alternative I thought of was that add_item should allocate a block,
say of size (100 * size-needed-by-an-item), then use pointers inside
this block until the time comes to allocate a new block for 100 items.

The problem with this is that deleting items becomes a mess - you can
only free a block when all 100 items in it have been deleted, so in the
worst case (where the programmer allocates 101 items, frees 99, adds
101, ...) you end up with for all intents and purposes a memory leak.

Is there a better solution?
You can use a pool of linked list structs, and some malloc
implementations actually create a sort of pool for objects of the same
size. Perhaps a different type of data structure would be a better fit
though. Often times programmers will use a linked list when an array of
structs will do.

There are also certain advantages to using a linked-list pool, or a
specialized pool for any data structure. For instance if you're dumping
a tree or linked list to the disk, and want to restore with minimal
relocation and cost for the ability to dump the data structure to the
disk, and restore. For the relocation you generally want to use an
optional part of C99 (an intptr_t or uintptr_t) though.
George
Dec 19 '07 #7
On Dec 17, 9:34 pm, c...@tiac.net (Richard Harter) wrote:
On Mon, 17 Dec 2007 19:51:32 +0100 (CET), Jeff Bown

<nos...@nospam. invalidwrote:
Consider implementing a (doubly) linked list.
The simplest strategy is to provide functions
item_t add_item(item_t predecessor);
void delete_item(ite m_t item);
where add_item allocates memory for a new list item and returns it (or
NULL), and delete_item frees that memory.
However, if at startup the program immediately adds a large number of
items to a list, then all those calls to malloc() become expensive.
An alternative I thought of was that add_item should allocate a block,
say of size (100 * size-needed-by-an-item), then use pointers inside
this block until the time comes to allocate a new block for 100 items.
The problem with this is that deleting items becomes a mess - you can
only free a block when all 100 items in it have been deleted, so in the
worst case (where the programmer allocates 101 items, frees 99, adds
101, ...) you end up with for all intents and purposes a memory leak.
Is there a better solution?

Your description is a little confusing - to me anyway, and
perhaps to others judging from the variety of answers you got.

Ordinarily a linked list (single, or double) consists of nodes,
where a node (doubly linked) looks something like this:

struct node {
node * prev; /* Link to previous node */
node * next; /* Link to next node */
void * data; /* generic pointer to data */

};

and the prototypes look something like this:

node * add_item(node * predecessor, void * datum);
void delete_item(nod e * item);

Usually you would have a few more routines but set that aside for
the moment. The point I am after is that you seem to be mixing
up nodes and data.

Now, supposing these are your prototypes, how do you go about
implementing them? I will suppose that you can write the code
for inserting and deleting nodes from linked lists. The question
at hand is: what about storage allocation and deallocation? It
is important to recognize that there are two different kinds of
things being allocated and freed, nodes and data.

A generic linked list package shouldn't be responsible for
allocating or freeing data, though there are standard techniques
that can be used.

For nodes a common technique is to (a) use a free list, and (b)
allocate blocks of nodes, link them together, and add them to the
free list. When adding items nodes are popped off the free list;
when deleting items nodes are pushed onto the free list.

HTH. HAND.
I see some list add item using ** such as
node * add_item(node ** predecessor, void * datum);

Any benefit compare to node * add_item(node * predecessor, void *
datum);?
Dec 26 '07 #8
On Wed, 26 Dec 2007 11:20:26 -0800 (PST), henry
<he**********@y ahoo.comwrote:
>On Dec 17, 9:34 pm, c...@tiac.net (Richard Harter) wrote:
>On Mon, 17 Dec 2007 19:51:32 +0100 (CET), Jeff Bown

<nos...@nospam .invalidwrote:
>Consider implementing a (doubly) linked list.
>The simplest strategy is to provide functions
item_t add_item(item_t predecessor);
void delete_item(ite m_t item);
where add_item allocates memory for a new list item and returns it (or
NULL), and delete_item frees that memory.
>However, if at startup the program immediately adds a large number of
items to a list, then all those calls to malloc() become expensive.
>An alternative I thought of was that add_item should allocate a block,
say of size (100 * size-needed-by-an-item), then use pointers inside
this block until the time comes to allocate a new block for 100 items.
>The problem with this is that deleting items becomes a mess - you can
only free a block when all 100 items in it have been deleted, so in the
worst case (where the programmer allocates 101 items, frees 99, adds
101, ...) you end up with for all intents and purposes a memory leak.
>Is there a better solution?

Your description is a little confusing - to me anyway, and
perhaps to others judging from the variety of answers you got.

Ordinarily a linked list (single, or double) consists of nodes,
where a node (doubly linked) looks something like this:

struct node {
node * prev; /* Link to previous node */
node * next; /* Link to next node */
void * data; /* generic pointer to data */

};

and the prototypes look something like this:

node * add_item(node * predecessor, void * datum);
void delete_item(nod e * item);

Usually you would have a few more routines but set that aside for
the moment. The point I am after is that you seem to be mixing
up nodes and data.

Now, supposing these are your prototypes, how do you go about
implementing them? I will suppose that you can write the code
for inserting and deleting nodes from linked lists. The question
at hand is: what about storage allocation and deallocation? It
is important to recognize that there are two different kinds of
things being allocated and freed, nodes and data.

A generic linked list package shouldn't be responsible for
allocating or freeing data, though there are standard techniques
that can be used.

For nodes a common technique is to (a) use a free list, and (b)
allocate blocks of nodes, link them together, and add them to the
free list. When adding items nodes are popped off the free list;
when deleting items nodes are pushed onto the free list.

HTH. HAND.

I see some list add item using ** such as
node * add_item(node ** predecessor, void * datum);

Any benefit compare to node * add_item(node * predecessor, void *
datum);?
Actually there can be. If the argument points directly to the
predecessor node the implementation cannot change the location of
the predecesssor node; if the argument is an indirect pointer
(**) the implementation can change the location. The down side,
such as it is, is that the code goes through an extra level of
indirection.

Dec 27 '07 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
2968
by: Francis Bell | last post by:
Hello, I'm trying to read data from a file and then insert that into a linked list. The way I have it, the program compiles, however, I'm getting a segmentation fault error message when I run the program. I'm fairly new at the pointer business, and I'd appreciate any advice. Here's my code: int main() { ifstream fin;
7
2167
by: dam_fool_2003 | last post by:
friends, I wanted to learn the various ways of inserting a single list. so: Method 1: #include<stdlib.h> #include<stdio.h> struct node { unsigned int data; struct node *next;
7
2612
by: Kieran Simkin | last post by:
Hi all, I'm having some trouble with a linked list function and was wondering if anyone could shed any light on it. Basically I have a singly-linked list which stores pid numbers of a process's children - when a child is fork()ed its pid is added to the linked list. I then have a SIGCHLD handler which is supposed to remove the pid from the list when a child exits. The problem I'm having is that very very occasionally and seemingly...
4
3604
by: JS | last post by:
I have a file called test.c. There I create a pointer to a pcb struct: struct pcb {   void *(*start_routine) (void *);   void *arg;   jmp_buf state;   int    stack; };   struct pcb *pcb_pointer;
32
5947
by: Clunixchit | last post by:
How can i read lines of a file and place each line read in an array? for exemple; array=line1 array=line2 ...
14
1861
by: fool | last post by:
Dear group, Thanks for all those who helped previously. Now I get some value printed. Is that the value of the list getting printed? Am I really polluted the list? Previous thread link (sorry for google) http://groups.google.com/group/comp.lang.c/browse_thread/thread/346d99317e6b772b/578ac16a2ed4ed35?hl=en#578ac16a2ed4ed35
51
8647
by: Joerg Schoen | last post by:
Hi folks! Everyone knows how to sort arrays (e. g. quicksort, heapsort etc.) For linked lists, mergesort is the typical choice. While I was looking for a optimized implementation of mergesort for linked lists, I couldn't find one. I read something about Mcilroy's "Optimistic Merge Sort" and studied some implementation, but they were for arrays. Does anybody know if Mcilroys optimization is applicable to truly linked lists at all?
6
2148
by: mattmao | last post by:
Okay, this is just my exercise in order to prepare for the coming assignment regarding the damned Linked List issue... The task is simple and I am about to finish it. However, I couldn't go around one last bit: how to print out the elements? Here is so far what I've got: #include <stdio.h> #include <stdlib.h> struct intRecord
4
2941
by: arnuld | last post by:
This program follows from the section 6.5 of K&R2 where authors created a doubly-linked list using a binary-tree based approach. The only thing I have rewritten myself is the getword function. I am using it because there are many concepts involved in this program that I want to understand like: 1.) degree of efficiency of this program as compared to sort using hash-table based approach. 2.) Keeping the program well structured so...
0
9554
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9378
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9989
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
7360
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6640
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5268
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3914
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
3510
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2788
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.