3

I have a simple structure like

typedef struct myPtr myPtr;

typedef struct example {

  myPtr* list_ptr;//just a list of pointers, doesnt matter for now
  int nb_elements;
  int nb_mllc;
} example;

and in my c file example.c i have implemented all functions needed for this, to malloc, realloc, free and add entries...

example* create_example(int num){

   example* ex = malloc(sizeof(example));
   if (ex == NULL) //do some error catching

   ex->list_ptr = malloc(sizeof(myPtr) * num);
   if (ex->list_ptr == NULL) //do some error catching

   ex->nb_mllc = num;
   ex->nb_elements = 0;

   return ex;
}

Now if I want to iterate over the entries of the structure, I know I can simply do it by using a for loop

  example* ex = create_example(10);
  //lets assume the entries are filled, so 
  // ex->nb_elements is greater than 0

 for (int i=0; i<ex->nb_elements; i++) //... do stuff

However I was wondering if it is possible to write a function, such that I iterate over the entries without knowing anything about the structure. So I am in another c file "another_file.c" and I want simply to not care about the structure itself, so just create it and then call a function like iterate_over, so skipping writing this loop, since then I also need to know how the structure variables look like in my "another_file.c" file. So something like

  example* ex = create_example(10);
  iterate_over(ex); //but then I dont know how to access the current element from here
  //or do something like

  while(iterate_over(ex) != NULL) //saying it is empty..

Can someone give me a hint how to do this, as I dont know how can I hide all the indexes and information needed here..

malajedala
  • 867
  • 2
  • 8
  • 22
  • `if (ex == NULL) //do some error catching` are you trying to say that you've omitted error handling functionality? If so, just add a `;` at the end, so that it is not confused that the next statement executes with the `if`. – ctrl-shift-esc Dec 01 '16 at 09:56
  • 2
    No i just wanted to let people know i am aware of null pointers and I am handling them but i wanted to keep the code short and only for the important parts for my question – malajedala Dec 01 '16 at 09:59
  • Take a look here http://stackoverflow.com/questions/1154709/how-can-i-hide-the-declaration-of-a-struct-in-c – Raskayu Dec 01 '16 at 09:59
  • @malajedala for brevity it's preferable to omit error checking completely rather than having half baked and incomplete code. But then you should mention "Error checking omitted for brevity" otherwise you likely will get comments such as "you should check the return value of malloc" etc. – Jabberwocky Dec 01 '16 at 10:03
  • Thank you michael. I will consider this in future posts, sorry about that. I just wanted to avoid exactly comments about not handling errors, so in future I will do it your way – malajedala Dec 01 '16 at 10:18

3 Answers3

0

I finally ran over some nice details, that i can put my loop into a macro, i think this is something i was seeking for.

However, i found an example of a foreach loop for an array in a macro

#define foreach(item, array) \
  for(int keep = 1, \
        count = 0,\
        size = sizeof (array) / sizeof *(array); \
    keep && count != size; \
    keep = !keep, count++) \
  for(item = (array) + count; keep; keep = !keep)

And to be honest I have no idea what is going on here, with keep= !keep and stuff, so can someone maybe relate me to some sources where I can find out what is going on here?

malajedala
  • 867
  • 2
  • 8
  • 22
0

A macro doesn't allow to hide information in the way you're seeking for, because it would have to be in the same compilation unit.
Consider writing this function in the separately compiled example.c:

myPtr *iterate_over(example *ex, myPtr *item)
{
    if (!item) item = ex->list_ptr; // first
    else     ++item;                // next
    if (item-ex->list_ptr < ex->nb_elements) return item;
    return NULL;                    // no more
}

The extra parameter item tells the function whether to start iterating from the first entry or to yield the next entry.

Now, you can write this in another_file.c:

    typedef struct example example; // no need to know more about the structure
    example *create_example(int num);   // prototype, usually in example.h file
    myPtr *iterate_over(example *ex, myPtr *item);  // prototype, see above
    example *ex = create_example(10);
    …   // fill the entries
    myPtr *item;
    for (item = NULL; item = iterate_over(ex, item); )
        printf("%p\n", item);   /* do anything with item */

This way, we succeeded in iterating over the myPtr list independent from the list implementation example.

(Though, there's no information hiding in the reverse direction, because still example.c needs to know the structure size of myPtr. But this would be another question.)

Armali
  • 18,255
  • 14
  • 57
  • 171
0

If you want to use create_example(N) style function for creating several instances, maybe you could return array of pointers:

  example** ex = create_examples(N);
  if (ex)
  {
      for (int i=0; i<N; i++)
          do_something( ex[i] ); 
      free_examples(ex, N);
  }

Another way is ignore dedicated array allocation functions, and do the same stuff by regular way:

  example* ex[N];

  for (int i=0; i<N; i++)
  {
      ex[i] = create_example();      
  }
  ...

The later approach can be for example used with FILE* and other hidden structures, when you can not implement own 'array creation functions'.

SKi
  • 8,007
  • 2
  • 26
  • 57