0

NOTE: I am actively fiddling with this over on Ideone.

I have a (self-referential) structure:

typedef struct T_Function T_Function;
struct T_Function
{
    T_Function * (* inhibits)[]; // pointer to array of pointers to this structure
};

and would like to use compound literals as the target of the inhibits pointer. Something along the lines of

T_Function a, b, c;
a.inhibits = & (<type>) {&b, &c};

This could be done as follows but I am looking to understand the type specification so I can use compound literals.

T_Function a, b, c;
T_Function * ai[] = {&b, &c};
a.inhibits = &ai;

What is the appropriate type specification to replace <type> above?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
altendky
  • 4,176
  • 4
  • 29
  • 39

2 Answers2

0

a.inhibits is a pointer to some subsequent memory locations forming the pointer array. If you want to assign something to a.inhibits, you need an array of pointers somewhere whose location to store in a.inhibits. This is why there is no syntax like &(...){&b, &c}: it can't be right regardless of what you are using for ... because there is no actual array {&b, &c} in the memory.

In your second example, you are allocating an array of T_Function * pointers on the stack. This is a common programming error: a.inhibits will point to a location on the stack, and as soon as the current stack frame is left, the contents of a.inhibits will be undefined. Still worse, writing to a.inhibits will cause undefined behavior.

You'll probably want to use a data structure of some kind, but to answer your question, the simplest solution would be to allocate the array on the heap:

#include <stdlib.h>

typedef struct T_Function T_Function;
struct T_Function
{
    T_Function **inhibits;  /* no [] */
};

T_Function a, b, c;
T_Function **ai = calloc(2, sizeof(T_Function *));
ai[0] = &b;
ai[1] = &c;
a.inhibits = ai;

Just make sure you free the memory once you don't need it any more.

user3426575
  • 1,723
  • 12
  • 18
  • Thanks for trying to keep me on the right path with my memory usage though this was really just meant as a snippet. You say that `&(...){&b, &c}` can't be right but I can do `int * (* not_typed)[4] = & (int *[]) {&one,&two,&three,&four};` (see http://ideone.com/PD3nMH for more). Thanks to you sending me back to the basics I found the answer and will post it separately. – altendky Jun 02 '15 at 19:51
  • This won't do what you think it does, either. In this case, `one`, `two`, `three`, and `four` are global variables which means their address is known at linking time. If you try to do this inside a function, you'll run into the same problems as before. – user3426575 Jun 02 '15 at 20:04
  • I appreciate your concern for my memory usage and will be considerate and wary. My only effort here was to learn the syntax for getting the address of a compound literal which is an array of pointers. – altendky Jun 02 '15 at 20:09
0

<type> can be T_Function *[].

typedef struct T_Function T_Function;
typedef T_Function * T_Inhibits[];

struct T_Function
{
    T_Inhibits * inhibitsTD; // pointer to array of pointers to this structure
    T_Function * (* inhibits)[]; // pointer to array of pointers to this structure
};

<snip>

T_Function x;
// direct
x.inhibitsTD = &(T_Function *[]) {&x};
x.inhibits = &(T_Function *[]) {&x};
// via typedef
x.inhibitsTD = &(T_Inhibits) {&x};
x.inhibits = &(T_Inhibits) {&x};

Do note that as @user3426575 pointed out, there are storage duration hazards with this. Being a compound literal does not inherently imply static duration.

C99 6.5.2.5-6

The value of the compound literal is that of an unnamed object initialized by the initializer list. If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

altendky
  • 4,176
  • 4
  • 29
  • 39