0

I have a function that is supposed to be creating structures and storing them in an array of structures.

Lets say this is my structure:

struct str {
    ...
};

The function takes a parameter that looks like this:

struct str **ptr

Which is a pointer to a pointer that points to a structure if I get it right and I am supposed to set this parameter to be pointing to the first element of the array of structures which will be the first structure in that array.

So, if the parameter looks like this, that means that instead of having just an array of structures, I have an array of pointers that point to that structure, right?

Now I have declared the array of pointers to structures like this:

 struct str *structures[20];

because I am expecting to have 20 (pointers to )structures store there.

Then I have a loop that is allocating memory for the structures and is storing them in the array like this:

 struct str *structure;

 structure = malloc(sizeof(struct str));

Then I fill in the parameters of the structure I want like this:

structure->a = 1; structure->b = 2; .........

And I store it in the array like this:

structures[n] = structure;

And I make sure it is stored in the array at the position where I wanted it to be by printing a parameter from the structure each loop like this:

printf("%d\n", structures[7]->a);

My question is, how do I set the parameter of the function to be pointing to the first pointer to a structure in that array?

And did I get it right?

Also, the parameter needs to be taken from main.

And I need to work with these (pointers to)structures of the array outside this one function as well.

What will the parameter look like?

struct str *pointer; ?

Also, wouldn't it be possible to just point the pointer to the array itself and it should automatically be pointing to the first element in it?

So that I could then reference the nth member of the array via the pointer since I need to work with all of them later on?

I have looked at this thread, but I'm still a bit confused so I'd appreciate any feedback.

Community
  • 1
  • 1
Daeto
  • 440
  • 1
  • 6
  • 19

1 Answers1

0

Reading through this, I notice a few inconsistencies in your post:

Why create an array of pointers to your struct as opposed to a simple array of structs? That is, let's say you have this declaration for your struct:

struct myStruct {
    int x;
    int y;
};

If you want to create an array of those structs just do:

//dynamic
struct myStruct* myArray = malloc(20*sizeof(struct myStruct));
//static
struct myStruct* myArray[20];

Note that both of these return a pointer to the first element of the array (which is of type struct myStruct). Your array is an array of struct myStruct elements, not an array of struct myStruct*.

An array of struct myStruct elements with size 20 is, for practical purposes, nothing more than contiguous memory big enough to hold 20 struct myStruct elements and represented by the pointer to the first element. Since the memory is contiguous, you can access the 'nth' element of your array by myArray[0] or *(myArray+n) (the latter is possible because an "array" is nothing more than a pointer to the first element of contiguous memory... so "adding" 1 to a pointer of a given type gives you the memory address of the next element... which you deference using the * operator to get the element itself).

It'll be much easier (not to mention much faster) to allocate memory for your array of structs once rather than creating an array of pointers to your structs. And then modify them in place.

So a function that takes in the array and increments that 5th and 6th elements might look like:

void modifyStructs (struct myStruct* myArray)
{
    //modify the fifth struct:
    ++myArray[4].x;
    //modify the sixth struct:
    ++myArray[5].x;
}

The few times you'll want an array of pointers are when:

  1. Creating a multidimensional array. Even then, this is really bad for cache performance... it's better to create a 1D array and define a macro for how to access the elements. BLAS/LAPACK do this.
  2. Creating an array where some elements should be NULL and you're not using structs. If you're using structs, it's much better to just define a field to identify whether your struct has been populated yet and use a simple array of structs.
  3. Creating an array to access a huge number of items but you don't want to allocate all that memory yet. Here, you don't really have a choice.
