Assign value to field in array of nested structs - c

I have a function test that accepts a pointer to a structure. How can I set the value of a field in a structure in the nested structure array? The structures are created and deleted elsewhere, I just want to set the value.
typedef struct {
int a;
} inner_struct_t;
typedef struct {
int b;
inner_struct_t innerStructsArr[];
} outer_struct_t;
void test(outer_struct_t *outerStruct);
void test(outer_struct_t *outerStruct) {
outerStruct->b = 123; // set a value in the outer struct
(outerStruct->innerStructsArr)[0].a = 456; // but this DOESN'T work
}

Here's a complete example that should work for you:
#include <stdio.h>
#include <malloc.h>
typedef struct {
int a;
} inner_struct_t;
typedef struct {
int b;
inner_struct_t *innerStructsArr;
} outer_struct_t;
void test(outer_struct_t *outerStruct, int n) {
outerStruct->b = 123; // set a value in the outer struct
outerStruct->innerStructsArr = malloc(sizeof(inner_struct_t) * n); // Allocate space
outerStruct->innerStructsArr[0].a = 456; // Assign a value
}
int main (int argc, char *argv[]) {
outer_struct_t s;
test(&s, 1);
printf("b=%d, inner[0]=%d\n", s.b, s.innerStructsArr[0].a);
free(s.innerStructsArr);
return 0;
}

When you have a structure with a flexible array member (FAM) in it, you need to allocate the space for the array at the same time that you allocate the space for the structure.
ISO/IEC 9899:2011 §6.7.2.1 Structure and union specifiers
¶18 As a special case, the last element of a structure with more than one named member may
have an incomplete array type; this is called a flexible array member. In most situations,
the flexible array member is ignored. In particular, the size of the structure is as if the
flexible array member were omitted except that it may have more trailing padding than
the omission would imply. However, when a . (or ->) operator has a left operand that is
(a pointer to) a structure with a flexible array member and the right operand names that
member, it behaves as if that member were replaced with the longest array (with the same
element type) that would not make the structure larger than the object being accessed; the
offset of the array shall remain that of the flexible array member, even if this would differ
from that of the replacement array. If this array would have no elements, it behaves as if
it had one element but the behavior is undefined if any attempt is made to access that
element or to generate a pointer one past it.
Given:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int a;
} inner_struct_t;
typedef struct
{
int b;
inner_struct_t innerStructsArr[];
} outer_struct_t;
static void test(outer_struct_t *outerStruct)
{
outerStruct->b = 123;
outerStruct->innerStructsArr[0].a = 456;
}
int main(void)
{
outer_struct_t *os = malloc(sizeof(*os) + 4 * sizeof(os->innerStructsArr[0]));
for (int i = 0; i < 4; i++)
os->innerStructsArr[i].a = 10 * i;
test(os);
printf(" b = %d\n", os->b);
for (int i = 0; i < 4; i++)
printf("[%d].a = %d\n", i, os->innerStructsArr[i].a);
free(os);
return 0;
}
Sample output:
b = 123
[0].a = 456
[1].a = 10
[2].a = 20
[3].a = 30

Related

Nested array struct in C

Why the content is not printed well (e.g. Segmentation Fault/NULL)? I'm passing the entire nested struct (i.e. the array list lp) to the main list. Any suggestion? I spent two days to understand what I wrong without success. I would to have an explanation about it.
#include <stdio.h>
#include <string.h>
struct list
{
char *a;
char *b;
} lp[10];
typedef struct
{
int k;
struct list thelist[2];
} palist;
int main()
{
lp[0].a = "One";
lp[0].b = "Two";
lp[1].a = "Three";
lp[1].b = "Four";
palist final_list = {10, *lp};
printf("%s, %s", final_list.thelist[1].a, final_list.thelist[1].b);
return 0;
}
What you have to understand is that on access, an array is converted to a pointer to the first element (subject to 4-exceptions not relevant here) C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)
When you attempt to initialize thelist with *lp you are attempting to initialize an array of struct list from the first element in lp. Assuming you change the intialization from {10, *lp} to (10, lp) that still will not work because now lp is a pointer to the first element which you attempt to use to initialize an array.
In order to accommodate the array/pointer conversion, you need to declare thelist as a pointer not an array, e.g.
typedef struct
{
int k;
struct list *thelist;
} palist;
(You can initialize a pointer with a pointer and all will be well)
Now using the initializer {10, lp} will provide a pointer for the initialization of thelist and your assignment will work (but you must keep track of the number of elements that are valid -- final_list[2].... would invoke Undefined Behavior as the elements 2 and beyond are not initialized)
Your total code would be:
#include <stdio.h>
struct list
{
char *a;
char *b;
} lp[10];
typedef struct
{
int k;
struct list *thelist;
} palist;
int main(void) {
lp[0].a = "One";
lp[0].b = "Two";
lp[1].a = "Three";
lp[1].b = "Four";
palist final_list = {10, lp};
printf("%s, %s\n", final_list.thelist[1].a, final_list.thelist[1].b);
return 0;
}
There are many other ways to initialize or assign this list in the form with the array
typedef struct
{
int k;
struct list thelist[2];
} palist;
for example
palist final_list = {10, {lp[0], lp[1]}};
final_list = (palist){10, {lp[0], lp[1]}};
final_list = (palist){10,};
memcpy(final_list.thelist, lp, sizeof(final_list.thelist));
https://godbolt.org/z/fUjLtE

