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.

11
  • "Expected function body after function declarator" is the warning I get when I try that. Commented Dec 27, 2019 at 21:51
  • 6
    history_t (*get_history())[6] { return history; } Commented Dec 27, 2019 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? Commented Dec 27, 2019 at 21:53
  • 1
    You simply call it as you would any function with no arguments. Commented Dec 27, 2019 at 21:57
  • 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 Commented Dec 27, 2019 at 22:06

2 Answers 2

8

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;
}
Sign up to request clarification or add additional context in comments.

Comments

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...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.