0

I am making a C function to integrate into Python that basically creates a two-dimensional array of chars (each row has constant, known length), reads some data into it, builds a numpy array from it, and returns it to the calling function in Python. I'm not an expert with C, but I believe that in order to preserve the array in memory after exiting the function where it was created, I need to allocate it on the heap with malloc. So I am trying this line:

//rowSize and interleaved are both integers; bytesPerTable is equal to rowSize * interleaved
char arrs[interleaved][rowSize] = (char **)malloc(bytesPerTable * sizeof(char));

Which gives me the compiler error

error: variable-sized object may not be initialized

I'm not sure how to make this work. I want to allocate a block of memory that is the size I need (bytesPerTable) and then organize it into the required two-dimensional array. If I simply declare

char arrs[interleaved][rowSize];

Then it works, but it's on the stack rather than the heap. Can anyone help?

dpitch40
  • 2,621
  • 7
  • 31
  • 44

3 Answers3

2

What you need is this:

char** arrs = (char **)malloc(interleaved * sizeof(char*));
for(i = 0; i < bytesPerTable; i++)
    arrs[i] = (char*)malloc(rowSize * sizeof(char));

This: char arrs[interleaved][rowSize]; is just a typical stack allocation.

Tudor
  • 61,523
  • 12
  • 102
  • 142
  • yep, should iterate through first level pointers to malloc each – devmiles.com Aug 16 '12 at 14:04
  • an emulated arrray was not what the OP has asked for, and which probably is not very much appropriate to pass to python. – Jens Gustedt Aug 16 '12 at 14:06
  • @Jens Gustedt: Upon re-reading his question I'm a bit confused. He does mention he wants rows to be of constant size, yet he also used `(char**)` on the right side of the assignment... – Tudor Aug 16 '12 at 14:10
  • @Tudor as he seems to be coming from a python background this `char**` there is probably just an artefact of him trying to make this work. – Jens Gustedt Aug 16 '12 at 14:12
  • The way Jens allocated it is the preferred way, Python or not, because it allocates memory adjacently on the heap, making it 100% compatible with statically allocated arrays and C library functions. I never understood why people keep insisting on the pointer-to-pointer version. – Lundin Aug 16 '12 at 14:54
  • But an array of pointers is different than an array of arrays, is it not? For example, in an array of character pointers a[2][3] seems to mean "go two bytes beyond the start of a, read the address there, then go three bytes beyond that address", whereas in an array of arrays (two-dimensional array) it means "two times the row width plus three bytes beyond the start of a". Which model does C use? – dpitch40 Aug 16 '12 at 16:08
  • @dpitch40: Yes, of course, they are different things. What you need to use depends on the situation. – Tudor Aug 16 '12 at 16:10
  • And it appears that the array of arrays can only be allocated on the stack; if I need it on the heap, I have to make an array of pointers? – dpitch40 Aug 16 '12 at 16:15
  • @dpitch40: Unfortunately, yes. When you need to use the heap then pointers will be involved. – Tudor Aug 16 '12 at 16:20
  • How does C distinguish between these types of arrays when you try to access their elements? (The two different meanings of a[2][3]) – dpitch40 Aug 16 '12 at 16:21
  • @dpitch40: The difference actually lies in the memory layout and not in the interpretation. Even a simple array such as `char a[10];` is a pointer to the first element. So when you write `a[5]` it actually means `*(a + 5)`. – Tudor Aug 16 '12 at 16:35
  • This is making less and less sense to me. Since interleaved only has two possible values (2 and 4), I'm going to sacrifice expandability and simply make four single-dimensional arrays. – dpitch40 Aug 16 '12 at 16:39
  • @dpitch40: Arrays of arrays are contiguous in memory, while arrays of pointers are not. The rest is just pointer arithmetic. – Tudor Aug 16 '12 at 16:40
2

Do it like this

char (*arrs)[rowSize] = malloc(bytesPerTable);

arrays can't be assigned to, pointers and arrays are really different kinds of objects.

Also:

  • don't cast the return of malloc
  • sizeof(char) is 1 by definition
Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • Are you sure it's portable to assume `sizeof(char)` to always be 1? AFAIK there's no guarantee about this. – Tudor Aug 16 '12 at 14:09
  • @Tudor, as I said it is even *defined* to be like this. The `sizeof` operator measures the size of an object in terms of multiples of `char` that fit into it. Your are perhaps mixing this up with the number of bits in a `char`. Although it is `8` in any architecture that you are likely to encounter, theoretically it could be larger. But `sizeof(char)` is always `1`. – Jens Gustedt Aug 16 '12 at 14:15
  • Yes, it's guaranteed to be 1. From the C standard `When applied to an operand that has type char, unsigned char, or signed char,(or a qualified version thereof) the result is 1.` – P.P Aug 16 '12 at 14:16
  • @Tudor: yes, sizeof(char) is guaranteed to be 1. – John Bode Aug 16 '12 at 14:21
  • @JensGustedt: shouldn't the argument to `malloc` be `sizeof *arrs * interleaved`? – John Bode Aug 16 '12 at 14:45
  • @JohnBode, I was just taking OP's orginal specification of the size that he needed. Wasn't completely clear to me. One other way could be just to do `sizeof(char[interleaved][rowSize])`, but I think we don't have enough information what he wanted. – Jens Gustedt Aug 16 '12 at 14:49
  • Why "don't cast the return of malloc"? I do notice that gcc doesn't give a warning if you don't even with -Wall and -Wextra. – Scooter Aug 16 '12 at 14:57
  • @Scooter Read the [C FAQ](http://c-faq.com/malloc/mallocnocast.html) and also [this](http://stackoverflow.com/questions/1565496/specifically-whats-dangerous-about-casting-the-result-of-malloc). – Lundin Aug 16 '12 at 15:00
0

You need to alloc it to a pointer, then you can cast it as an array.

Mark
  • 595
  • 5
  • 13
  • Right, was getting confused with structs. So I guess memcpy from the pointer to the array then. – Mark Aug 16 '12 at 14:07