tags:

views:

113

answers:

4

Hello,

gcc 4.4.3 c89

I am wondering why I can't allocate the size of the array when initializing an array of pointers to char.

I get the following error:

variable-sized object may not be initialized

This works ok. However, the sizeof of will return 4 bytes as a char * is 4 bytes in size. Which is no good, as its not the actual size that I want.

void inc_array(const char * const src, size_t size)
{
    /* Array of pointers */
    char *dest[sizeof(src)] = {0};
}

However, this is what I want to do is pass the actual size and use that to initialize the length of the array.

void inc_array(const char * const src, size_t size)
{
    /* Array of pointers */
    char *dest[size] = {0};
}

What is the difference when sizeof of returns a size_t and I am passing a size_t?

Many thanks for any suggestions,

+4  A: 

Use malloc to allocate dynamically sized arrays.

You must also ensure that malloced data is eventually freed.

kbrimington
@kb. Thanks for the tutorial. I know about malloc and free. However, I was just wondering why I could the following char *dest[sizeof(src)] and I can't do char *dest[size]? Thanks
robUK
@robUK - see the edit to my answer
D.Shawley
@rob: I see. It happens to be the case that `sizeof(src)` is known at compile time, but `size` was not. That is the root of the problem.
kbrimington
+4  A: 

In C89 you simply cannot do this - variable sized arrays are not supported before C99. Array sizes are required to be compile-time constants. You want something like:

void inc_array(const char * const src, size_t size) {
    char ** dest = calloc(size, sizeof(char*));
    /* do stuff with dest here! */
}

I'm not sure that you want an array of pointers though. I would have expected the following:

void inc_array(const char * const src, size_t size) {
    char *dest = calloc(size, sizeof(char));
    memcpy(&dest[0], &src[0], size);
    /* do stuff with dest */
    free(dest);
}

Edit: I forgot to answer the second part of your question.

The difference is that sizeof(src) is a compile time expression (IIRC) since it is calculating the size of a type. In this case, it is identical to sizeof(char*) which is probably 32-bits on your platform. However, size in char *dest[size] cannot be statically determined. Both are size_t values but C89 requires that the number of elements in a statically allocated array are determinable at compile time. This is why you have to resort to dynamic allocation.

D.Shawley
The error isn't that variable-length arrays aren't *supported*, it's that they can't be *initialised*. Evidently the OP's compiler supports C99.
caf
I figured that the version of gcc supported VLAs as a GNU extension. I should have simply said that VLAs are not supported in C89. I'll edit in the change.
D.Shawley
+1  A: 

The reason the sizeof operator is not working as you would expect is that an array "decays" to a pointer when you pass it to a function:

int array[5];
printf("%d\n", sizeof(array) / sizeof(int)); /* prints 5 */

/* ... */

void some_function(int array[])
{
  printf("%d\n", sizeof(array) / sizeof(int)); /* prints 1, no matter what */
}

As for defining your arrays, in older versions of C, variable length arrays were not allowed (note that Visual Studio still implements this old version of C). You had to specify a constant size:

const size_t some_size = 22;
size_t some_other_size = 5;
int array1[5]; /* okay */
int array2[some_size]; /* okay */
int array3[some_other_size]; /* not okay - not const */

Newer versions of C (compilers that implement the C99 standard) allow you to specify a variable size:

size_t some_other_size = 5;
int array3[some_other_size]; /* okay - VLA */

As a side note, no version of the C++ standard has included support for VLAs. Some C++ compilers have implemented their own extensions, however (See comment by Groxx).

If you want to allocate a variable amount of contiguous memory in a C compiler that doesn't support VLAs, you must use malloc and free, as kbrimington suggested:

size_t size = 5;
int* array = (int*)malloc(sizeof(int) * size);
/* use array */
free(array);
Merlyn Morgan-Graham
"No version of C++ has ever allowed VLAs" <- totally inaccurate. C99, the one you're mentioning, does. http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html or http://en.wikipedia.org/wiki/Variable-length_array#Examples (note the first example). Caused a few question-marks when I was compiling with GCC and my prof was compiling with whatever Visual Studio uses.
Groxx
@Groxx: I suppose I should rephrase that to "no version of the C++ standard has included a definition for VLAs". It is an extension in GCC and IBM's C++ compiler. And I'm talking about C++, not C, even though I know the question is about C. It's just a side note :)
Merlyn Morgan-Graham
+1  A: 

As the error message says, variable-length arrays can't be initialised - that is, it's the = { 0 } part that's the problem. You can still use a variable-length array - you just need to explicitly initialise it:

void inc_array(const char * const src, size_t size)
{
    /* Array of pointers */
    size_t i;
    char *dest[size];

    for (i = 0; i < size; i++)
        dest[i] = 0;
}
caf
@caf. Yes, you are correct. I have just tested that.
robUK
@caf. so VLA are perfectly acceptable its only when you try and initialize them. I have marked this as correct, as this is the real reason why I got that error. Thanks.
robUK
@robUK: They're acceptable in the current C standard, and as a gcc extension to the older C standard.
caf