How to use the double pointer structure correctly

Below is the code, I'm so puzzled of how to use that double pointer int struct _AReport and struct _BReport.
My system is running on a Embedded computer, I use VS to debug this parts.
My system is composed of 1 struct _AReport, 17 struct _BReport and 16 struct _CReport on the whole.
The goal is that struct _AReport will contain all the informations.
I'm poor at English, thanks for being patient.
#include "stdafx.h"
typedef struct _AReport AReport;
typedef struct _BReport BReport;
typedef struct _CReport CReport;
typedef struct _AData AData;
typedef struct _BData BData;
typedef struct _CData CData;
typedef struct _ABCDatas ABCDatas;
struct _AReport
{
AData *adata;
BReport **breport;
};
struct _BReport
{
int _b;
BData *bdata;
CReport **creport;
};
struct _CReport
{
int _c;
CData *cdata;
};
int main()
{
int i = 0;
AReport Ar;
//BReport Br_dyadic[17][16] = { 0 };
BReport Br[17];
BReport *Br_Pointer = Br;
Ar.breport = &(Br_Pointer);
for (i = 0; i < 17; i++)
{
Br[i]._b = i + 1;
}
(Ar.breport[0])->_b = 99;
(Ar.breport[0] + 1)->_b = 99;
return 0;
}
If your question is does this problem require pointers to pointers, the answer is no: pointer arithmetics allow a single pointer to access all elements of a 1D array.
But if your question is does the last lines correctly access the elements of Br, then the answer it yes. Here is what actually happens:
Ar.breport is a pointer to a pointer to the first element of array Br (from BReport *Br_Pointer = Br; Ar.breport = &(Br_Pointer);, BrPointer being a pointer to first element of Br)
Ar.breport[0] is by definition the same as *(Ar.breport) => it is a pointer to the first element of Br
so Ar.breport[0] + 1 is by pointer arithmetics a pointer to the second element of Br
It is then legal to use those 2 pointers to dereference them and access the _b member of the BReport they point to.
You could make sure of that by simply adding:
printf("%d - %d - %d\n", Br[0]._b, Br[1]._b, Br[2]._b);
just before the return 0; (of after adding #include <stdio.h>...) and that should print 99 - 99 - 2

How do I return a struct (from a function) containing an array with the correct elements in that array?

I'm making a program that returns a struct containing an array, but the elements in the array are completely wrong. I keep searching for an answer on this site, Google, and even Bing and nothing. The best I can find are answers like this:
Functions can't return arrays in C.
However, they can return structs. And structs can contain arrays...
from How to make an array return type from C function?
Now, how do I fix this without the use of pointers?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
struct Codes{
int as;
int a[];
};
struct Codes create(int as){
int a[as];
for(int j = 0;j<as;j++)
a[j]=j+1;
struct Codes c;
c.as = as;
c.a[c.as];
for(int i=0; i<as; i++)
c.a[i] = a[i];
for(int i=0; i<as; i+=1)
printf("%d \n", c.a[i]);
return c;
}
int main(int argc, char **argv) {
struct Codes cd;
int as = 4;
cd = create(as);
for(int i=0; i<4; i+=1)
printf("%d \n", cd.a[i]);
}
Actual output:
1
2
3
4
0
0
2
-13120
Expected output:
1
2
3
4
1
2
3
4
structs with flexible value are not meant to be manipulated by value, only by pointer.
You cannot return a struct with a flexible member by value, because C does not know how many items it needs to allocate to the return value, and how many bytes it needs to copy.
Allocate your struct in dynamic memory using malloc of sufficient size, copy your data into it, and return a pointer to the caller:
struct Codes *c = malloc(sizeof(struct Codes)+as*sizeof(int));
c->as = as;
for (int i = 0 ; i != as ; i++) {
c->a[i] = i+1;
}
return c;
Change your function to return a pointer; make sure the caller frees the result.
In your function, struct Codes create(int as), the struct Codes c; is allocated on the stuck, so the memory is no longer valid once the function returns...
...It is true that the core struct is copied in the return value... but the variable array length c.a isn't part of the struct (it's a memory "trailer" or "footer") and isn't copied along with the return value.
Either:
allocate the struct and pass it to a struct Codes create(struct Codes *dest, int as) function; OR
make the struct array fixed in size struct Codes{ int as; int a[4]; };
Good luck.

