3

Initializing an array of pointers to structs in C can be done using compound literals.

typedef struct {
int a;
int b;
} s;

In C:

s *ptrArray[] = {
    &(s){
        .a = 1,
        .b = 2
    },
    &(s){
        .a = 4,
        .b = 5
    }
};

How can this be done in C++?

I have also seen the difference in initializing structs in C++ not using compound statements:

s s1 = { a: 7, b: 8 };
10
  • Read up on containers, smart pointers, list initialization and aggregate initialization. C and C++ are two completely different languages. Commented Mar 1, 2018 at 14:51
  • 4
    Why do you want to use pointers for that? Why don't you want to use std::vector<s> s1 = {{1,2}, {4,5}};? Commented Mar 1, 2018 at 14:52
  • Arrays, pointers, and arrays of pointers in C++ are best avoided. Commented Mar 1, 2018 at 15:04
  • @n.m.: That requires some link as a reference or an explanation. Commented Mar 1, 2018 at 15:06
  • 1
    @n.m.: I think you should have a more pedagogical approach to comments on newbie questions. Commented Mar 1, 2018 at 16:24

2 Answers 2

2

First - initializing anything to the address of a temporary value seems extremely fishy, in C as well. Are you sure that's valid? Hmmm. Anyway, a C++ compiler will really not let you do that.

As for the your designated (named-field) initialization C++ line - it's actually non-standard, it's a GNU C++ extension, and you can't rely on it.

You could do this:

struct s { int a, b; };

int main() {
    s data[] = { { 1, 2 }, { 4, 5 } };
    // instead of ptrArray[i], use &(data[i])
}   

This compiles just fine. But - a more C++'ish version of this code would be:

#include <array>

struct s { int a, b; };

int main() {
    std::array<s, 2> data { s{ 1, 2 }, s{ 4, 5 } };
    // instead of ptrArray[i], use &(data[i]),
    // or use iterators, or ranged for loops
}   

Why would you want to use std::array? Here's one explanation of the benefits. Actually, you could do slightly better and repeat yourself less with:

int main() {
    auto data = make_array(s{ 1, 2 }, s{ 4, 5 });
    // instead of ptrArray[i], use &(data[i]),
    // or use iterators, or ranged for loops
}   

The make_array function is taken from here; you also have std::experimental::make_array(), but that's not standardized yet.

If you want to add or remove elements from data at run-time, you might switch to using std::vector:

#include <vector>

struct s { int a, b; };

int main() {
    std::vector<s> data { s{ 1, 2 }, s{ 4, 5 } };
    // instead of ptrArray[i], use &(data[i]),
    // or use iterators, or ranged for loops
}   
Sign up to request clarification or add additional context in comments.

4 Comments

Compound literals in C have the lifetime of the surrounding block as if they were local variables. They don't have the lifetime of C++ temporaries. Though it's worth noting that the GNU C++ extension which adds compound literals uses C++ temporary lifetime.
@einpoklum yes sorry for the confusion.
@CandyGumdrop: But Is the compound literal the initializer of ptrArray, or are the initializers of the pointers also blessed with the entire program's lifetime?
@einpoklum Each (type) { initializer } (C99 compound literal) expression effectively creates a new anonymous local variable (or global variable if created at file scope), so taking the address of one like int *x = &(int) {123}; is perfectly safe and would be equivalent to int foo = 123; int *x = &foo;. The OP's example is equivalent to initializing an array with some addresses of local variables, which can be a perfectly valid thing to do.
1

The reason your initialize was failing is you were attempting to initialize the array of pointers to struct to the address of numeric literal constants. The same as:

#define A 5
int b = &A;    /* NOT HAPPENING */

(you can't take the address of 5)

You can solve your problem by simply initializing an array of s instead of an array of pointers to s, e.g.:

    s ptrarr[] = { {1, 2}, {4, 5} };

With that change, your array will initialize fine, e.g.

#include <iostream>

typedef struct {
    int a;
    int b;
} s;

int main (void) {

    s ptrarr[] = { {1, 2}, {4, 5} };
    int cnt = 0;

    for (auto& i : ptrarr)
        std::cout << "ptrarr[" << cnt++ << "] : " << i.a << ", " << i.b << "\n";

}

Example Use/Output

$ ./bin/ptrarrystruct
ptrarr[0] : 1, 2
ptrarr[1] : 4, 5

2 Comments

Where is the OP taking the address of numeric literal constants? C99 compound literals evaluate to lvalues with a lifetime of the enclosing scope. The OP's example is completely valid C, just using a language feature which doesn't exist in C++.
The numeric intializers are not a compound literals (the cast is omitted). Without the cast, you are attempting to initialize the address of { {1,2}, {4,5} }, you can't do that in C or C++. "initialization makes pointer from integer without a cast"

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.