0

I am trying to write a getter for a 2d array of a struct. I have tried all kinds of solutions and my IDE complains about all of them.

static history_t history[3][6];

history_t **get_history(){
    return history;
};

From my understanding, this is correct. An array of array is a pointer to pointers. However, my IDE complains about incompatible pointer types. I have not been able to find any combination of signatures and accessors for history which allow me to return anything useful.

Is this something which is possible in C?

warning: returning 'history_t (*)[6]' {aka 'struct <anonymous> (*)[6]'} from a function with incompatible return type 'history_t **' {aka 'struct <anonymous> **'} [-Wincompatible-pointer-types]
     return history;

So, my function isn't returning history_t **, but history_t *[6]. However, redefining the signature to return history_t*[6] also does not work.

kopecs
  • 1,545
  • 10
  • 20
Daniel Paczuski Bak
  • 3,720
  • 8
  • 32
  • 78
  • "Expected function body after function declarator" is the warning I get when I try that. – Daniel Paczuski Bak Dec 27 '19 at 21:51
  • 6
    `history_t (*get_history())[6] { return history; }` – Lxer Lx Dec 27 '19 at 21:52
  • 1
    Can you please explain what is going on here? And will this pass a copy, or a reference to the 2d array? – Daniel Paczuski Bak Dec 27 '19 at 21:53
  • And how am I supposed to call this get_history function? – Daniel Paczuski Bak Dec 27 '19 at 21:56
  • 1
    You simply call it as you would any function with no arguments. – kopecs Dec 27 '19 at 21:57
  • What is the type of the variable I assign using this function? – Daniel Paczuski Bak Dec 27 '19 at 21:58
  • @LxerLx you should provide an answer with the function definition given in your comment so it can be accepted. – kopecs Dec 27 '19 at 21:58
  • @DanielPaczuskiBak like so `history_t (*identifier)[6] = get_history();` – kopecs Dec 27 '19 at 22:01
  • 1
    @DanielPaczuskiBak get_history is a function returning a **pointer** to an array[6] of history_t. It does **not** return a copy. It returns a **pointer** to a 6-element array of history_t. An array of array is **not** a pointer to pointers – Lxer Lx Dec 27 '19 at 22:06
  • @DanielPaczuskiBak I suspect you're confused by the mislabeling of a `**` pointer "array" created by, for example, nested `malloc()` calls. That's **NOT** a "2-d array". That construct is an array of pointers to individual and completely separate one-dimensional arrays. See https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays for a good explanation. – Andrew Henle Dec 27 '19 at 22:12
  • regarding: `history_t history[3][6]; sensor_history_t = ...` there is a big difference between `history_t` and `sensor_history_t` – user3629249 Dec 28 '19 at 00:36

2 Answers2

7

There are many misconceptions about arrays, multidimensional arrays, and pointers. I will try to explain the differences between them, then answer the question. Below, T denotes a type name.

T x[3]; /* the type of x is "array of T" */

x is an array. It has three elements. Each element is a T.

T *x[3]; /* the type of x is "array of pointer to T" */

x is an array. It has three elements. Each element is a pointer-to-T.

T (*x)[3]; /* the type of x is "pointer to an array of three Ts" */

x is a pointer. It points to an array. The array has three elements. Each element is a T

T x[3][6]; /* the type of x is "array of array of six Ts" */

x is an array. It has three elements. Each element is an array of six Ts. Hence x is a multidimensional array, or more precisely, a two dimensional array, a 3×6 array of Ts.

And now, a very important rule in C: An expression with the type "array of T" is converted to the "pointer to T" that points to the initial element of the array object, except when it is the operand of the sizeof or address operator. So,

void f(T*);

void g(void)
{
    T x[3];
    /* ... */
    f(x); /* equivalent to f(&x[0]); */
}

The pointer to the first element of the array x is passed as an argument in the function call f(x) above. The array is not passed. It is not possible to pass an array directly to a function as an argument in C (it can be done indirectly by wrapping the array in a structure). Returning from a function has the same semantic: an array cannot be returned from a function (unless it is wrapped in a structure):

T *f(void)
{
    static T x[3];
    /* ... */
    return x; /* Equivalent to return &x[0]; */
}

A pointer to the initial element of the array x is returned.

Your array is defined as

static history_t history[3][6]; /* static is not relevant in this discussion */ 

Type of history is "array of array of six history_ts". It will be converted to "pointer to array of six history_ts" when it is returned from a function, as discussed above. An object x with the type "pointer to array of six history_ts" is defined as

history_t (*x)[6];

To declare a function returning that type, the x is replaced by the function declarator.

history_t (*get_history())[6]; /* function returning pointer to array of six history_ts */

The () has higher precedence than the *, so no parentheses needed around get_history(). To define such a function, the function body is added:

static history_t history[3][6];

history_t (*get_history())[6]
{
    /* ... */
    return history;
}
Lxer Lx
  • 292
  • 1
  • 6
1

you have a static array which must have a fixed size 6 in your case. So if you have to return a pointer of 6.

history_t (*get_history())[6] { 
    return history; 
}

Then to call this function an use its result, you could do

history_t (*identifier)[6] = get_history();

See about pointer, static and other...

kopecs
  • 1,545
  • 10
  • 20
TZof
  • 150
  • 1
  • 7