initializing a struct array with array inside

So I made a struct with a with an uninitialized array inside but the outer struct is an array that is initialized. I then loop through and print the values but I'm not getting anything. NUM is already defined as 12.
#include "header.h"
#include <stdio.h>
#include <stdlib.h>
void make() {
struct suit {
char *type;
int people[];
} deck[4] = {"Hunter", NUM,
"Fighter", NUM,
"Jumper", NUM,
"Strider", NUM};
};
//print type and numbers 1-12
for (int i = 0; i < 4; i++) {
for (int j = 0; j < NUM; i++) {
printf(deck[i].type);
printf(deck[i].people[j]);
}
}
}
Allocate the memory of int people[]; array, So, your struct should look like this, since it is an object definition:
struct suit {
char *type;
int people[10]; //compile time allocation
} deck[4] = {"Hunter", NUM,
"Fighter", NUM,
"Jumper", NUM,
"Strider", NUM};
people is a flexible array member and Standard C does not allow initialization of flexible array member. Though, GCC allows static initialization of flexible array as an extension. So,
struct suit {
char *type;
int people[];
} deck = {"Hunter", NUM};
is valid snippet as per GCC, but at the same time GCC doesn't allow nested array initialization when flexible array member is involved and therefore the initializer for deck[4] is not valid.
Of course, this extension only makes sense if the extra data comes at the end of a top-level object, as otherwise we would be overwriting data at subsequent offsets. To avoid undue complication and confusion with initialization of deeply nested arrays, we simply disallow any non-empty initialization except when the structure is the top-level object. For example:
struct foo { int x; int y[]; };
struct bar { struct foo z; };
struct foo a = { 1, { 2, 3, 4 } }; // Valid.
struct bar b = { { 1, { 2, 3, 4 } } }; // Invalid.
struct bar c = { { 1, { } } }; // Valid.
struct foo d[1] = { { 1, { 2, 3, 4 } } }; // Invalid.
Also note that you should use appropriate format specifiers in printf for different data types.

