WickSec
WickSec

Reputation: 41

How to return a char** in C

I've been trying for a while now and I can not seem to get this working:

char** fetch  (char *lat, char*lon){
  char emps[10][50];
  //char** array = emps;
  int cnt = -1;

  while (row = mysql_fetch_row(result)) 
  { 
    char emp_det[3][20];
    char temp_emp[50] = "";
    for (int i = 0; i < 4; i++){
        strcpy(emp_det[i], row[i]);
    }

    if ( (strncmp(emp_det[1], lat, 7) == 0) && (strncmp(emp_det[2], lon, 8) == 0) ) {

        cnt++;
        for (int i = 0; i < 4; i++){
            strcat(temp_emp, emp_det[i]);
            if(i < 3) {     
                strcat(temp_emp, " ");
            }   
        }
        strcpy(emps[cnt], temp_emp);
    }
  }
}

mysql_free_result(result);
mysql_close(connection);
return array;

Yes, I know array = emps is commented out, but without it commented, it tells me that the pointer types are incompatible. This, in case I forgot to mention, is in a char** type function and I want it to return emps[10][50] or the next best thing. How can I go about doing that? Thank you!

Upvotes: 1

Views: 5822

Answers (5)

Jean-Fran&#231;ois Fabre
Jean-Fran&#231;ois Fabre

Reputation: 140168

If you found a way to cast char emps[10][50]; into a char * or char **

  • you wouldn't be able to properly map the data (dimensions, etc). multi-dimensional char arrays are not char **. They're just contiguous memory with index calculation. Better fit to a char * BTW
  • but the biggest problem would be that emps would go out of scope, and the auto memory would be reallocated to some other variable, destroying the data.

There's a way to do it, though, if your dimensions are really fixed:

You can create a function that takes a char[10][50] as an in/out parameter (you cannot return an array, not allowed by the compiler, you could return a struct containing an array, but that wouldn't be efficient)

Example:

void myfunc(char emp[10][50])
{
   emp[4][5] = 'a';  // update emp in the function

}

int main()
{
   char x[10][50];
   myfunc(x);
   // ...
}

The main program is responsible of the memory of x which is passed as modifiable to myfunc routine: it is safe and fast (no memory copy)

Good practice: define a type like this typedef char matrix10_50[10][50]; it makes declarations more logical.

The main drawback here is that dimensions are fixed. If you want to use myfunc for another dimension set, you have to copy/paste it or use macros to define both (like a poor man's template).

EDIT

a fine comment suggests that some compilers support variable array size. So you could pass dimensions alongside your unconstrained array:

void myfunc(int rows, int cols, char emp[rows][cols])

Tested, works with gcc 4.9 (probably on earlier versions too) only on C code, not C++ and not in .cpp files containing plain C (but still beats cumbersome malloc/free calls)

Upvotes: 2

dbush
dbush

Reputation: 223699

What you're attempting won't work, even if you attempt to cast, because you'll be returning the address of a local variable. When the function returns, that variable goes out of scope and the memory it was using is no longer valid. Attempting to dereference that address will result in undefined behavior.

What you need is to use dynamic memory allocation to create the data structure you want to return:

char **emps;
emps = malloc(10 * sizeof(char *));
for (int i=0; i<10; i++) {
    emps[i] = malloc(50);
}
....
return emps;

The calling function will need to free the memory created by this function. It also needs to know how many allocations were done so it knows how many times to call free.

Upvotes: 2

PMar
PMar

Reputation: 1

Another problem: Returning a 2D matrix as 'char**' is only meaningful if the matrix is implemented using an array of pointers, each pointer pointing to an array of characters. As explained previously, a 2D matrix in C is just a flat array of characters. The most you can return is a pointer to the [0][0] entry, a 'char*'. There's a mismatch in the number of indirections.

Upvotes: -1

John Bode
John Bode

Reputation: 123448

An array expression of type T [N][M] does not decay to T ** - it decays to type T (*)[M] (pointer to M-element array).

Secondly, you're trying to return the address of an array that's local to the function; once the function exits, the emps array no longer exists, and any pointer to it becomes invalid.

You'd probably be better off passing the target array as a parameter to the function and have the function write to it, rather than creating a new array within the function and returning it. You could dynamically allocate the array, but then you're doing a memory management dance, and the best way to avoid problems with memory management is to avoid doing memory management.

So your function definition would look like

void fetch( char *lat, char *lon, char emps[][50], size_t rows ) { ... }

and your function call would look like

char my_emps[10][50];
...
fetch( &lat, &lon, my_emps, 10 );

Upvotes: 3

Paul92
Paul92

Reputation: 9062

In order to understand why you can't do that, you need to understand how matrices work in C.

A matrix, let's say your char emps[10][50] is a continuous block of storage capable of storing 10*50=500 chars (imagine an array of 500 elements). When you access emps[i][j], it accesses the element at index 50*i + j in that "array" (pick a piece of paper and a pen to understand why). The problem is that the 50 in that formula is the number of columns in the matrix, which is known at the compile time from the data type itself. When you have a char** the compiler has no way of knowing how to access a random element in the matrix.

A way of building the matrix such that it is a char** is to create an array of pointers to char and then allocate each of those pointers:

char **emps = malloc(10 * sizeof(char*)); // create an array of 10  pointers to char
for (int i = 0; i < 10; i++)
    emps[i] = malloc(50 * sizeof(char)); // create 10 arrays of 50 chars each

The point is, you can't convert a matrix to a double pointer in a similar way you convert an array to a pointer.

Upvotes: 0

Related Questions