-1

I am a beginner in programming C and need help with getting and setting values when I create a dynamic array of structures.

I have this struct for example:

struct opt{
    int size;
    Element* elements;
    CopyFunction copyElement;
};
typedef struct opt * Popt;

I want to use dynamic allocation and use malloc to allocate memory for 5 structs of type struct opt; I used this line:

Popt opt_t = (Popt)malloc(5*sizeof(struct opt));

I want to get and set values in these structures. If I think about that like OOP, I would like to get the values like this:

opt_t[2].size, opt_t[3].elements, opt_t[3].copyElement

How can I do it with C? I tried to use the following lines and its looking bad (my memory filled with garbage).

*((&(opt_t->size)+(2*sizeof(struct opt))))
*((&(opt_t->elements)+(3*sizeof(struct opt))))
*((&(opt_t->copyElement)+(3*sizeof(struct opt))))
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    Be aware that the `_t` suffix is most commonly used to indicate a type name (think `size_t`, `uint8_t`, `wchar_t` etc from the C standard, and many more from POSIX). It would probably be better not to use the suffix on variables; it has the potential to confuse those reading the code. It isn't actually wrong; it just sends the wrong message to people who've seen a lot of C code. – Jonathan Leffler Dec 11 '16 at 21:50
  • See also [Is it a good idea to typedef pointers](http://stackoverflow.com/questions/750178/is-it-a-good-idea-to-typedef-pointers) — the succinct answer is "No". – Jonathan Leffler Dec 11 '16 at 21:57

2 Answers2

2

If I think about that like OOP, I would like to get these values:

opt_t[2].size, opt_t[3].elements, opt_t[3].copyElement

How can I do it with C?

Like in 'OOP':

opt_t[2].size
opt_t[3].elements
opt_t[3].copyElement

Did you try it? What went wrong? You don't need to scale pointers by the size of the object in normal C, so the notations like *((&(opt_t->size)+(2*sizeof(struct opt)))) are going in the wrong direction completely. It would be possible to dissect what they are doing, but it is not what was intended and invokes undefined behaviour by accessing memory outside the bounds of what was allocated. (If you really want to know what they do, leave a comment and I'll expound, but you should explain what you think they do in your comment.)

If you wanted to, you could use:

(*(opt_t + 3)).copyElement

You index the pointer, dereference it, and then apply the member access. But it is simpler to use opt_t[3].copyElement instead.


Also, as I noted in two comments:

  1. Be aware that the _t suffix is most commonly used to indicate a type name (think size_t, uint8_t, wchar_t etc from the C standard, and many more from POSIX). It would probably be better not to use the suffix on variables; it has the potential to confuse those reading the code. It isn't actually wrong; it just sends the wrong message to people who've seen a lot of C code.

  2. See also Is it a good idea to typedef pointers, to which the succinct answer is 'No' (or 'usually No'). As demonstrated by responses to this question, such typedefs can lead to confusion.


It has also been suggested that there's possibly some confusion about memory allocation in the question. Since it says:

I want to use dynamic allocation and use malloc to allocate memory of 5 structs of type struct opt

and promptly proceeds to demonstrate an acceptable way of doing exactly that, albeit with a cast which many people despise but which doesn't worry me anywhere near as much as it seems to upset other people, I don't see a need to comment further on memory allocation. I quietly assume there will be a call free(opt_t) or equivalent somewhere when the code has finished with the allocated space — and that if there is space allocated for the elements members, that space will be freed first.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • You might want to comment on the poor choice of identifier name: `opt_t` should be used to name a type, not a variable. The `Popt` pointer `typedef` will cause problems too, sooner or later. It is also not obvious if the OP knows that `malloc()` returns uninitialized memory. – chqrlie Dec 12 '16 at 01:43
0

You need a double pointer:

Popt *opt_t;

//do error checking of the return value of malloc
opt_t = malloc(5 * sizeof(opt_t)); //5 pointers
for(i = 0; i < 5; i++){
    opt_t[i] = malloc(sizeof(opt)); //each struct
}

In the end free memory:

for(i = 0; i < 5; i++){
    free(opt_t[i]);
}
free(opt_t);
  • Don't forget you might have to free all the pointers in each `Popt` and whatever they point at and so on. Its wise to encapsulate allocating and freeing `Popt` structs in `Popt_new` and `Popt_free`. It's also good to use `calloc` so you can tell the difference between an allocated pointer and garbage from malloc. – Schwern Dec 11 '16 at 22:03
  • @JonathanLeffler The question was to *dynamically* allocate memory. This way you can change *5* to any number instead of *Popt opt_t[5]* – γηράσκω δ' αεί πολλά διδασκόμε Dec 11 '16 at 22:08
  • @Schwern *Don't forget you might have to free all the pointers in each Popt...* What about the last 3 lines of code in my anwser. I am confused! – γηράσκω δ' αεί πολλά διδασκόμε Dec 11 '16 at 22:10
  • I think you've misread and misunderstood the question. Time will tell whether you're right or I'm right. The array is allocated; the choice of 5 was arbitrary in the `malloc()` call. – Jonathan Leffler Dec 11 '16 at 22:10
  • @γηράσκωδ'αείπολλάδιδασκόμε Note that `Popt.elements` is a pointer, probably to an array of `Element`s. That pointer points to memory and it has to be free'd else it will leak. Since it's an array, it's probable that `Popt` is responsible for that memory. So you need a `if( opt_t[i].elements != NULL ) { free(opt_t[i].elements) }`. This is also why it's better to use `calloc`, otherwise `opt_t[i].elements` will contain unallocated garbage, or to always initialize it with something. To guarantee a consistent create/destroy procedure is followed, it's best to put them into functions. – Schwern Dec 11 '16 at 22:23
  • @JonathanLeffler Holy moly!! You are completely right! It didn't cross my mind. – γηράσκω δ' αεί πολλά διδασκόμε Dec 11 '16 at 22:29
  • @Schwern Yes. In the end you need to free all the memories that have been allocated with malloc. But you are nitpicky in my anwser(which is not an anwser actually) only! Why didn't you post the comment to the accepted anwser too. The question was **not** how to free all memories. My 3 last lines were just a "bonus" – γηράσκω δ' αεί πολλά διδασκόμε Dec 11 '16 at 22:36
  • @γηράσκωδ'αείπολλάδιδασκόμε Answer or not, bonus material or not, it's still gonna leak memory. If it has caveats you have to list them or someone new to C won't know. I get concerned about teaching new folks poor memory management because memory problems are so common in C and yet so silent and easy to sweep under the rug. As for the accepted answer, they left memory allocation out of it. I suspect the OP needs help with both parts. – Schwern Dec 11 '16 at 22:50
  • @Schwern kudos to you for teaching new folks. But i know how things work in this site. I was a newbie once upon a time. You move the cursor onto the name. If the reputation is 5+ digit number you keep your comment to your self. Anyway. I dont have anything with you. You are correct to your observations. Have a nice day – γηράσκω δ' αεί πολλά διδασκόμε Dec 11 '16 at 23:02