-2

I am having the following situation, an array of structs passed to a function. So, inside function I'm dealing with double pointer. Now I am confused, it is working but I'm not sure why is it working on both ways(I like to try things out in different ways so I would get a better understanding of it).

The array is received as argument as: Rules **rules_array

Example 1:

rules_array = (Rules**) malloc(alloc_size*sizeof(Rules*));

By doing like in example 1, I would expect to make one more loop to allocate memory for all these structs(array elements) that are going to be pointed from Rules* elements, but obviously it's not needed and that's what I don't understand.

Example 2 (which makes more sense to me):

*rules_array = (Rules*) malloc(alloc_size*sizeof(Rules));

Thanks in advance!

trincot
  • 317,000
  • 35
  • 244
  • 286
Johnnie W
  • 127
  • 1
  • 1
  • 9
  • It is unclear what you mean. Could you show a compiled example where these allocations are used and what is the problem with them? – Vlad from Moscow Feb 02 '16 at 14:16
  • A pointer is not an array (and vice versa)! – too honest for this site Feb 02 '16 at 14:21
  • As written, I don't understand why is the 1st example behaving just like the 2nd one? It's simply working, like it's skipping one "pointing level".. – Johnnie W Feb 02 '16 at 14:23
  • It might work the same _within the function_ that receives `rules_array` as an argument. _But_ presumably said array was passed as a pointer-to-pointer so the function could modify the underlying pointer to reflect its newly allocated memory. That simply will not happen in the first case. Only the local copy of the argument will be modified, within the function's scope. – underscore_d Feb 02 '16 at 14:26
  • @Olaf exactly, that's why I'm confused, why is actually the 1st example working – Johnnie W Feb 02 '16 at 14:27
  • @underscore_d ahhh okay, that actually makes sense. So I'm not able to access the allocated memory outside the function? – Johnnie W Feb 02 '16 at 14:30
  • You would be able to access it if you had a pointer to it; it still exists; you just don't know _where_. Again, the first option does not modify the locally passed pointer-to-pointer, so the address of the newly allocated memory is not knowable outwith the function. Both methods produce the same effective results _within_ the function, but presumably the reason you pass in a _pointer-to-_ pointer is that you want to update the 'pointed pointer' with the new allocated memory and use it _outwith_ the function. (Things like this make me appreciate C++ references a lot more, in retrospect...) – underscore_d Feb 02 '16 at 14:35
  • Yeah exactly, thanks for expl. But is there some explanation why are the both examples behaving the same inside the function? So far what I've learned, the example one shouldn't be behaving same as example two. Anyway could you maybe give me an explanation why I'm not able to access the modified content outside function?(getting some junk code - using same prinft with one "pointing level" lower) http://prntscr.com/9y2rm1 – Johnnie W Feb 02 '16 at 14:48
  • @JohnnieW We'll need to see a [Minimal, Complete, Verifiable Example](http://stackoverflow.com/help/mcve) to answer that. – dbush Feb 02 '16 at 14:58
  • Define "working"! From the information given, the clear statement is: it does not work. It will not even compile. That's why you are supposed to provide a [mcve]. Oh, and: do not cast the result of `malloc` & friends in C! – too honest for this site Feb 02 '16 at 15:00
  • The reason why they both work the same within the function is that they would both allocate and point at the 'same' (quotes because probably different physical addresses between runs, but forget that) buffer. But only the 2nd method allows the address of that buffer to leave the function's scope, by writing it to a dereferenced pointer passed by - and thus returned to - the caller. I don't know how many more ways I can rephrase this, and I'm not going to invest in a more general explanation of local variables when they're a basic facet of the language. – underscore_d Feb 02 '16 at 15:08
  • @underscore_d yeah it's fully understandable :) thx – Johnnie W Feb 03 '16 at 08:53

1 Answers1

2

The second example is correct.

You want to create a 1 dimensional array of Rules. So you allocate space for alloc_size*sizeof(Rules) bytes. Because your function is (presumably) getting passed the address of a pointer (i.e. a Rules **), you want to assign the allocated memory to the dereferenced pointer, i.e. *rules_array. Then when the function returns, you have access to that memory.

The only thing that needs to change is to get rid of the cast. Casting the return value of malloc can mask other errors in your code. See Do I cast the result of malloc? for more details.

Your assumption about the first example is correct. That's part 1 of creating a 2 dimensional array, or more precisely an array of pointers, each of which will point to an array. In that case, you would either need to return rules_array and assign that to a Rules **, or pass the address of a Rules ** so that rules_array is a Rules *** and dereference it before assigning to it.

Community
  • 1
  • 1
dbush
  • 205,898
  • 23
  • 218
  • 273
  • @ZbynekVyskovsky-kvr000 - what compiler have you seen the warnings requiring a cast? I have never seen one on my C99 compiler, GCC and CLANG. – ryyker Feb 02 '16 at 14:15
  • 1
    @ZbynekVyskovsky-kvr000 Incorrect. In C++, the cast is needed. In C, a `void *` can freely be assigned to or from any non-function pointer. Using a cast can hide the fact that `stdlib.h` was not included. – dbush Feb 02 '16 at 14:15
  • Ya I get it, but according to some professor's weird standards we're obligated to cast -.- . Could you just explain me why is the 1st example behaving just like the 2nd one? It's simply working, like it's skipping one "pointing level".. – Johnnie W Feb 02 '16 at 14:22
  • 1
    @JohnnieW [Undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior). In the first case, you assign the allocated memory to a local variable, which is not the same as the variable in the calling function. When you return, the calling function variable points to garbage. You're "lucky" that it works and doesn't crash. If you rand [vangrind](http://valgrind.org) on that code, it would report that you're writing somewhere you shouldn't. – dbush Feb 02 '16 at 14:26
  • @dbush I was just about to do that :D thanks man for the explanation! – Johnnie W Feb 02 '16 at 14:31
  • @dbush What is funny, somehow I'm not able to access the same content even if I'm doing on the second way. I'm trying a prinft with just one "pointing level" lower, and I'm accessing some junk code still – Johnnie W Feb 02 '16 at 14:44
  • 1
    @JohnnieW Then post a more complete example that demonstrates the issue. – dbush Feb 02 '16 at 14:46
  • It is actually working, I just neglected a counter and thats where the problem was :) thanks ! – Johnnie W Feb 02 '16 at 15:35