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.