alfalfasprout
  • 243
  • 1
  • 12
  • The reason why I thought that I need to create an array of pointers to structs was because of the function parameter struct str **ptr which is a pointer to a pointer to a struct and this parameter is supposed to be pointing to the first element of the array. So this is why I concluded that it must indeed be an array of pointers to struct instead of just an array of structs. Note that I cannot modify this function parameter. But now that I think about it, I could set up an array of structs, and set the pointer to pointer be equal to the array since it is a pointer to the first element? – Daeto Nov 29 '15 at 17:03
  • Yep, you can simply grab a pointer to the array and it'll be of type struct str**. Makes things way easier than having to allocate memory for elements individually. – alfalfasprout Nov 29 '15 at 19:36
  • Okay. I have an array of structures struct str structures[ ]; inside the function I am currently working with. Each element of the array is filled with a dynamically allocated structure. This function is expecting an argument struct str **ptr from main and is supposed to make it point to the first element of the array. So I have created struct str **ptr; in my main function and I am passing it into this function as (ptr) and inside I set it equal to the name of the array of structures. However, when I then want to access the array via this pointer from main, it doesnt work. What went wrong? – Daeto Nov 29 '15 at 20:29
  • What I don't understand is why you're dynamically allocating each element in the array if you have a simple array of structs. Here's what I mean: `struct str *structures = malloc(20*sizeof(struct str));` already allocates enough memory for your entries. Let's say you have a function `void myfn(struct str**)`. Then all you need to do to call it is `myfn(&structures);`. If you really need an array of pointers, then you just do: `struct str **structures = malloc(20*sizeof(struct str*));` `for(int i=0 ; i<20 ; ++i){structures[i] = malloc(sizeof(struct str));}` Then you can then pass it directly. – alfalfasprout Nov 29 '15 at 21:37
  • ^note that in either of the approaches above, working with the array inside the function should be the same. – alfalfasprout Nov 29 '15 at 21:43
  • I am allocating the memory for each structure separately because I was asked to. In the end, it is equivalent to your method, isn't it? Nope I do not need an array of pointers. I just need a struct str **pointer; from my main function to point to the structure inside the other function as I need to be able to work with that structure in other parts of the program. – Daeto Nov 29 '15 at 21:55
  • An array of struct pointers is the same exact thing as a pointer to a pointer to a struct (in the first case, it points to the first element of the array, in the second, it can point to any random struct pointer). So, to properly access the structs in your array you'll need to use the second approach in my comment above. This sounds exactly like what you want to do (you'll end up with a struct **str that you can pass to your function and use). Can you paste code? That'll help a lot. – alfalfasprout Nov 29 '15 at 22:25
  • This is what I am trying to do. - http://codepad.org/hXTavY84 Sorry I wrote it in python but this is supposed to be C and just a quick illustration. – Daeto Nov 29 '15 at 22:44
  • Alright, does [this](http://goo.gl/Hxdg4K) do what you want? Basically what you wrote except without extraneous allocations. Compiles without any added flags on gcc/clang/icc. – alfalfasprout Nov 29 '15 at 23:55
  • I really appreciate the code you posted but the array needs to be created inside that function not declared in main like this struct str **ptr = malloc(NUM_ENTRIES * sizeof(struct str *)); The format needs to be how I wrote it but there seems to be something wrong when I try to pass the **pointer as an argument of the function. – Daeto Nov 30 '15 at 00:24
  • Alright, I think I understand what you want then. Check out [this](http://goo.gl/jX7zsg) version. Here, you pass a pointer to your struct array (which is NULL initially) and all initialization is done inside the function. – alfalfasprout Nov 30 '15 at 00:49
  • Almost, the way I did it was that I have intialized the structure like this inside the function struct str structures[ n ]; and all I need right now, is a pointer from the main function to point to this when I pass it as an argument struct str **ptr . Can this be done? I feel like I am losing my mind over this : D – Daeto Nov 30 '15 at 00:58
  • Yeah, well the problem is that if you initialize the structure using `struct str structures[NUM_ENTRIES]` it's allocated on the stack. So as soon as the function exits, the memory address that points to that array will be invalid. Let's say you're inside the function that takes "struct str **myPtr" as an argument. And you have a pointer `struct str *mainPtr = NULL` you declared in main. Then inside, to allocate/initialize the array, just do `*myPtr = malloc(sizeof(struct str)*NUM_ENTRIES)`. This way you can use the pointer you declared in main by passing it as &mainPtr;. – alfalfasprout Nov 30 '15 at 01:10
  • Okay. I did struct str **structures; structures = malloc(nxsizeof(struct str)); And filled it. Now, how do I point to this array using a pointer from main function? No matter how I pass the argument, nothing works. – Daeto Nov 30 '15 at 01:21
  • But how do I then populate it with the other (already allocated) structures if I declare it like this inside the function? – Daeto Nov 30 '15 at 01:27
  • Can you paste your code again? Just to see what it looks like now. – alfalfasprout Nov 30 '15 at 01:34
  • I just realized I might have been wrongly allocating the structures the array is supposed to hold. They should be allocated on the heap I guess if I want to use them outside this function, but I have been declaring them like this struct str structure; and then innitializing them via a function that takes their &structure as an argument. Maybe I should have used struct str *structure; structure = malloc.... instead? – Daeto Nov 30 '15 at 01:44
  • In your main function you want a variable of type struct *str. Let's called it "mainArr". This will be your array of structs. In your main, just set it to NULL to start. Eg; don't allocate anything at all in main. Your init function needs to take in a variable of type struct **str. We'll call it "structarrptr". You'll pass mainArr to init(struct str **structarrptr) by calling the function in the following way: init(&mainArr). This way, you can allocate an array using the pointer you declared in main and henceforth main will be see the changes you applied in init(). (continued...) – alfalfasprout Nov 30 '15 at 01:49
  • (...continued) Inside init() you need to do only one allocation. You need to allocate an array of struct str objects of length 20 (or whatever). This array (which you remember is the pointer to the first object) will be stored at the address pointed to by structarrptr. So... your allocation inside init() will be *structarrptr = malloc(20 * sizeof(struct str)); To modify the elements of this array *within* init() you'll do something like: (*structArrPtr)[1].x = 5; – alfalfasprout Nov 30 '15 at 01:51
  • Thanks very much for this explanation! I will try it out tomorrow as I need to go now and will let you know how it worked out. Thanks again for your replies and patience : ) Hope you have a great day! – Daeto Nov 30 '15 at 01:56
  • Yes it works as it should now. Or at least appears to be working as it should. Thanks a lot : ) – Daeto Nov 30 '15 at 17:51