0

So I got this question from a competition website and I am completely puzzled. Here it is:

Which of the following memory allocation code for p[10][10] confirms perfectly to classical definition of an array? The options are:

char **p;
int i;
p = (char**)malloc(10*sizeof(char*));
*p = (char*)malloc(10*sizeof(char));
for(i = i; i<10; i++)
    p[i] = p[0] +10*i;

char **p;
int i;
p = (char**)realloc(p, 10*sizeof(char*));
*p = (char*)realloc(p, 10*sizeof(char));
for(i = i; i<10; i++)
    p[i] = p[0] +10*i;

char **p = NULL;
int i;
p = (char**)malloc(10*sizeof(char*));
*p = (char*)malloc(10*sizeof(char));
for(i = i; i<10; i++)
    p[i] = (char*)realloc(p[i-1], 10*i*sizeof(char));

char **p;
int i;
p = (char**)malloc(10*sizeof(char*));
for(i = i; i<10; i++)
    p[i] = (char*)malloc(10*sizeof(char));

I am completely puzzled. Any ideas are most welcome. Thanks.

EDIT: If none of them are are correct, what would be the correct implementation? A bit of explanation is most welcome as I am preparing for aa competitive exam that requres these skills which ask questions like this (most of which has obvious 'side effects' :( ). Also edited the typos.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
Jishan
  • 1,654
  • 4
  • 28
  • 62
  • 1
    None of them confirms the definition of array! – haccks Aug 27 '14 at 16:49
  • Only the last could have allocated memory that could be used as a matrix, if it weren't for the pesky [*undefined behavior*](http://en.wikipedia.org/wiki/Undefined_behavior) in the loop initialization. – Some programmer dude Aug 27 '14 at 16:49
  • @Igor; Not a proper way. – haccks Aug 27 '14 at 16:51
  • They all contain a lot of bugs and typos (e.g. `size0f`). But even if they didn't, it depends on what the author means by "classical definition of an array". – interjay Aug 27 '14 at 16:54
  • The 'classical' definition of p[10][10] would be 100 items in contiguous memory, so the answer is none of the above. Also, it's kind of hard to allocate memory for an array unless the type is specified, e.g. `char p[10][10]` or `int p[10][10]`. So the question is horribly written, and the answers are all wrong. You might want to find a better site to study from. – user3386109 Aug 27 '14 at 17:11

3 Answers3

2

None. This one does:

char (*p)[10] = malloc(10*sizeof(*p));

Explanation:
p is declared as a pointer to an array of ten chars. Since it points to an array, sizeof(*p) returns the size of that array, which is 10. So, the malloc() call allocates memory for ten such arrays, i. e. 100 bytes.

Now, when you derefence the pointer as in p[3], the value is the fourth array in the slap of memory. However, this value decays to a pointer to its first element in almost all contexts, so when you say p[3][5] the value is the 6th element within the 4th array within the memory slap.

Sorry, if this sounds a bit confusing, but it's really the same thing that's happening when you declare an array with char array[10][10];, except that the memory comes from a different place.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • `*p` is an expression, use `sizeof *p` without parenthesis. – Nelfeal Aug 27 '14 at 17:20
  • 2
    @Nelxiost Yes, those parentheses are not needed. As far as I'm concerned, whether you use them or not is simply a matter of style. I simply prefer to use the `sizeof` operator as if it were a function. I believe it is more likely to be understood quickly that way, even though that does not seem to be the case when you are the reader :-) – cmaster - reinstate monica Aug 27 '14 at 17:46
  • My mistake, I thought it was required in some way by the standard. A matter of style, indeed. – Nelfeal Aug 27 '14 at 17:51
1

First things first : do not cast the return value of malloc in C. This is not your code, but anyway, it is always good to say.
Also, the loops should be rewritten like so : for(i = 1; i < 10; i++) or maybe for(i = 0; i < 10; i++). i = i is probably an error (what is that website, again ?), and I will assume so.

char **p;
int i;
p = malloc(10*sizeof(char*));
*p = malloc(10*sizeof(char));
for(i = 1; i < 10; i++)
    p[i] = p[0] + 10*i;

This first code allocates 10 char* to p, and then 10 char to *p, which is equivalent to p[0]. Then, it puts the addresses of an unallocated 2D array into the other values of p[i] for i from 1 to 9. Since the array is not allocated (or only partially - p[0] is allocated), this is pretty bad.

char **p;
int i;
p = realloc(p, 10*sizeof(char*));
*p = realloc(p, 10*sizeof(char));
for(i = 1; i < 10; i++)
    p[i] = p[0] + 10*i;

This second code uses realloc instead of malloc, which does not solve the previous problems, but also adds probable segmentation faults : realloc on an uninitialized pointer is a bad idea.

char **p = NULL;
int i;
p = malloc(10*sizeof(char*));
*p = malloc(10*sizeof(char));
for(i = 1; i < 10; i++)
    p[i] = realloc(p[i-1], 10*i*sizeof(char));

This third code does the same as the first one for the first part, but then uses realloc on p[i] for i starting with 0. I assume realloc deallocates the pointer you pass to it, so this is not really a good idea. And the 10*i*sizeof(char) is not a good idea either. Basically, you will have p[9] allocated with 90 char, and nothing else. And, by the way, initializing p to NULL here doesn't do anything.

char **p;
int i;
p = malloc(10*sizeof(char*));
for(i = 0; i < 10; i++)
    p[i] = malloc(10*sizeof(char));

This fourth code has something good at least : it allocates separately each p[i] for i from 0 to 9 (I assume i starts with 0 here, unlike in the other codes). So, this might be the answer you are looking for.

Finally, the question is badly formulated since none of these codes have the same semantics as a declaration like char p[10][10].

Edit :

If you want a dynamically allocated 2D array, you can use this for instance :

int i;
char **p = malloc(10 * sizeof *p);
for(i = 0; i < 10; i++)
    p[i] = malloc(10 * sizeof *p[i]);

You can also, as cmaster did, use a pointer to an array type (like char[10]). This is the exemple from cmaster : char (*p)[10].

Community
  • 1
  • 1
Nelfeal
  • 12,593
  • 1
  • 20
  • 39
0

Well let's see:

  1. This will likely lead to errors because p[1][0] (among others) points to invalid memory locations.
  2. This is undefined behavior because you pass an uninitialized pointer to realloc().
  3. That code possibly leaves uninitialized pointers all over the place.
  4. This code loops from [1, 10), where I would expect [0, 10). So it's also terrible.

Therefore:

All of these are terrible. The correct code is either:

char (*p)[10] = malloc(10 * sizeof(*p));

Or:

char **p = malloc(10 * sizeof(*p));
for (int i=0; i<10; ++i)
    p[i] = malloc(10 * sizeof(**p));
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173