Assign multiple values to array in C
Asked Answered
L

9

47

Is there any way to do this in a condensed form?

GLfloat coordinates[8];
...
coordinates[0] = 1.0f;
coordinates[1] = 0.0f;
coordinates[2] = 1.0f;
coordinates[3] = 1.0f;
coordinates[4] = 0.0f;
coordinates[5] = 1.0f;
coordinates[6] = 0.0f;
coordinates[7] = 0.0f;
return coordinates;

Something like coordinates = {1.0f, ...};?

Lima answered 20/8, 2010 at 22:55 Comment(3)
Are you returning a pointer to a local variable, there? Some of the things people have said in answers/comments below assume either that the variables involved are automatics, or that they're not. Might help if you specify.Longing
Once the struct is initialized, there isn't an easy way to mass-assign members (other than making a copy of another struct with memcpy). I often find myself wishing I had this feature.Epicedium
I think your original answer is the best -- it's intuitive, though a bit verbose, but that is not a concern for modern compilers.Tight
P
37

If you really to assign values (as opposed to initialize), you can do it like this:

 GLfloat coordinates[8]; 
 static const GLfloat coordinates_defaults[8] = {1.0f, 0.0f, 1.0f ....};
 ... 
 memcpy(coordinates, coordinates_defaults, sizeof(coordinates_defaults));

 return coordinates; 
Pahoehoe answered 20/8, 2010 at 22:59 Comment(3)
Better even, make it "static const" and compilers can optimize the variable right out of the code.Kellyekellyn
@Zan Lynx: Won't most compilers be smart enough to do that anyways? Oh well. Good practice to be explicit I suppose.Phoneme
@Chris Cooper: not if it's a global (which might be modified in code the compiler can't see). You can't really tell from these code snippets whether the "..." elides the start of a function.Longing
G
22

Although in your case, just plain initialization will do, there's a trick to wrap the array into a struct (which can be initialized after declaration).

For example:

struct foo {
  GLfloat arr[10];
};
...
struct foo foo;
foo = (struct foo) { .arr = {1.0, ... } };
Gobioid answered 20/8, 2010 at 23:39 Comment(0)
C
12

The old-school way:

GLfloat coordinates[8];
...

GLfloat *p = coordinates;
*p++ = 1.0f; *p++ = 0.0f; *p++ = 1.0f; *p++ = 1.0f;
*p++ = 0.0f; *p++ = 1.0f; *p++ = 0.0f; *p++ = 0.0f;

return coordinates;
Copalm answered 20/8, 2010 at 23:59 Comment(1)
Elegant, I give you that, but managing some reasonable set of initialization data (with eventual need to adjust them) will be cumbersome. I would prefer some syntax where only data (and may be some delimiters for visibility purposes) would suffice. Besides it is pointer arithmetic. MISRA would go crazy about it.Toxicology
S
4

Exactly, you nearly got it:

GLfloat coordinates[8] = {1.0f, ..., 0.0f};
Sprinkling answered 20/8, 2010 at 22:56 Comment(2)
@smsteel That syntax only applies to declarationsQuicksand
This is bad.. Is there other way to simplify it? :)Lima
P
4

You can use:

GLfloat coordinates[8] = {1.0f, ..., 0.0f};

but this is a compile-time initialisation - you can't use that method in the current standard to re-initialise (although I think there are ways to do it in the upcoming standard, which may not immediately help you).

The other two ways that spring to mind are to blat the contents if they're fixed:

GLfloat base_coordinates[8] = {1.0f, ..., 0.0f};
GLfloat coordinates[8];
:
memcpy (coordinates, base_coordinates, sizeof (coordinates));

or provide a function that looks like your initialisation code anyway:

void setCoords (float *p0, float p1, ..., float p8) {
    p0[0] = p1; p0[1] = p2; p0[2] = p3; p0[3] = p4;
    p0[4] = p5; p0[5] = p6; p0[6] = p7; p0[7] = p8;
}
:
setCoords (coordinates, 1.0f, ..., 0.0f);

keeping in mind those ellipses (...) are placeholders, not things to literally insert in the code.

Palacios answered 20/8, 2010 at 23:6 Comment(0)
P
4

I went with an array initialization method:

#include <stdarg.h>

void int_array_init(int *a, const int ct, ...) {
  va_list args;
  va_start(args, ct);
  for(int i = 0; i < ct; ++i) {
    a[i] = va_arg(args, int);
  }
  va_end(args);
}

called like,

const int node_ct = 8;
int expected[node_ct];
int_array_init(expected, node_ct, 1, 3, 4, 2, 5, 6, 7, 8);

The C99 array initialization, like this:

const int node_ct = 8;
const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };

And in the configure.ac:

AC_PROG_CC_C99