How to access members of a `struct' according to a variable integer in C?

Suppose I have this struct (which incidentally contain bit-fields, but you shouldn't care):
struct Element {
unsigned int a1 : 1;
unsigned int a2 : 1;
...
unsigned int an : 1;
};
and I want to access the i'th member in a convenient way. Let's examine a retrieval solution.
I came up with this function:
int getval(struct Element *ep, int n)
{
int val;
switch(n) {
case 1: val = ep->a1; break;
case 2: val = ep->a2; break;
...
case n: val = ep->an; break;
}
return val;
}
But I suspect that there is a much simpler solution. Something like array accessing style, maybe.
I tried to do something like that:
#define getval(s,n) s.a##n
But expectedly it doesn't work.
Is there a nicer solution?
Unless you have specific knowledge of the underlying structure of the struct, there is no way to implement such a method in C. There are all sorts of problems that will get in the way including
Members of different sizes
Packing issues
Alignment issues
Tricks like bitfields will be problematic
You're best off implementing a method by hand for your struct which has a deep understanding of the internal members of the structure.
If every field in your struct is an int, then you should basically be able to say
int getval(struct Element *ep, int n)
{
return *(((int*)ep) + n);
}
This casts the pointer to your struct to a pointer to an array if integers, then accesses the nth element of that array. Since everything in your struct seems to be an integer, this is perfectly valid. Note that this will fail horribly if you ever have a non-int member.
A more general solution would be to maintain an array of field offsets:
int offsets[3];
void initOffsets()
{
struct Element e;
offsets[0] = (int)&e.x - (int)&e;
offsets[1] = (int)&e.y - (int)&e;
offsets[2] = (int)&e.z - (int)&e;
}
int getval(struct Element *ep, int n)
{
return *((int*)((int)ep+offsets[n]));
}
This will work in the sense that you'll be able to call getval for any of the int fields of your struct, even if you have other non-int fields in your struct, since the offsets will all be correct. However, if you tried to call getval on one of the non-int fields it would return a completely wrong value.
Of course, you could write a different function for each data type, e.g.
double getDoubleVal(struct Element *ep, int n)
{
return *((double*)((int)ep+offsets[n]));
}
and then just call the proper function for whichever datatype you'd want. Incidentally, if you were using C++ you could say something like
template<typename T>
T getval(struct Element *ep, int n)
{
return *((T*)((int)ep+offsets[n]));
}
and then it would work for whatever datatype you'd want.
If your struct was anything except bitfields, you could just use array access, if I'm right in remembering that C guarantees that a series of members of a struct all of the same type, has the same layout as an array. If you know which bits in what order your compiler stores bitfields into integer types, then you could use shift/mask ops, but that's then implementation-dependent.
If you want to access bits by variable index, then it's probably best to replace your bitfields with an integer containing flag bits. Access by variable really isn't what bitfields are for: a1 ... an are basically independent members, not an array of bits.
You could do something like this:
struct Element {
unsigned int a1 : 1;
unsigned int a2 : 1;
...
unsigned int an : 1;
};
typedef unsigned int (*get_fn)(const struct Element*);
#define DEFINE_GETTER(ARG) \
unsigned int getter_##ARG (const struct Element *ep) { \
return ep-> a##ARG ; \
}
DEFINE_GETTER(1);
DEFINE_GETTER(2);
...
DEFINE_GETTER(N);
get_fn jump_table[n] = { getter_1, getter_2, ... getter_n};
int getval(struct Element *ep, int n) {
return jump_table[n-1](ep);
}
And some of the repetition could be avoided by the trick where you include the same header multiple times, each time having defined a macro differently. The header expands that macro once for each 1 ... N.
But I'm not convinced it's worth it.
It does deal with JaredPar's point that you're in trouble if your struct mixes different types - here all the members accessed via a particular jump table must of course be of the same type, but they can have any old rubbish in between them. That still leaves the rest of JaredPar's points, though, and this is a lot of code bloat for really no benefit compared with the switch.
No, there is no simple way to do this easier. Especially for bitfields, that are hard to access indirectly through pointers (you cannot take the address of a bitfield).
You can of course simplify that function to something like this:
int getval(const struct Element *ep, int n)
{
switch(n)
{
case 1: return ep->a1;
case 2: return ep->a2;
/* And so on ... */
}
return -1; /* Indicates illegal field index. */
}
And it seems obvious how the implementation can be further simplified by using a preprocessor macro that expands to the case-line, but that's just sugar.
If the structure really is as simple as described, you might use a union with an array (or a cast to an array) and some bit-access magic (as in How do you set, clear and toggle a single bit in C?).
As Jared says, the general case is hard.
I think your real solution is to not use bitfields in your struct, but instead define either a set type or a bit array.
I suggest code generation. If your structures don't contain huge amount of fields you can auto generate routines for each field or for a range of fields
and use them like:
val = getfield_aN( myobject, n );
or
val = getfield_foo( myobject );
If you have
Only bitfields, or all the bitfields first in your struct
less than 32 (or 64) bitfields
then this solution is for you.
#include <stdio.h>
#include <stdint.h>
struct Element {
unsigned int a1 : 1;
unsigned int a2 : 1;
unsigned int a3 : 1;
unsigned int a4 : 1;
};
#define ELEMENT_COUNT 4 /* the number of bit fields in the struct */
/* returns the bit at position N, or -1 on error (n out of bounds) */
int getval(struct Element* ep, int n)
{
if(n > ELEMENT_COUNT || n < 1)
return -1;
/* this union makes it possible to access bit fields at the beginning of
the struct Element as if they were a number.
*/
union {
struct Element el;
uint32_t bits;
} comb;
comb.el = *ep;
/* check if nth bit is set */
if(comb.bits & (1<<(n-1))) {
return 1;
} else {
return 0;
}
}
int main(int argc, char** argv)
{
int i;
struct Element el;
el.a1 = 0;
el.a2 = 1;
el.a3 = 1;
el.a4 = 0;
for(i = 1; i <= ELEMENT_COUNT; ++i) {
printf("el.a%d = %d\n", i, getval(&el, i));
}
printf("el.a%d = %d\n", 8, getval(&el, 8));
return 0;
}
Based on eli-courtwright solution but without using array of field offsets
......
if you have a structure containing pointer field like this, maybe you could write:
struct int_pointers
{
int *ptr1;
int *ptr2;
long *ptr3;
double *ptr4;
std::string * strDescrPtr;
};
Then you know that every pointer has a 4 bytes offset from a pointer to the structure, so you can write:
struct int_pointers ptrs;
int i1 = 154;
int i2 = -97;
long i3 = 100000;
double i4 = (double)i1/i2;
std::string strDescr = "sample-string";
ptrs.ptr1 = &i1;
ptrs.ptr2 = &i2;
ptrs.ptr3 = &i3;
ptrs.ptr4 = &i4;
ptrs.strDescrPtr = &strDescr;
then, for example, for a int value you can write:
int GetIntVal (struct int_pointers *ep, int intByteOffset)
{
int * intValuePtr = (int *)(*(int*)((int)ep + intByteOffset));
return *intValuePtr;
}
Calling it by:
int intResult = GetIntVal(&ptrs,0) //to retrieve the first int value in ptrs structure variable
int intResult = GetIntVal(&ptrs,4) //to retrieve the second int value in ptrs structure variable
and so on for the others structure fields values (writing other specific functions and using correct bytes offset value (multiple of 4)).
Although the OP specifies that we shouldn't care about the contents of the struct, since they are just bitfields would it be possible to use a char or int (or whatever data type has the size required) to create an n-bit "array" in this case?
void writebit(char *array, int n)
{
char mask = (1 << n);
*array = *array & mask;
}
with the char types replaced with a larger type if a longer "array" was needed. Not sure this is a definitive solution in other structs but it should work here, with a similar readbit funcition.
If you want to access your structure using both element index:
int getval(struct Element *ep, int n)
and by name:
ep->a1
then you are stuck with some hard to maintain switch like method that everyone has suggested.
If, however, all you want to do is access by index and never by name, then you can be a bit more creative.
First off, define a field type:
typedef struct _FieldType
{
int size_in_bits;
} FieldType;
and then create a structure definition:
FieldType structure_def [] = { {1}, {1}, {1}, {4}, {1}, {0} };
The above defines a structure with five elements of size 1, 1, 1, 4 and 1 bits. The final {0} marks the end of the definition.
Now create an element type:
typedef struct _Element
{
FieldType *fields;
} Element;
To create an instance of an Element:
Element *CreateElement (FieldType *field_defs)
{
/* calculate number of bits defined by field_defs */
int size = ?;
/* allocate memory */
Element *element = malloc (sizeof (Element) + (size + 7) / 8); /* replace 7 and 8 with bits per char */
element->fields = field_defs;
return element;
}
And then to access an element:
int GetValue (Element *element, int field)
{
/* get number of bits in fields 0..(field - 1) */
int bit_offset = ?;
/* get char offset */
int byte_offset = sizeof (Element) + bit_offset / 8;
/* get pointer to byte containing start of data */
char *ptr = ((char *) element) + byte_offset;
/* extract bits of interest */
int value = ?;
return value;
}
Setting values is similar to getting values, only the final part needs changing.
You can enhance the above by extending the FieldType structure to include information about the type of value stored: char, int, float, etc, and then write accessors for each type which checks the required type against the defined type.
Why not build getval() in to the struct?
struct Whang {
int a1;
int a2;
int getIth(int i) {
int rval;
switch (i) {
case 1: rval = a1; break;
case 2: rval = a2; break;
default : rval = -1; break;
}
return rval;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Whang w;
w.a1 = 1;
w.a2 = 200;
int r = w.getIth(1);
r = w.getIth(2);
return 0;
}
getIth() would have knowledge of the internals of Whang, and could deal with whatever it contained.

Resources