If when passing to functions we treat parameters uint32_t data[] and uint32_t* data as both being pointers to an array of data, why is the same not true when setting a member of a struct? Quick example:
#include <stdint.h> /* uint32_t */
#include <string.h> /* memcpy */
#include <stdlib.h> /* malloc */
typedef struct {
uint32_t data[1024];
} tData;
typedef struct {
uint32_t *data;
} pData;
int main()
{
// structs
pData pdata;
tData sdata;
// Test 1.
///////////////////////////////////
uint32_t mydata[1024];
// This is OK
pdata.data = mydata;
// This is not OK
sdata.data = mydata;
// But this is OK
memcpy(sdata.data, mydata, 1024);
// Test 2.
///////////////////////////////////
uint32_t *otherdata = malloc(sizeof(uint32_t)*1024);
// This is OK
pdata.data = otherdata;
// This is not OK
sdata.data = otherdata;
// But this is OK
memcpy(sdata.data, otherdata, 1024);
}
In order to satisfy the struct tData must I do a memcpy? Is this the only way?
It looks like an attempt to assign an array directly, something like this (without structs)
int A[10];
int B[10];
int *ptr;
ptr = A; // OK
A = B; // Not ok
assigning array to pointer will make the pointer to point to the first element of the array, while comparing 2 arrays directly is not allowed.
The example with memcpy is equal to copying elements(their memory) one by one. so you can also do something like this.
for(int i = 0; i < 1024; ++i)
sdata.data[i] = mydata[i];
Related
I am trying to simulate a memory manager in C language. I need help solving a problem with assigning uint64_t values into an uint64_t** array elements.
After writing the code, I tested it by trying to write several values.
ex:- 0x2222222222222222, 0x33, 0x11111111 ....
This is my complete code.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
struct Memory{
int hashtablesize;
uint32_t **hashtable; // The array address in use
uint64_t **values; // Stored values
void (*write)(uint32_t *address, struct Data *data, struct Memory *mem);
void (*read)(uint32_t *address, struct Data *data, struct Memory *mem);
int (*cell_index)(uint32_t *address, struct Memory *mem);
void (*extend_hashtable)(struct Memory *mem);
void (*dump)(struct Memory *mem);
};
struct Data{
enum Type {UINT8,UINT16,UINT32,UINT64} type;
uint64_t* value;
};
void write(uint32_t *address, struct Data *data, struct Memory *mem){
int cell_index = mem->cell_index(address,mem);
if(data->type==UINT8){
uint64_t value = *((uint64_t*)data->value) & 0x00000000000000FF;
mem->values[cell_index]=value;
}
if(data->type==UINT16){
uint64_t value = *((uint64_t*)data->value) & 0x000000000000FFFF;
mem->values[cell_index]=value;
}
if(data->type==UINT32){
uint64_t value = *((uint64_t*)data->value) & 0x00000000FFFFFFFF;
mem->values[cell_index]=value;
}
if(data->type==UINT64){
uint64_t value = *((uint64_t*)data->value) & 0xFFFFFFFFFFFFFFFF;
mem->values[cell_index]=value;
}
mem->hashtable[cell_index]=*address;
}
//void read(uint32_t *address, struct Data *data, struct Memory *mem){
// To be implemented
//}
// Return the index of the given address from **hashtable
int cell_index(uint32_t *address, struct Memory *mem){
int hashtablesize = mem->hashtablesize;
for(int i;i<hashtablesize;i++){
if(mem->hashtable[i]==*address){
return i;
}
}
mem->extend_hashtable(mem);
return mem->hashtablesize-1;
}
// This function dynamically allocate memory for new memory addresses
void extend_hashtable(struct Memory *mem){
int hashtablesize = mem->hashtablesize;
uint32_t **new_hashtable = (uint32_t*)malloc(sizeof(uint32_t*)*(hashtablesize+1));
uint64_t **new_values = (uint64_t*)malloc(sizeof(uint64_t*)*(hashtablesize+1));
memset(new_hashtable, 0, (hashtablesize+1) * sizeof(uint32_t*));
memset(new_values, 0, (hashtablesize+1) * sizeof(uint64_t*));
for(int i;i<hashtablesize;i++){
new_hashtable[i] = (uint32_t*)malloc(sizeof(uint32_t));
memset(new_hashtable[i], 0, sizeof(uint32_t));
new_hashtable[i] = mem->hashtable[i];
}
for(int i;i<hashtablesize;i++){
new_values[i] = (uint64_t*)malloc(sizeof(uint64_t));
memset(new_values[i], 0, sizeof(uint64_t));
new_values[i] = mem->values[i];
}
mem->hashtable = new_hashtable;
mem->hashtablesize+=1;
mem->values = new_values;
}
// Print out the addresses and store values
void dump(struct Memory *mem){
int hashtablesize = mem->hashtablesize;
for(int i;i<hashtablesize;i++){
printf("Memory Address: %x, \t Value: %u\n",mem->hashtable[i],mem->values[i]);
}
printf("Memory dump success\n");
}
In the dump method, the used addresses and the stored values will be printed.
I tried to write the following value in order. Please consider that I provided Data objects (structs) with the correct type.
0x11111111 #(type : UINT32)
0x2222222222222222 #(type : UINT64)
0x33 #(type : UINT8)
I expected the following output.
Memory Address: a, Value: 11111111
Memory Address: 14, Value: 2222222222222222
Memory Address: 1e, Value: 33
Memory dump success
But I got this.
Memory Address: a, Value: f7ff2ba011111111
Memory Address: 14, Value: f7ff2ba022222222
Memory Address: 1e, Value: f7ff2ba000000033
Memory dump success
The first 32 bits are either being overwritten by random values or are not being replaced by the new values I want to write.
I know this is a problem with pointer variables, but can't figure out how to fix this
I tried to figure out if there was any problem with casting by printing the result of casting. That works fine. So the problem is with assigning them into the values in the Memory struct.
This is the code for testing.
#include <stdint.h>
#include <stdio.h>
#include "memory.h"
struct Memory memobj;
struct Memory *mem = &memobj;
int main(){
uint32_t *addresses[3];
uint32_t a1=10,a2=20,a3=30;
addresses[0] = &a1;
addresses[1] = &a2;
addresses[2] = &a3;
uint64_t *values_to_write[3];
struct Data d1,d2,d3;
d1.type=UINT32;
d1.value = malloc(sizeof(uint32_t));
*(uint32_t*)d1.value=0x11111111;
d2.type=UINT64;
d2.value = malloc(sizeof(uint64_t));
*(uint64_t*)d2.value = 0x222222222222222;
d3.type=UINT8;
d3.value = malloc(sizeof(uint8_t));
*(uint8_t*)d3.value = 0x33;
values_to_write[0] = &d1;
values_to_write[1] = &d2;
values_to_write[2] = &d3;
mem->hashtable = (uint32_t**)malloc(sizeof(uint32_t));
mem->values = (uint64_t**)malloc(sizeof(uint64_t));
memset(mem->hashtable,0,sizeof(uint32_t)*1);
memset(mem->values,0,sizeof(uint64_t)*1);
mem->hashtablesize=0;
mem->cell_index = cell_index;
mem->dump = dump;
mem->extend_hashtable = extend_hashtable;
mem->read = read;
mem->write = write;
for(int i=0;i<3;i++){
mem->write(addresses[i],values_to_write[i],mem);
}
mem->dump(mem);
return 0;
}
Can someone tell me how to fix this or where can I find a solution for this?
I've one solid structure and another structure with pointers. The purpose of program is to assign: solid structure to structure with pointers and access each solid structure member using other structure pointer.
I've problem statement: as two structure member as not symmetric, when i assign solid structure address to structure with pointers, member pointer initialization go bad and crash the system.
Does anyone have any approach to find a solution for this problem in an optimized way?
----------------------------------------------------------------------- program -----------------------------
#include <stdio.h>
#include <string.h>
#include <stddef.h>
/* ===================== Binding Structure ================================= */
typedef struct
{
char id;
}tmodel;
typedef struct
{
char id;
}tbrand;
typedef struct
{
char id;
}tcommercialRef;
typedef struct
{
char id;
}tserialnum;
typedef struct
{
tmodel *smodel;
tbrand *sbrand;
tcommercialRef *scommref;
tserialnum *sslnum;
}tmetadata;
typedef struct
{
tmetadata *smetadata;
}tlink;
typedef struct
{
tlink *slink;
}trefernce;
typedef struct
{
char id[10];
int ttl;
int tss;
trefernce *sref;
}telectrical;
/* ===================== Application Strucuture ==============================*/
void filldata(telectrical *elec);
typedef struct
{
tmodel smodel;
tbrand sbrand;
tcommercialRef scommref;
tserialnum sslnum;
}Ymetadata;
typedef struct
{
Ymetadata smetadata;
}slink;
typedef struct
{
slink glink;
}refernce;
typedef struct
{
char id[10];
int ttl;
int tss;
refernce grefernce;
}gtelectrical;
//solid strucutre object
gtelectrical obj;
//structure pointer object
telectrical *elec = {0};
/* =============================== main.c =================================== */
int main()
{
printf("test");
//static void **p = (void *)&elec;
obj.tss = 55;
obj.ttl = 100;
obj.grefernce.glink.smetadata.smodel.id = 5;
obj.grefernce.glink.smetadata.sbrand.id = 6;
obj.grefernce.glink.smetadata.scommref.id = 7;
obj.grefernce.glink.smetadata.sslnum.id = 8;
elec = (telectrical *)&obj;
//elec structure -> sref pointer goes bad as it's not same type as "grefernce"
//*p = (void *)&obj;
//static long x = (long) offsetof( telectrical, sref);
//(long) offsetof(struct telectrical, sref);
//*(*p + x) = obj.grefernce.glink.smetadata.;
elec->id[0] = 0;
elec->id[1] = 1;
elec->id[2] = 2;
elec->ttl = 5;
elec->tss = 10;
elec->sref->slink->smetadata->sslnum->id = 4;
elec->sref->slink->smetadata->sbrand->id = 1;
elec->sref->slink->smetadata->scommref->id = 2;
elec->sref->slink->smetadata->smodel->id = 3;
//filldata(elec);
printf("------");
printf("%d\n",elec->sref->slink->smetadata->sslnum->id);
printf("%d\n",elec->sref->slink->smetadata->sbrand->id);
printf("%d\n",elec->sref->slink->smetadata->scommref->id);
printf("%d\n",elec->sref->slink->smetadata->smodel->id);
return 0;
}
/* //////////////////////////////////////// user scope ////////////////////////////// */
void filldata(telectrical *pelec)
{
pelec->id[0] = 0;
pelec->id[1] = 1;
pelec->id[2] = 2;
pelec->ttl = 5;
pelec->tss = 10;
//pelec->sref->slink->smetadata->sslnum->id = 4;
//pelec->sref->slink->smetadata->sbrand->id = 1;
//pelec->sref->slink->smetadata->scommref->id = 2;
//pelec->sref->slink->smetadata->smodel->id = 3;
}
You are not assigning memory for the pointers to other struct present inside another struct. Here is something which might help you in multi-level memory allocation and assignment:
#include<stdio.h>
#include<stdlib.h>
typedef struct A
{
int i;
}A_Node;
typedef struct B
{
A_Node *A_ptr;
}B_Node;
typedef struct C
{
B_Node *B_ptr;
}C_Node;
int main(void)
{
//ACCESSING-MANIPULATING A USING B
B_Node B_obj;
B_obj.A_ptr=malloc(sizeof(*(B_obj.A_ptr)));
(B_obj.A_ptr)->i=192;
A_Node A_obj=*(B_obj.A_ptr); //For checking if the allocation is successful and good
printf("%d\n",A_obj.i);
//ACCESSING-MANIPULATING A USING C
C_Node C_obj;
C_obj.B_ptr=malloc(sizeof(*(C_obj.B_ptr))); //allocating space for struct of B using C object
(C_obj.B_ptr)->A_ptr = malloc(sizeof(*((C_obj.B_ptr)->A_ptr))); //allocating space for struct of A using B Struct for which space was allocated in previous step by C struct
((C_obj.B_ptr)->A_ptr)->i=876;
A_obj=*((C_obj.B_ptr)->A_ptr); //For checking if the allocation is successful and good
printf("%d\n",A_obj.i);
return 0;
}
Read the code and ask if there are any doubts, in the similar way this multi-level struct-inside-struct can be created (though it would be ugly).
Assuming that the following structures exist...
typedef struct MyFirstStruct
{
uint8_t someContent;
}
typedef struct MySecondStruct
{
MyFirstStruct* firstStructs;
uint8_t firstStructCount;
}
... and a function gets the following Parameter.
const MySecondStruct* const secondStruct
Is it allowed to change any value?
I am sure that this is not correct:
secondStruct->firstStructCount++.
But neither the Compiler nor PC-Lint complains about secondStruct->firstStructs->someContent++.
Is it allowed to do Change someContent because firstStructs is not const or is the behavior undefined?
Thanks!
The values of the nested struct(s) firstStructs can change as long as the pointer does not change. The constness of the pointer prevents the pointer value from changing, but the constness of the struct only means that its values must not change (i.e. the value of the pointer and the count).
You can modify the struct(s) pointed to by firstStructs arbitrarily without changing the pointer. You can also clearly see from the struct definition that this is legal, because firstStructs is a pointer to struct MyFirstStruct, not a pointer to const struct MyFirstStruct.
Here is an example to understand the principle without the const-pointer to const elements:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x;
} Simple;
typedef struct {
Simple* s;
int scount;
} Nested;
int main()
{
Nested x;
x.scount = 10;
x.s = malloc(sizeof(Simple) * x.scount);
const Nested n = x;
for (int i = 0; i < n.scount; ++i)
{
n.s[i].x = i;
printf("%d\n", n.s[i].x);
}
}
It is OK and it was easy to check yourself:
typedef struct
{
uint8_t someContent;
} MyFirstStruct;
typedef struct
{
MyFirstStruct* firstStructs;
uint8_t firstStructCount;
}MySecondStruct;
MyFirstStruct fs;
MySecondStruct str = {.firstStructs = &fs};
const MySecondStruct* const secondStruct = &str;
int main()
{
secondStruct->firstStructs->someContent++;
}
but did not as the posted code was full of syntax errors.
You cant of course change the pointer itself:
This will give you errors:
typedef struct
{
uint8_t someContent;
} MyFirstStruct;
typedef struct
{
MyFirstStruct* firstStructs;
uint8_t firstStructCount;
}MySecondStruct;
MyFirstStruct fs[2];
MyFirstStruct ss;
MySecondStruct str = {.firstStructs = fs};
const MySecondStruct* const secondStruct = &str;
int main()
{
secondStruct->firstStructs++->someContent++;
secondStruct->firstStructs = &ss;
}
I have a huge struct array and I created different function to get the struct pointer based on a member's value:
typedef struct {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} test_t;
test_t test[10]; // Initialized somewhere else
static test_t* __get_struct_by_a(uint_32_t a) {
for (uint32_t i = 0; i < 10; i++) {
if (test[i].a == a)
return &test[i];
}
return NULL;
}
static test_t* __get_struct_by_b(uint_32_t b) {
...
}
Is there an easy way to tackle this in C instead of create a lookup function for every member?
Following is one way to write a general function to get (find) your first matching struct member.
I tried to keep consistent with your sample code, adding a few #include directives that may be necessary, and a typical fixed-array size #define for TEST_SIZE so that you don't use hard-coded values for the loop indices.
#include <stddef.h>
#include <stdio.h>
#include <string.h>
typedef struct {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} test_t;
test_t test[10]; // Initialized somewhere else
#define TEST_SIZE (sizeof(test)/sizeof(test[0]))
static test_t* __get_struct_by_offset(const void* value_ptr, const size_t offset, const size_t field_size)
{
for (uint32_t i = 0; i < TEST_SIZE; i++)
{
if (0 == memcmp(value_ptr, ((unsigned char*)&test[i])+offset, field_size))
{
return &test[i];
}
}
return NULL;
}
You would use it like this:
uint32_t a_value_to_find = 5; /* example field "a" value to find */
uint32_t b_value_to_find = 10; /* example field "b" value to find */
test_t* test_ptr;
/* find specified value for field "a" */
test_ptr = __get_struct_by_offset(&a_value_to_find, offsetof(test_t, a), sizeof(a_value_to_find));
/* find specified value for field "b" */
test_ptr = __get_struct_by_offset(&b_value_to_find, offsetof(test_t, b), sizeof(b_value_to_find));
It's your responsibility to ensure that the data types for *value_ptr and the field at the specified offset are identical, and therefore of the same size (field_size).
To simplify the usage, you could write some macros as shorthand for these calls. For example:
#define GET_A(value) __get_struct_by_offset(&value, offsetof(test_t, a), sizeof(value))
#define GET_B(value) __get_struct_by_offset(&value, offsetof(test_t, b), sizeof(value))
The queries for "a" and "b" are then simplified to:
/* find specified value for field "a" */
test_ptr = GET_A(a_value_to_find);
/* find specified value for field "b" */
test_ptr = GET_B(b_value_to_find);
If I have a struct in C that has an integer and an array, how do I initialize the integer to 0 and the first element of the array to 0, if the struct is a member another struct so that for every instance of the other struct the integer and the array has those initialized values?
Initialisers can be nested for nested structs, e.g.
typedef struct {
int j;
} Foo;
typedef struct {
int i;
Foo f;
} Bar;
Bar b = { 0, { 0 } };
I hope this sample program helps....
#include <stdio.h>
typedef struct
{
int a;
int b[10];
}xx;
typedef struct
{
xx x1;
char b;
}yy;
int main()
{
yy zz = {{0, {1,2,3}}, 'A'};
printf("\n %d %d %d %c\n", zz.x1.a, zz.x1.b[0], zz.x1.b[1], zz.b);
return 0;
}
yy zz = {{0, {0}}, 'A'}; will initialize all the elements of array b[10] will be set to 0.
Like #unwind suggestion, In C all instances created should initialized manually. No constructor kind of mechanism here.
You can 0-initialize the whole struct with {0}.
For example:
typedef struct {
char myStr[5];
} Foo;
typedef struct {
Foo f;
} Bar;
Bar b = {0}; // this line initializes all members of b to 0, including all characters in myStr.
C doesn't have constructors, so unless you are using an initializer expression in every case, i.e. write something like
my_big_struct = { { 0, 0 } };
to initialize the inner structure, you're going to have to add a function and make sure it's called in all cases where the structure is "instantiated":
my_big_struct a;
init_inner_struct(&a.inner_struct);
Here is an alternative example how you would do things like this with object-oriented design. Please note that this example uses runtime initialization.
mystruct.h
#ifndef MYSTRUCT_H
#define MYSTRUCT_H
typedef struct mystruct_t mystruct_t; // "opaque" type
const mystruct_t* mystruct_construct (void);
void mystruct_print (const mystruct_t* my);
void mystruct_destruct (const mystruct_t* my);
#endif
mystruct.c
#include "mystruct.h"
#include <stdlib.h>
#include <stdio.h>
struct mystruct_t // implementation of opaque type
{
int x; // private variable
int y; // private variable
};
const mystruct_t* mystruct_construct (void)
{
mystruct_t* my = malloc(sizeof(mystruct_t));
if(my == NULL)
{
; // error handling needs to be implemented
}
my->x = 1;
my->y = 2;
return my;
}
void mystruct_print (const mystruct_t* my)
{
printf("%d %d\n", my->x, my->y);
}
void mystruct_destruct (const mystruct_t* my)
{
free( (void*)my );
}
main.c
int main (void)
{
const mystruct_t* x = mystruct_construct();
mystruct_print(x);
mystruct_destruct(x);
return 0;
}
You don't necessarily need to use malloc, you can use a private, statically allocated memory pool as well.