tags:

views:

89

answers:

5

I am trying to pass an array of character strings (C style strings) to a function. However, I don't want to place a maximum size on length of each string coming into the function, nor do I want to allocate the arrays dynamically. Here is the code I wrote first:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void fun(char *s[])
{
    printf("Entering Fun\n");
    printf("s[1]=%s\n",(char *)s[1]);
}

int main(void)
{
    char myStrings[2][12];

    strcpy(myStrings[0],"7/2/2010");
    strcpy(myStrings[1],"hello");
    fun(myStrings);

    return(0);
}

I got a seg fault when run and the following warning from the compiler: stackov.c: In function ‘main’: stackov.c:17: warning: passing argument 1 of ‘fun’ from incompatible pointer type stackov.c:5: note: expected ‘char *’ but argument is of type ‘char ()[12]’

However, when I change the main() to the following it works:

int main(void)
{
    char myStrings[2][12];
    char *newStrings[2];

    strcpy(myStrings[0],"7/2/2010");
    strcpy(myStrings[1],"hello");
    newStrings[0]=myStrings[0];
    newStrings[1]=myStrings[1];
    fun(newStrings);

    return(0);
}

Isn't array[2][12] the same thing as an array of character pointers when it is passed to a function?

+3  A: 

Try

void fun(char s[][12]) { ...}

Read also from the c-faq: My compiler complained when I passed a two-dimensional array to a function expecting a pointer to a pointer

Tom
+6  A: 

No, char array[2][12] is a two-dimensional array (array of arrays). char *array[2] is an array of pointers.

char array[2][12] looks like:

7/2/2010\0\x\x\xhello\0\x\x\x\x\x\x

where \0 is NUL and \x is indeterminate.

while

char *array[2] is:

0x CAFEBABEDEADBEEF

(assuming 32-bit)

The first has 24 contiguous characters, the second has two pointers (to the beginnings of strings elsewhere).

Matthew Flaschen
+2  A: 

Isn't array[2][12] the same thing as an array of character pointers when it is passed to a function?

No, it is a two-dimensional array. The difference is that an array of pointers contains pointers, but array[2][12] is actually an array of arrays - no pointers involved.

BTW you could do:

char* mystrings[2]={"aha", "haha"};
fun(mystrings);
jpalecek
This has the benefit of storing only the actual number of chars needed for the strings. The drawback is that an (additional) pointer is also allocated for each string. But the ease of use of the pointers is the main advantage.
Loadmaster
Yes, I know this worked, but for the actual application, I couldn't initialized the array at compile time.
Mike
@Mike: When you use it in a function, the array is actually initialized at runtime.
jpalecek
A: 

Your array is declared as a 2-D array, but you want to pass it to the function as though it's a 1-D array of string pointers.

Tom's answer is correct, you can omit the size of the first dimension of multidimensional array declarations for function parameters.

Your second solution works because it explicitly passes a 1-D array of string pointers to the function. Of course, it requires the extra overhead of the array of pointers in addition to the original 2-D string array.

Loadmaster
A: 

char myStrings[2][12]; declares myStrings as an array of arrays of characters. This means that myStrings is stored as the 24 bytes

7/2/2010.???hello.??????
‘——————————’‘——————————’
myStrings[0]myStrings[1]

where . represents a null character and ? represents an uninitialized byte.

char *newStrings[2]; declares newStrings as an array of pointers to characters. This means that newStrings is stored as the 2×sizeof(char*) bytes

[..][..]

where [..] represents a pointer object (not yet initialized).

If you want to pass strings of different lengths to your function, you have to pass an array of pointers, not an array of arrays. As you can see above, these are different layouts.

General advice: whenever you're around pointers, draw diagrams (on whiteboard or blackboard if you can, otherwise on paper) showing the various objects in memory, with arrows indicating what is pointing where. There are two kinds of C programmers: the ones who draw such diagrams when they encounter pointers, and the really experienced ones who draw the diagrams in their head.

Gilles
I am confused by your statement: ". Note that your subsequent calls to strcpy try to write to a pointer that has not been uninitialized. It was pure mischance that the program gave the result you wanted instead of crashing." What do you mean? Also what are you getting at by "pointer that has not been uninitialized"?Thanks
Mike
@Mike: Sorry, this bit was a mistake on my part (I'd misread your code).
Gilles
@Gilles: No problem. I just wanted to make sure I wasn't missing something.
Mike