Why is this illegal in C? What is wrong with reinitializing p to a different posn? The same effect can be achieved by changing the field values individually so I don't understand why it can't be done in one step with p = {1, 2}.
struct posn {
int x;
int y;
};
int main() {
struct posn p = {3, 4};
p = {1, 2}; //Causes error
// must do p.x = 1; p.y = 2;
return 0;
}
That's the way the language is specified.
To stay somewhat consistent with C's general design, in order to allow p = {1, 2}, {1, 2} would have to be an expression. But of what type? It could be int[2], or struct { int a; short s; }, or a lot of other things.
With C99, a compound literal can be used, which explicitly mentions the type (and thereby solves the problem of how to determine the type), a parenthesized type-name followed by an initializer in {} brackets:
p = (struct posn){1, 2};
You may use a compound literal. For example
#include <stdio.h>
struct posn
{
int x;
int y;
};
int main(void)
{
struct posn p = { 3, 4 };
p = ( struct posn ){ 1, 2 };
printf( "p.x = %d, p.y = %d\n", p.x, p.y );
return 0;
}
The program output is
p.x = 1, p.y = 2
This works because structures opposite to arrays have copy assignment operator.
However you can enclose an array in structure and use the same trick to reassign arrays.
Here is an example
#include <stdio.h>
struct posn
{
int a[2];
};
int main(void)
{
struct posn p = { { 3, 4 } };
p = ( struct posn ){ { 1, 2 } };
printf( "p.a[0] = %d, p.a[1] = %d\n", p.a[0], p.a[1] );
return 0;
}
Thus it looks like std::array in C++.:)
That is not entirely true, you can't use the initializer list but you certainly can initialize or more precisely change the members of your struct whenever you want, try this
p.x = 1;
p.y = 2;
initializer lists can only be part of a declaration.
Related
Is there any syntax similar to doing something like this
typedef struct foo
{
int X;
int Y;
int Z;
} foo;
int main()
{
// Initialize everything
foo Variable = (foo){
.X = 10;
.Y = 15;
.Z = 20;
};
// Assign the X and Y variables, but keep Z the same
Variable = (foo){
.X = 15;
.Y = 20;
// .Z stays the same
};
}
Would be nice to have this type of QOL syntax instead of having to type
int main()
{
foo Variable = {bla bla};
// Keep having to type Variable. to access struct members
Variable.X = 10;
Variable.Y = 15;
}
This gets really annoying with structs in structs i.e.
Struct1->Struct2.Struct3.Element.X = 10;
Struct1->Struct2.Struct3.Element.Y = 15;
No, C does not support this style of initialization or assignment.
If you want to access only a part of a structure, you need to express this explicitely.
EDIT:
You can get away with:
Variable = (foo){
.X = 15;
.Y = 20;
.Z = Variable.Z;
};
At least an optimizing compiler will just generate the operations for the changing elements. But it is more source than single assignments.
You can use the preprocessor to save your fingers (or copy/paste)...
struct {
int f1;
int f2;
struct {
int b1;
int b2;
int b3;
} bar;
} foo = {
1, 2, { 42, 43, 44 },
};
printf( "%d %d %d\n", foo.bar.b1, foo.bar.b2, foo.bar.b3 );
#define S foo.bar
S.b1 = 7;
S.b2 = 8;
printf( "%d %d %d\n", S.b1, S.b2, S.b3 );
#undef S
the general usage of flexible array is to use malloc to define the flexible array. I'm trying to explore defining the flexible array with another struct. An example
typedef struct {
uint64_t header;
size_t data_size;
float data[];
} test_base_t;
typedef struct {
test_base_t base;
float data[3];
} test_t;
As I understand, flexible array needs to be defined at the end of a struct. And clangd will give the following warning. -Wgnu-variable-sized-type-not-at-end
I just wanted to ask if anybody has done this before and is it safe? Or is there a better way to define flexible array size without alloc?
You can then wrap the usage of the object in a macro to static assert ext.base.data == ext.data before casting and passing to a general API consumes test_base_t. This way you can have the memory required in compile instead of allocing.
Edit
There seem to be a confusion on how I wanted to consume it, here is an example to demonstrate
#define SUM_BASE(test) \
sum_base(&test->base); \
_Static_assert(test->data == test->base.data);
float sum_base(test_base_t *base)
{
float sum = 0;
for (size_t i = 0; i < base->data_size; i++)
{
sum += base->data[i];
}
return sum;
}
test_t test = { .base = { .data_size = 3, }, .data = { 1, 2, 3, }, };
SUM_BASE((&test));
You cannot create actual instances of test_base_t with an initialized array, but you can create compound literals with an initialized array of a specified length and cast their address as test_base_t pointers. The layout and alignment of both structures should be compatible, given that they have exactly the same types, save for the flexible array length.
Here is an example:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint64_t header;
size_t data_size;
float data[];
} test_base_t;
#define TEST_ARRAY(n) (test_base_t*)&(struct { uint64_t header; \
size_t data_size; \
float data[n]; })
float sum_base(const test_base_t *p) {
float sum = 0.F;
for (size_t i = 0; i < p->data_size; i++) {
sum += p->data[i];
}
return sum;
}
void print_test(const test_base_t *p) {
printf("%"PRIu64" %zu { ", p->header, p->data_size);
if (p->data_size) {
printf("%g", p->data[0]);
for (size_t i = 1; i < p->data_size; i++) {
printf(" %g", p->data[i]);
}
}
printf(" } sum=%g\n", sum_base(p));
}
int main() {
test_base_t *p1 = TEST_ARRAY(1){.data_size = 1, .data = {1}};
test_base_t *p2 = TEST_ARRAY(2){.data_size = 2, .data = {1, 2}};
print_test(p1);
print_test(p2);
print_test(TEST_ARRAY(3){.data_size = 3, .data = {1, 2, 3}});
print_test(TEST_ARRAY(4){.data_size = 4, .data = {1, 3, 5, 7}});
return 0;
}
Here is another approach, perhaps closer to your expectations, using a union with a base member with the flexible type and a parametric instance type with the appropriate array size:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint64_t header;
size_t data_size;
float data[];
} test_base_t;
/* parametric type template using C macros */
/* structures with a flexible array can be members of union types */
#define test_base_t(...) \
union { \
test_base_t base; \
struct { \
uint64_t header; \
size_t data_size; \
float data[__VA_ARGS__]; \
}; \
}
float sum_base(const test_base_t *p) {
float sum = 0.F;
for (size_t i = 0; i < p->data_size; i++) {
sum += p->data[i];
}
return sum;
}
void print_test(const test_base_t *p) {
printf("%"PRIu64" %zu { ", p->header, p->data_size);
if (p->data_size) {
printf("%g", p->data[0]);
for (size_t i = 1; i < p->data_size; i++) {
printf(" %g", p->data[i]);
}
}
printf(" } sum=%g\n", sum_base(p));
}
int main() {
test_base_t(1) t1 = { .data_size = 1, .data = {1} };
test_base_t(2) t2 = { .data_size = 2, .data = {1, 2} };
/* the print_test function can be called without casts */
print_test(&t1.base);
print_test(&t2.base);
print_test(&((test_base_t(3)){.data_size = 3, .data = {1, 2, 3}}).base);
print_test(&((test_base_t(4)){.data_size = 4, .data = {1, 3, 5, 7}}).base);
return 0;
}
C 2018 6.7.2.1 3 says of a structure containing a flexible array member:
… such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.
Thus, the test_t type in the question violates this “shall” requirement, and C 2018 4 2 says that makes the behavior not defined by the C standard. A compiler could reject this code. If the compiler accepts it, the behavior of the program is not defined by the C standard.
As an example of what could go wrong (in that the C standard allows it), consider this code:
test_t test = { .base = { .data_size = 3, }, .data = { 1, 2, 3, }, };
printf("%g\n", test.base.data[0]);
Since test.base.data[0] was never assigned a value through that expression, and the standard does not define test.data to alias test.base.data, the compiler may assume the value of test.base.data[0] is uninitialized and hence unspecified, and this printf may use any value of the float type, even if test.base.data[0] and test.data[0] nominally refer to the same memory.
And in this code:
test_t test = { .base = { .data_size = 3, } };
for (int i = 0; i < 4; ++i)
test.base.data[i] = i+1;
test_t copy = test;
The compiler may assume that, since test.data was never initialized, it does not need to be copied to copy when initializing it from test.
bool checkSubarraySum(int* nums, int numsSize, int k) {
int i, s, found = 0;
e_t buff[10000];
int n;
e_t *set[SZ] = { 0 }, *e;
put(set, &buff[n ++], 0, -1);
s = 0;
for (i = 0; i < numsSize; i ++) {
s += nums[i];
if (k) s = s % k;
e = lookup(set, s);
if (e) {
if (i - e->idx >= 2) {
found = 1;
break;
}
} else {
put(set, &buff[n ++], s, i);
}
}
return found;
}
What is e_t *set[SZ] = { 0 }, *e; doing? e_t is a user defined type but I don't think that matters. e is not a pointer that has been defined anywhere in global scope to my knowledge, and I tried something like the following:
int *array[5] = {0}, *u;
and no syntax errors were given. The first part, i.e. int *array[5] = {0} initializes all five elements of this array to 0. But what is the purpose of *u? You can't just assign an array to something else, right, it's an address, not a pointer. And u has never even been defined, so, I would expect some sort of NameError...
Thanks for any help in advance.
It is similar to typing:
int x, y;
but notice the types when typing something like:
int a, *b, **c;
/* ^ ^ ^
* int int* int**
*/
therefore
int *array[5] = {0}, *u;
/* ^ is pointer to int */
int *array[5] = {0}, *u;
Is a declaration of two int objects. The first:
int *array[5] = {0}
declares an array-of-pointers to int [5] (meaning an array of 5 pointers to int) initialized to NULL by virtue of using the "universal initializer" {0}. The equivalent, but more intuitive initialization would be:
int *array[5] = {NULL}
The ',' is simply a separator here that allows the second declaration *u to be included in the same line without a separate int *u; declaration.
(not to be confused with the comma-operator that simply discards expressions to the left of the final ',' evaluating the last expression. See What does the comma operator , do? -- thank you #AnttiHaapala)
So:
..., *u;
declares a single (uninitialized) pointer-to int.
e_t *set[SZ] = { 0 }, *e;
is a declaration of two objects; set is an array of pointers to e_t, while e is a pointer to a single e_t. It may also be written as:
e_t *set[SZ] = {0};
e_t *e;
e_t *set[SZ] = { 0 }, *e; should be read as "the programmer hereby declares that the following are of type e_t: the objects pointed to by each SZ elements in set; and the object pointed to by e."
= {0} causes each element in set to be initialized to null pointers - the first explicitly and the remaining implicitly.
I'm trying to assign an array to one of the fields of a typedef struct and I can't find a way to do it practically.
I've searched for this problem but all I seem to find is answers for char * arrays which is not what I'm looking for, I'm just trying to assign an array to an int array, and looking for a practical way for the code below to work without having to initialize all the variables in the struct (they will be initialized later, but I just want to set the array variable):
typedef struct {
int array[5];
int number;
} Rot;
Rot RA;
void config()
{
RA.array = {1, 2, 3, 4, 5}; //This returns an "expected expression before "{"" error
int arr[5];
int i;
for (i = 0; i < 5; i++)
{
arr[i] = i + 1;
}
RA.array = arr; //I understand why this fails, but I need to do this in a practical way
}
Please assume that config is called later and the struct and RA are all accessible to it.
RA.array = {1, 2, 3, 4, 5};
memcpy(RA.array, (int[]){1, 2, 3, 4, 5}, sizeof RA.array);
RA.array = arr;
memcpy(RA.array, arr, sizeof arr); // better: sizeof RA.array
You can use memcpy as shown in another answer. Or alternatively, copy the whole struct and not just the array, using a temporary variable in the form of a compound literal:
RA = (Rot) { {1, 2, 3, 4, 5}, 0 };
This is possible because while C doesn't allow run-time assignment of arrays, it does allow it of structs.
You can use memcpy as shown in another answer, or copy the whole struct as shown in another answer (although your question states that you just want to set the array, not the remainder of the struct).
Another option is to embed just the array into another struct:
typedef struct {
int elem[5];
} RotArr;
typedef struct {
RotArr arr;
int number;
} Rot;
Then you can access element i of the array in Rot RA as RA.arr.elem[i]. Also, you can assign values to a whole RotArr object. The remainder of your code could look something like this:
Rot RA;
void config(void)
{
RA.arr = (RotArr){{1, 2, 3, 4, 5}};
RotArr arr;
int i;
for (i = 0; i < 5; i++)
{
arr.elem[i] = i + 1;
}
RA.arr = arr;
}
Note that (RotArr){{1, 2, 3, 4, 5}} is a compound literal value of RotArr type. It could also be written as (RotArr){ .elem = {1, 2, 3, 4, 5} } or (RotArr){ .elem = { [0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5 } } to be absolutely clear which parts of the compound literal are being set explicitly (any remaining parts will be set to 0), but since it only has a single member, these forms of the compound literal value are a bit over-the-top.
The following works according to C syntax. Not sure this is what you wanted.
#include <string.h>
#include <stdio.h>
typedef struct {
int array[5];
int number;
} Rot;
Rot RA = {{1,2,3,4,5}};
void main()
{
RA = (Rot) {{5, 6, 7, 8, 9}};
int arr[5];
int i;
for (i = 0; i < 5; i++)
{
arr[i] = i + 1;
}
memmove(RA.array, arr, sizeof(RA.array));
// OR
int l = sizeof(arr)/sizeof(arr[0]);
for(int i =0 ; i < l ; ++i) {
*(RA.array + i) = *(arr + i);
printf("%d\n",RA.array[i]);
}
}
Moreover, use memmove since that allows memory overlap.
// Structure to store tuples of data
struct tuple {
double val;
int source; // 1 or 2, as in sample1 or sample2
};
// Assume both samples are of length n
double function(double* sample1, double* sample2, int n) {
struct tuple data[n*2];
for (int i = 0; i < n; i = i + 2) {
struct tuple t = {sample1[i], 1};
data[i] = t;
t = {sample2[i], 2};
data[i+1] = t;
// more processing
return value;
}
I want to avoid declaring struct tuple t inside the loop, since I shouldn't need to, but I can't figure out a way to declare and initialize a struct on the right hand side of an assignment. Is there a way this can be done?
If your sole intent is to avoid a named t variable, you can dispense with it for a pair of compound literals:
data[i] = (struct tuple){sample1[i], 1};
data[i + 1] = (struct tuple){sample2[i], 2};
It should satisfy any desire for terseness. Bear in mind you need to enable C11 (or C99) support for it to work. 1
1 - That variable length array kinda indicates you already do have it enabled.