1

Inspired by this question. I created this function:

char** char2Da (int r, int c) {

    char (*p)[c] = malloc(sizeof(char[r][c]));
    // come code filling 2D array
    return (char**) p;
}

Unfortunately it does not work. Why? Is it possible to return a pointer to 2D array in C and preserve [][] notation using method from above? If it is not, why? What am I missing here?
I know there is workaround by creating outside array, passing it by ref to function. But its a bit ugly and I would love to encapsulate everything in one function.

Bare in mind that I have PHP and JavaScript background and there you just create arr[][] and return it from function. No fuss.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
CoR
  • 3,826
  • 5
  • 35
  • 42

1 Answers1

3

The types char ** and char ( * )[c] are different types. For example dereferencing the first pointer of the type char ** you will get the value stored in first characters of the first row of the allocated array that is not a pointer.

You can do the task the following way

void * char2Da (int r, int c) {

    char (*p)[c] = malloc(sizeof(char[r][c]));
    // come code filling 2D array
    return p;
}

and then in the caller write

char ( *p )[c] = char2Da( r, c );

Here is a demonstrative program

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

void * f( size_t r, size_t c )
{
    char ( *p )[c] = malloc( sizeof( char[r][c] ) );
    
    return p;
}


int main(void) 
{
    size_t r = 2, c = 3;
    
    char ( *p )[c] = f( r, c );
    
    free( p );
    
    return 0;
}

Or another demonstrative program.

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

void * f( size_t r, size_t c )
{
    char ( *p )[c] = malloc( sizeof( char[r][c] ) );

    char value = 'A';
    
    for ( size_t i = 0; i < r; i++ )    
    {
        memset( p[i], value++, c );
        p[i][c-1] = '\0';
    }
    
    return p;
}


int main(void) 
{
    size_t r = 2, c = 3;
    
    char ( *p )[c] = f( r, c );
    
    for ( size_t i = 0; i < r; i++ ) puts( p[i] );
    
    free( p );
    
    return 0;
}

The program output is

AA
BB

If c is a compile-time constant that is you are not allocating a variable length array then the function declaration could look for example like

#define C 10

char ( *char2Da (int r ) )[C];
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thanks a lot. So I'll always have to use `char(*p)[c] = f( r, c );` c value must be on both sides of = sign? Is there some other/better way to avoid that `c value on both sides`? – CoR Dec 18 '20 at 22:01
  • @CoR You are dynamically allocating a variable length array of the type char[r][c]. So the pointer to the element (row) of the array has the type char ( * )[c] that you should use to access elements of the array as it is shown in the second demonstrative program. – Vlad from Moscow Dec 18 '20 at 22:04
  • 1
    @CoR: You can avoid repeating `c` with `char (*p)[c] = f(r, sizeof *p / sizeof **p);`. That avoids the repetition, which is generally a good thing for avoiding bugs, but it does add clutter. It is common to have a macro that provides the number of elements of an array: `#define NumberOf(x) (sizeof (x) / sizeof *(x))`. Then you could write `char (*p)[c] = f(r, NumberOf(*p));`. It is the sort of thing an expert might use to keep their code orderly, depending on circumstances, but it may be unfamiliar and puzzling to novices. – Eric Postpischil Dec 18 '20 at 22:11