had the compiler on my dev box perfectly happy. The compiler on the server complained with:

error: variable-sized object may not be initialized
   const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };

and

warning: excess elements in array initializer
   const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };

for each element

It doesn't complain at all about, for example:

int expected[] = { 1, 2, 3, 4, 5 };

I like the check on size, and that the varargs support is acting more robustly than the support for the array initializer.

Find PR with sample code at https://github.com/wbreeze/davenport/pull/15/files

Regarding https://mcmap.net/q/361568/-assign-multiple-values-to-array-in-c from @paxdiablo, I liked it; but, felt insecure about having the number of times the initializaion pointer advances synchronized with the number of elements allocated to the array. Worst case, the initializing pointer moves beyond the allocated length. As such, the diff in the PR contains,

  int expected[node_ct];
- int *p = expected;
- *p++ = 1; *p++ = 2; *p++ = 3; *p++ = 4;
+ int_array_init(expected, node_ct, 1, 2, 3, 4);

The int_array_init method will safely assign junk if the number of arguments is fewer than the node_ct. The junk assignment ought to be easier to catch and debug.

Patriapatriarch answered 19/7, 2019 at 18:29 Comment(1)
I upvoted because of the variadic approach, which makes for more readable code. But it is buried a bit into your answer. Maybe you should edit your post to give it the attention it deserves.Sybilla
T
0

If you are doing these same assignments a lot in your program and want a shortcut, the most straightforward solution might be to just add a function

static inline void set_coordinates(
        GLfloat coordinates[static 8],
        GLfloat c0, GLfloat c1, GLfloat c2, GLfloat c3,
        GLfloat c4, GLfloat c5, GLfloat c6, GLfloat c7)
{
    coordinates[0] = c0;
    coordinates[1] = c1;
    coordinates[2] = c2;
    coordinates[3] = c3;
    coordinates[4] = c4;
    coordinates[5] = c5;
    coordinates[6] = c6;
    coordinates[7] = c7;
}

and then simply call

GLfloat coordinates[8];
// ...
set_coordinates(coordinates, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f);
Transcendentalistic answered 13/6, 2018 at 9:29 Comment(0)
R
0

You can use _Generic and __VA_ARGS__ to write a generic array assignment macro. It doesn't need the number of arguments passed. But it's NULL terminated; Meaning you can't assign NULL aka 0. (You can put something else other than NULL which you know you won't assign).

#define ARRAY_ASSIGN(arr, ...) _Generic(arr,                              \
                    GLfloat* : GLfloat_array_assign(arr, __VA_ARGS__, NULL))

#define GEN_ARRAY_ASSIGN_FUNC(type)    \
inline void type ## _array_assign(type* a, ...) { \
    va_list list;                      \
    va_start(list, a);                 \
    int count = 0;                     \
    type arg = va_arg(list, type);     \
    while (arg) {                      \
        a[count++] = arg;              \
        arg = va_arg(list, type);      \
    }                                  \
    va_end(list);                      \
}  

GEN_ARRAY_ASSIGN_FUNC(GLfloat);

You call GEN_ARRAY_ASSIGN_FUNC for every type and you add the type to the _Generic arguments.

And use it like this:

ARRAY_ASSIGN(coordinates, 1.f, 2.f, 3.f, 4.f);

Or if you prefer providing count rather than NULL termination:

#define ARRAY_ASSIGN(arr, count, ...) _Generic(arr,                              \
                    GLfloat* : GLfloat_array_assign(arr, count, __VA_ARGS__))

#define GEN_ARRAY_ASSIGN_FUNC(type)    \
inline void type ## _array_assign(type* a, int count, ...) { \
    va_list list;                      \
    va_start(list, count);             \
    type arg = va_arg(list, type);     \
    for (int i=0; i<count; i++) {      \
        a[i] = arg;                    \
        arg = va_arg(list, type);      \
    }                                  \
    va_end(list);                      \
}  

And:

ARRAY_ASSIGN(coordinates, 4, 1.f, 0.f, 1.f, 0.f);
Rabelais answered 2/5, 2024 at 20:44 Comment(0)
P
-1
typedef struct{
  char array[4];
}my_array;

my_array array = { .array = {1,1,1,1} }; // initialisation

void assign(my_array a)
{
  array.array[0] = a.array[0];
  array.array[1] = a.array[1];
  array.array[2] = a.array[2];
  array.array[3] = a.array[3]; 
}

char num = 5;
char ber = 6;

int main(void)
{
  printf("%d\n", array.array[0]);
// ...

  // this works even after initialisation
  assign((my_array){ .array = {num,ber,num,ber} });

  printf("%d\n", array.array[0]);
// ....
  return 0;
}
Pharisee answered 13/6, 2018 at 8:8 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.