0

So i have a linked list implementation and the struct looks like this:

typedef struct channel_db{

    unsigned int channel_id;                //Channel ID
    unsigned int node_id;                   //Node ID
    unsigned int channel_size;              //Channel data size (bytes)
    unsigned int channel_period;            //Channel data period (ms)
    double actual_bw;
    double required_bw;
    unsigned int compression;


    struct channel_db *next;
    struct channel_db *previous;

}CHANNEL_DB;

At some point in my code i need to search for all the nodes in the list that meet a certain requirement, for example actual_bw above a certain threshold and return all the channel_id's that meet that requirement. Is there a simple way to do this, or should i create another linked list just for these purposes?

AstroCB
  • 11,800
  • 20
  • 54
  • 68
Trota
  • 135
  • 3
  • 9
  • I'd just use a vector of pointers to node elements myself. I.e `vector listOfMatchingNodes;` – enhzflep Nov 20 '12 at 04:51
  • @enhzflep - That's a C++ feature. – beatgammit Nov 20 '12 at 04:52
  • Maybe do two passes: one to determine how many matches you have, and another to fill a dynamically allocated array with the matches. – Vaughn Cato Nov 20 '12 at 04:53
  • @enhzflep i forgot to mention i'm coding in C no C++. – Trota Nov 20 '12 at 04:54
  • 1
    return ptr to ptrs. end can be identified by *NULL* – tuxuday Nov 20 '12 at 04:54
  • @tjameson - bugger. Effective reading and comprehension seems to be a broken feature in me today. Totally missed reading the tags. :slinks-away: – enhzflep Nov 20 '12 at 04:55
  • Return an array of node pointers satisfying the criteria! – Swanand Nov 20 '12 at 04:56
  • the thing about returning an array, is that i would need to search the list twice. once to count the matches and allocate memory for the returning array, and a second one to actually fill the array with the values i want to return. i wanted something a bit more elegant, but maybe i'll have to do it this way – Trota Nov 20 '12 at 04:58

1 Answers1

1

The best thing about C is that it's small and simple. The worst thing about C is that it's small and simple.

There is no "built in" way to do what you want.

Sure you can define linked lists of integers, but you'll have to deal with freeing the list after it's no longer needed, which can be harder than it sounds. And such a list will have a 100% overhead for pointer space. Not a problem for most applications, but something to think about.

A better option is to use your own vector-like container that resizes itself as needed, "simulating" a C++ vector. This is the basic idea. NB: This code omits error handling.

Or as another recommendation said, implement a count in one pass, allocate exactly the counted numbewr of integers, then accumulate results in a second pass. Very stingy of memory, but obviously a run time penalty. Again not a big deal for small lists.

Or you could adopt this nice effort to build a container library for C.

Finally, you can sidestep returning a list entirely by providing instead a mapping primitive that accepts a callback function:

typedef int (*CHANNEL_DB_MAPPED_FUNCTION)(CHANNEL_DB *db, void *env);

int map_onto_channel_db(CHANNEL_DB *db, CHANNEL_DB_MAPPED_FUNCTION *f, void *env)
{
   CHANNEL_DB *p;

   // Assumes null terminated list. Adjust for circular lists if that's what you're using
   for (p = db; p; p = p->next)  {
     int rtn = f(p, env);
     if (rtn != 0) return rtn;
   }
   return 0;
}

The function can do anything you like and accumulate results into a record provided through the void pointer env. In particular it can do whatever you might have done with the returned list of integers. Of course this is less flexible than having the return value.

Community
  • 1
  • 1
Gene
  • 42,664
  • 4
  • 51
  • 82