简体   繁体   中英

Initialize array of 3-value structures using memset

How do I initialize array of structures with values? So, I have structure color with rgb values.

struct color{
    GLfloat r;
    GLfloat g;
    GLfloat b;
}

and trying to initialize it with 1.0f.

color* cArray = (color*) malloc(w*h*sizeof(color));
memset(&cArray, 1.0, sizeof color);

But instead of correct work I get segmentation fault on cArray[0]. What do I miss?

Note: Do not cast void * (result of malloc() ) to other pointers and always check the result of malloc() & friends .

Memset takes an unsigned char (most likely 8 bits) and treats the area passed as an array of char. It has no idea of structs, arrays etc. Just of a 1-dimensional array of char. (as @chqrlie noted, memset() actually takes an int ; this is, however, internally converted to unsigned char ).

The segfault is because you pass the address of cArray which is a pointer to the actual array, not its value which would be the array itself.

For float, memset() most likely only makes sense setting it to all- 0 :

memset(cArray, 0, sizeof(struct color) * w * h);

Note: memset has no idea on data types. It just takes a pointer to a block of memory and a count and stores the value to that area. It is your responsibility all arguments are valid!

Note that writing the memory area with 0 is actually float zero ( 0.0 , actually +0.0 ), as that has all bits cleared. That was a briliant intention by the guys who dsigned the encoding for floats.

As you allocate right before, you can combine this using calloc() . That will allocate and clear the memory area of the array. However, if you intend to set all values explicitly anyway, you better stick with malloc() .

If you want to set other float values, you have to write your own loop. However, you can threat the array as 1-dimensional for that.

for ( size_t i = 0 ; i < w * h ; i++ )
    cArray[i] = (struct color){ .r = 1.0, .g = 1.0, .b = 1.0 };

That uses a compound literal . Alternatively you can also set the fields seperately.

If you are upt for speed, the compount-literal approach might be the fastest. This way ,the compiler might very well load al values into three registers and store them directly into memory using store-multiple. However it might do, I would bet the compiler will recognize that pattern and optimize as hell, as it is commonly used for very large loops.

You can't use memset() to set float values.

The memset() function is used for bytes, so using it for float s is not allowed, you need to explicitly initialize each member

This is memset() 's signature

void *memset(void *s, int c, size_t n);

although it expects int 1 for it's second parameter, the standard says

7.24.6 Miscellaneous functions

7.24.6.1 The memset function

  1. The memset function copies the value of c (converted to an unsigned char ) into each of the first n characters of the object pointed to by s .

" converted to an unsigned char " so it sets bytes.

Also take in consideration the following:

  1. You don't need to cast the return value of malloc() , and it's better if you don't do it.

  2. Always check that malloc() returned non- NULL , specially when allocating a lot of memory.


1 As you can see you can't pass float.

There are multiple problems with your code:

You allocate a matrix w x h of color structures:

color *cArray = (color*) malloc(w * h * sizeof(color));

The cast is not necessary in C, but opinions differ about the recommended alternatives. A safer version would be:

color *cArray = malloc(w * h * sizeof(*cArray));

More importantly, our call to memset is incorrect in multiple ways:

memset(&cArray, 1.0, sizeof color);
  1. You pass the address of the pointer instead of the value of the pointer cArray .
  2. You only pass the size of a single color structure. This size exceeds the size of the pointer, hence the crash. If you intended to set the whole array you should have store the size into a temporary variable.
  3. You pass a double instead of an int as the value to set. You cannot initialize an array of double values with memset : this function initializes a block of memory by setting all bytes to the same value. Passing 0 would initialize double values correctly if your system uses IEEE-754 representation for floating point values, otherwise it might invoke undefined behaviour.

You must initialize the matrix with a loop:

for (size_t i = 0, n = w * h; i < n; i++) {
    cArray[i].r = cArray[i].g = cArray[i].b = 1.0;
}

This loop can be optimized by modern compilers. I suggest you play with this very interesting tool: http://gcc.godbolt.org/# .

You can also keep a copy of a pre-initialized array and use memcpy to initialize the allocated array.

First, colors are (in your case) 3 bytes, not 3 floats.

then this code:

struct color{
    GLfloat r;
    GLfloat g;
    GLfloat b;
}

and trying to initialize it with 1.0f.

color* cArray = (color*) malloc(w*h*sizeof(color));
memset(&cArray, 1.0, sizeof color);

will cause a compiler to raise several warnings:

due to the compiler will not knowing what a 'color' is due to:

syntax errors in the struct definition
and references to the struct are missing the 'struct' modifier.

when calling malloc() (and family of functions) always check (!=NULL) the returned value to assure the operation was successful.

In C, do not cast the returned value from malloc() (and family of functions)

notice that a struct definition ends with a ';'

suggest using:

struct color
{
    char r;
    char g;
    char b;
};

struct color* cArray = NULL;
if( NULL == (cArray =malloc(w*h*sizeof(struct color))))
{ // then malloc failed
    perror( "malloc for struct color array failed" );
    exit( EXIT_FAILURE )
}

// implied else, malloc successful

memset(&cArray, 1, w*h*(sizeof (struct color) );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM