8

I have a struct in C, which members are float arrays. I want to initialize it during compile time like this:

typedef struct curve {                                                                                         
    float *xs;                                                                                             
    float *ys;                                                                                             
    int    n;                                                                                              
} curve;                                                                                                       

curve mycurve1 = {                                                                                             
    {1, 2, 3},                                                                                                     
    {4, 2, 9},                                                                                                     
    3                                                                                                              
};

curve mycurve2 = {
    {1, 2, 3, 4},
    {0, 0.3, 0.9, 1.5},
    4
};                                                                                                              

But I get compile errors.

One possible solution might be to use arrays and not pointers in the struct. This is the accepted answer of a very similar question from here: https://stackoverflow.com/a/17250527/1291302, but the problem with that approach is that I don't know the array size at typedef time. Not only that, I might want to initialize another, bigger curve.

Another approach might be with malloc, but I find that overkill, because I know the array size at compile time and I don't need it to change during run-time.

I don't know another approaches, which might be useful. Maybe casting array to pointer?? - I don't really know how I would approach that.

4
  • I don't profess to be a C or C++ expert, but unless typedefs utilize macros, isn't it all happening at compile-time? Commented Feb 12, 2020 at 20:00
  • I guess, I might be using the terms slightly incorrectly. What I meant that I want to populate the array in the code and from that point, I don't need it changed at runtime. Commented Feb 12, 2020 at 20:16
  • JonnyRobbie, with "I want to populate the array in the code and from that point, I don't need it changed at runtime", consider making const with const curve mycurve1 = { ... Commented Feb 12, 2020 at 20:19
  • What does the const keyword do? (besides not allowing any changes to that array). Is is essentially a compiler hint for optimization? Or does it do someting else? Why should I consider it? Commented Feb 12, 2020 at 20:27

2 Answers 2

7

You may not initialize a scalar object like a pointer with a braced list that contains several initializers.

But you can use compound literals.

Here is a demonstrative program.

#include <stdio.h>

typedef struct curve {                                                                                         
    float *xs;                                                                                             
    float *ys;                                                                                             
    int    n;                                                                                              
} curve;                                                                                                       

int main(void) 
{
    curve mycurve1 = 
    {                                                                                             
        ( float[] ){ 1,  2, 3 },                                                                                                     
        ( float[] ){ 4,  2, 9 },                                                                                                     
        3
    };

    curve mycurve2 = 
    {
        ( float[] ){ 1, 2, 3, 4 },
        ( float[] ){ 0, 0.3, 0.9, 1.5 },
        4
    };

    for ( int i = 0; i < mycurve1.n; i++ )
    {
        printf( "%.1f ", mycurve1.xs[i] );
    }
    putchar( '\n' );

    for ( int i = 0; i < mycurve2.n; i++ )
    {
        printf( "%.1f ", mycurve2.ys[i] );
    }
    putchar( '\n' );

    return 0;
}

Its output is

1.0 2.0 3.0 
0.0 0.3 0.9 1.5 
Sign up to request clarification or add additional context in comments.

3 Comments

So, you're essentially casting the braced list as a float array, which is compatible with assigning to a pointer? Is that somewhat correct?
@JonnyRobbie There is no casting. The compound literals create in main arrays with the automatic storage duration and pointers to first elements of this arrays are assigned to data members of the structure.
@JonnyRobbie It's not a cast, although the syntax is similar; look up "compound literals". It achieves basically the same thing as what I did in my answer (which I deleted because this is better); it's like making a separate array and initializing the member point to point to it, except here the compiler does it for you and doesn't give it a name to clutter your namespace.
3

A suggested take on @Vlad from Moscow good answer.

Use const when constant

because I know the array size at compile time and I don't need it to change during run-time.

Consider const curve mycurve1 = .... This allows for select optimizations, identifies mis-use and allows passing &mycurve1 to bar(const curve *). Also with const float [... allows passing mycurve1.xs to foo(const float *).

Avoid magic numbers

#define CURVE1_N 3
const curve mycurve1 = {
  ( const float[CURVE1_N] ){ 1,  2, 3 },
  ( const float[CURVE1_N] ){ 4,  2, 9 },  
  CURVE1_N
};

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.