1

I'm having a problem processing a multidimensional array. I'm trying to get "123" "456" "x123" and "x456" to appear on screen inside a function using pointers:

void f(char ***array){
    while (**array != '\0'){
        while (*array != '\0'){
            printf("%s\n",*array);array++;
        }
    }
}

int main(){
    char* arr[50][50]={{"123","456"},{"X123","X456"}};
    f(arr);
    return 0;
}

When compiling, I receive the warning passing argument 1 of 'f' from incompatible pointer type at the line f(arr);. and when running the code, I see:

123
456
Segmentation fault

and the program exits.

When I change my code to this:

void f(char **array){
    while (*array != '\0'){
        printf("%s\n",*array);array++;
    }
}

int main(){
    char* arr[50]={"123","456"};
    f(arr);
    return 0;
}

The numbers iterate fine, but I'd rather group my data into sets at some point for better organization. Why does the first set of code with multidimensional array not execute properly?

R_Kapp
  • 2,818
  • 1
  • 18
  • 32
Mike -- No longer here
  • 2,064
  • 1
  • 15
  • 37
  • 2
    Three stars? Time to rethink the code, but can't find the relevant link except http://stackoverflow.com/questions/10087113/how-many-levels-of-pointers-can-we-have – Weather Vane Aug 20 '15 at 18:32
  • C multidimensional arrays are *not* the same thing as an array of pointers to arrays. You need to write `void f(const char *array[][50]) { ... }`. Or, using GNU non-compile-time-constant multidimensional array dimensions: `void f(const int cols, const char *array[][cols]) { ... }`. It's been a while since I did this, but I think that works. Either that or inside your function you have to cast `array` to a pointer to an array of that type. – Peter Cordes Aug 20 '15 at 19:21
  • 1
    @PeterCordes Dimensions as arguments is part of C99. – Jason Aug 20 '15 at 19:57

3 Answers3

3

First, why three stars? What is it that you are trying to accomplish? The obvious solution is to create a two-dimensional array of characters, then store the string in the array, one per row. Consider the following example:

char arr[][ 6 ] = { "123", "456", "X123", "X456" };

Note that we are allowed to omit the number of rows in the arr array, but C requires that we specify the number of columns. Unfortunately, not all the strings are long enough to fill an entire row of the array, so C padded them with null characters. ( Note that there is a bit of wasted space in the array )

      0     1     2     3     4     5
   +-----+-----+-----+-----+-----+-----+
 0 |  1  |  2  |  3  | '\0'| '\0'| '\0'|
   +-----+-----+-----+-----+-----+-----+
 1 |  4  |  5  |  6  | '\0'| '\0'| '\0'|
   +-----+-----+-----+-----+-----+-----+
 2 |  X  |  1  |  2  |  3  | '\0'| '\0'|
   +-----+-----+-----+-----+-----+-----+
 3 |  X  |  4  |  5  |  6  | '\0'| '\0'|
   +-----+-----+-----+-----+-----+-----+

If having three stars in your code is what you want, then you will have to add one additional element which is always NULL. ( By the way, why don't you want to use the length of the array? )

Another way is to use a ragged array. C doesn't provide a "ragged array type", but it does give us the tools to simulate one. ( just create an array whose elements are pointers to strings ) Consider the following example:

#define N   4

int main( int argc, const char * argv[] ) {

    char *str[] = { "123", "456", "X123", "X456" };

    for ( char **p = &str[ 0 ]; p < str + N; ++p ) {
        puts( *p );
    }

    return EXIT_SUCCESS;
}

To access one of the strings, all we need is subscript the arr array.

Hope this helps..

Ben cisneros
  • 71
  • 1
  • 2
0

It is hard to tell what you are attempting to do, but if I understand correctly, you appear to have an additional array dimension that isn't required. You are testing an uninitialized value as soon as you reach the 5th string (leading to your segfault). To correct it, you could do something like:

#include <stdio.h>

void f(char **array){
    while (*array != '\0'){
        // while (*array != '\0'){
        printf("%s\n",*array);array++;
        //}
    }
}

int main(){
    char *arr[50]={"123","456","X123","X456",NULL};
    f(arr);
    return 0;
}

Output

$ ./bin/func_f
123
456
X123
X456

Note: an explicit NULL is used as a sentinel to stop iterating when the data is exhausted. There are a number of ways to handle this, this being only one.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

You generally shouldn't use pointers and arrays interchangeably. The common knowledge is that they're the same, but they aren't. This is particularly true for multi-dimensional arrays.

Multidimensional arrays have to be laid out linearly in memory, since addresses are linear. There are a couple ways to do this, but C uses row-major ordering. What this means is that the last index increases fastest as addresses increase.

For example, a two dimensional array

int x[rows][cols];

the two statements would be equivalent

x[row][col] = y;
*(x + (row * cols) + col) = y;

What this means is that in order to access the elements of your multi-dimensional array in a function, the function needs to know at least the sizes of the higher dimensions to validly access.

void f(int rows, int cols, char* array[rows][cols]){
  for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
      printf("%s\n", array[i][j]);
    }
  }
}

int main(){
  char* arr[50][50]={{"123","456"},{"X123","X456"}};
  f(50, 50, arr);
  return 0;
}

However, if it is necessary to iterate without knowing the dimensions, you can take advantage of the memory layout to effectively iterate over rows and columns (and higher dimensions). Although, this adds the necessity for an entry in the array that signals an end (e.g. NULL). Aside from making the code more complex, it adds memory overhead since the last row containing the NULL generally must be allocated.

#include <stdio.h>

void f(char** array){

  while (*array)
    printf("%s\n", *(array++));
}

int main(){

  char* arr[][2] = { {"123","456"}, {"X123","X456"}, {NULL, NULL} };

  f((char**) arr);

  return 0;
}
Jason
  • 3,777
  • 14
  • 27
  • your last code is an idea but I still get `passing argument 1 of 'f' from incompatible pointer type` when compiling and a segfault when executing. Maybe theres no true answer to my question since everyone is suggesting me to use single dimension only. – Mike -- No longer here Aug 21 '15 at 04:02
  • @Mike I wrote the last version too quick, see the changes above. This is one of the reasons it's bad to interchangeably use pointers and arrays. – Jason Aug 21 '15 at 05:08