Marcus Johansson
Marcus Johansson

Reputation: 2667

Passing two dimensional array with "constant" length

I am trying to pass a two-dimensional char array to a function. I have found how to do it with a one-dimensional array, but I am having a hard time extrapolating that to how to deal with my current situation. See example code:

void foo( char ** bar ) {

}

int main () {
    char mlady[100][100];
    foo(mlady);
}

The compiler hints that the argument should be of type char (*)100, but I can't get that to compile. I also tried a lot of bruteforce without luck.

I am surprised I can't find this on google/SO, but I guess I am using the wrong keywords.

Upvotes: 1

Views: 103

Answers (2)

Crowman
Crowman

Reputation: 25926

When you define a multi-dimensional array, the bytes are laid out contiguously in memory.

For instance:

char a[3][5];

will give you 15 contiguous bytes of memory, laid out as so:

----------------------------------------------
| a + 0  | a + 1  | a + 2  | a + 3  | a + 4  |
----------------------------------------------
| a + 5  | a + 6  | a + 7  | a + 8  | a + 9  |
----------------------------------------------
| a + 10 | a + 11 | a + 12 | a + 13 | a + 14 |
----------------------------------------------

To reference a[x][y], the compiler will translate this to a + y + x * 5, in the same way that it translates indexing of a single element array from a[x] to a + x.

You'll see that in order for this translation to work for a two-dimensional array, you must know the rightmost dimension. In other words, the 5 in the definition char a[3][5] appears in the calculation a + y + x * 5, and must appear for that calculation to be able to work.

You don't need to know the leftmost dimension, because it doesn't appear in the calculation.

This is generally true of any multi-dimensional array. In order to calculate the offset of a specified index, you must know all of the dimensions except for the leftmost one. It doesn't hurt to have the leftmost one, but you don't need it.

Another way of saying all this is that "multi-dimensional arrays" in C are really just convenient ways of working with one-dimensional arrays. There's nothing char a[3][5] gives you that you can't accomplish with char a[15], and replacing all instances of a[x][y] with *(a + y + x * 5), it just makes the syntax slightly more convenient. Under the hood, these two ways are actually identical.

So, on the one hand, attempting to pass a two-dimensional array to a function as a char ** will not work, because you're not providing the rightmost dimension to the function, and the function needs it. void func(char (*bar)[5]) and void func(char bar[][5]) would be equivalent ways of doing that. In the first case, you need the parentheses around *bar because otherwise you'd have void func(char *bar[5]), where bar would be declared as a five element array of pointers to char, which is not what you have at all.

More fundamentally, passing it as a char ** won't work because a char ** is a pointer to a char pointer, and in a two-dimensional char array, you don't have any char pointers in there - just a bunch of plain chars. A pointer to the array will be passed to the function, but when you dereference it once, there are no more pointers to find, and to get from a char ** to a char you need to deference twice.

If you were to do something like (error checking omitted for brevity):

char ** list_strings = malloc(3 * sizeof *list_strings);
list_strings[0] = malloc(5);
list_strings[1] = malloc(5);
list_strings[2] = malloc(5);

then you could pass list_strings as a char ** because it actually is one, and not a true multi-dimensional array - there are two levels of indirection in there, once to get to the individual strings, and then again to get to an individual character in one of those strings. What you'd be passing to your function would be a single-dimensional (dynamically allocated) array of char *. The fact that your function could then go on to deference any of those members again does not make it a multi-dimensional array.

When you pass a char ** in this way, you technically don't need to know any of the dimensions, at least not to access any particular element. You do, of course, need to know the dimensions to avoid the function dropping off the end of any of them, unless you hardcode the dimensions of the array into your function and only ever pass it arrays of that size, which is generally not a good way to write programs.

Upvotes: 2

ani627
ani627

Reputation: 6057

Change void foo( char ** bar ) to void foo( char bar[][100] ).

When you are passing a multidimensional array to a function, the first array dimension does not have to be specified. However the second(and subsequent) dimensions must be provided to the function.

For more information check this C-Faq.

Upvotes: 5

Related Questions