How to assign value to multiple member a structure at once - c

Let's assume that we have a struct that has 4x 1-byte members.
I want to use Xyz as a memory address and cast it as a 32bit pointer then I will assign values to it.
By this, I would able to set all the byte members at once.
This is just an example for my question, char, int, or set to 256 is just arbitrary examples.
#include <stdio.h>
struct temp{
char abc;
char def;
char ghk;
char lmn;
}xyz;
int main()
{
xyz = (struct temp){11,22,33,44};
printf("Byte1 %d\r\n",xyz.abc);
printf("Byte2 %d\r\n",xyz.def);
printf("Byte3 %d\r\n",xyz.ghk);
printf("Byte4 %d\r\n",xyz.lmn);
*((unsigned int*)xyz) = 256;
printf("Byte1 %d\r\n",xyz.abc);
printf("Byte2 %d\r\n",xyz.def);
printf("Byte3 %d\r\n",xyz.ghk);
printf("Byte4 %d\r\n",xyz.lmn);
return 0;
}
Here I prepare a similar approach for the array which is working as expected ;
#include <stdio.h>
char mem[4];
int main()
{
mem[0] = 49;
mem[1] = 50;
mem[2] = 51;
mem[3] = 52;
printf("Byte1 %d\r\n",mem[0]);
printf("Byte2 %d\r\n",mem[1]);
printf("Byte3 %d\r\n",mem[2]);
printf("Byte4 %d\r\n",mem[3]);
*(int*)mem = 256;
printf("Byte1 %d\r\n",mem[0]);
printf("Byte2 %d\r\n",mem[1]);
printf("Byte3 %d\r\n",mem[2]);
printf("Byte4 %d\r\n",mem[3]);
return 0;
}
How can I do the same thing that I did by an array by using struct?

This:
*((unsigned int*)xyz) = 256;
Is a strict aliasing violation. This means you can't take a pointer to one type, cast it to another type, dereference the casted pointer, and expect things to work. The only exception is casting to a pointer to char * to read the individual bytes of some other type.
What you can do however is use a union. It is permitted to write to one member of a union and read from another to reinterpret the bytes as a different type. For example:
union u {
int i;
struct {
char c1;
char c2;
char c3;
char c4;
} s;
};
...
union u u1;
u1.i = 256;
printf("byte1=%02x\n", u1.c1);
printf("byte2=%02x\n", u1.c2);
printf("byte3=%02x\n", u1.c3);
printf("byte4=%02x\n", u1.c4);

Related

Referencing a struct member with pointer arithmetic

I've got a struct definition,
struct liste{
unsigned int size;
unsigned int capacity;
char* data;
};
and an instance,
struct liste lst = {3, 4, "hi"};
and what I'm trying to do is get the data member without directly calling lst.data. So far I've been able get a pointer, dataC ;
char* dataC = (char *) ((char *)&lst + 2 * sizeof(unsigned int));
whereby printing dataC and &lst.data as pointers gives the same output. I thought dereferencing dataC and casting the result to a char * would yield a pointer identical lst.data but I get a segfault.
Is there something I'm missing??
According to your code, dataC does not store the address of the data "hi", but the address of the pointer of lst.data. You can see the code below. dataC is the address of lst.data. *dataC is the address of the string "hi", the same as lst.data.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<stdint.h>
struct liste{
unsigned int size;
unsigned int capacity;
char *data;
};
int main()
{
struct liste lst = {3, 4,"hi"};
char **dataC = (char **) ((char *)&lst + 2 * sizeof(unsigned int));
printf("datac = %s\n",(*dataC));
}
Your code is neither portable nor rugged, because there might be struct padding inside the struct. If you need to do something like you attempt here, you should be using the offsetof macro, which is used to get the byte offset of a member inside a struct. Example:
#include <stdio.h>
#include <stddef.h> // offsetof
struct liste{
unsigned int size;
unsigned int capacity;
char* data;
};
int main (void)
{
struct liste lst = {3, 4, "hi"};
char** ptrptr = (char**) ((char*)&lst + offsetof(struct liste, data)) ;
puts(*ptrptr);
}
Notably the (char*)&list part has nothing to do with the data we are looking for being of char type. This is simply a way of iterating through a larger data type byte by byte, which C allows if we use character pointers. We end up with a character pointer pointing at the location of (the pointer) data inside the struct. By casting the result to char**, we make it clear that whatever we are pointing at is a char*.
Similarly, we could get the capacity member like this:
unsigned int** pp_cap = (unsigned int**) ((char*)&lst + offsetof(struct liste, capacity)) ;
printf("%d\n", *pp_cap);

Problem with copy values from a simple table to a table from structure for a specified address in C Code

I have a problem with this code when I want to copy value from a table to another table in a structure with a specified address of the table in the structure.
I put the code example below. If I use PtrTableStruct, that does not work. If I use PtrTableStruc2, that works but no address is specified. Somebody can help me, please :)
typedef struct
{
unsigned short Table_Truc[256];
unsigned short Table_Essai[256];
} ESSAI_STRUC_TABLE;
int main(int argc, char *argv[]) {
unsigned char TheTable[2];
ESSAI_STRUC_TABLE *PtrStruct = (ESSAI_STRUC_TABLE*) 0x1000000;
unsigned char* PtrTableStruct = (unsigned char*) &PtrStruct->Table_Essai[0];
unsigned char* PtrTableStruct2 = (unsigned char*) malloc(256 * sizeof(unsigned short));
printf("address TheTable 0x%x\n",TheTable);
printf("address PtrStruct 0x%x\n", PtrStruct);
printf("address PtrTableStruct 0x%x\n", PtrTableStruct);
printf("address PtrTableStruct2 0x%x\n", PtrTableStruct2);
TheTable[0] = 100;
TheTable[1] = 101;
unsigned char * NewTable = TheTable;
int iter;
for(iter=0;iter<2;iter++){
*PtrTableStruct++ = *NewTable++; // that does not work
// *PtrTableStruct2++ = *NewTable++; // that works
}
return 0;
}
This assignment:
ESSAI_STRUC_TABLE *PtrStruct = (ESSAI_STRUC_TABLE*) 0x1000000;
is probably not going to do what you expect it to. There is nothing to indicate sufficient memory is allocated at address 0x1000000, or that that location is owned by your process.
In general, since you have:
typedef struct
{
unsigned short Table_Truc[256];
unsigned short Table_Essai[256];
} ESSAI_STRUC_TABLE;
...then you can get a pointer to an instance of that struct by creating an instance and a pointer:
ESSAI_STRUC_TABLE instanceOfTable[2] = {0}, *ptrToInstanceOfTable = NULL;
...and assigning the pointer to the address of the instance:
ptrToInstanceOfTable = &instanceOfTable[0];//pointer is pointing
//to legal memory owned by the process.
Now, ptrToInstanceOfTable is pointing to an area of memory sufficient for an array of 2 ESSAI_STRUC_TABLE.
By the same reasoning, this statement:
unsigned char * NewTable = TheTable;
Can be written as:
unsigned char *NewTable = &TheTable[0];

C Converting a struct to an array of bytes and back again

I want to convert a struct to an array of bytes, and back again taking the bytes and converting/casting them to the struct.
here's some hypothetical code:
let's assume we have a struct foo
struct foo
{
int x;
float y;
} typedef foo;
assuming that we have already allocated some memory of 1000 bytes, i want to be able to put the bytes that the struct above represents into my already allocated 1000 bytes.
How about memcpy(ptrToAllocedMemory, &structOnStack, sizeof(structOnStack));?
Too convert a struct to an array of bytes ...
Simple assigned via a union. The members of foo will be copied with the assignment, perhaps any padding too. #Eric Postpischil
struct foo {
int x;
float y;
} typedef foo;
foo data_as_foo;
union x_foo {
foo bar;
unsigned char array_o_bytes[sizeof foo];
} x;
x.bar = data_as_foo;
// Do something with x.array_o_bytes
for (unsigned i = 0; i < sizeof x.array_o_bytes; i++) {
printf("%2X ", x.array_o_bytes[i]);
}
An assignment is not even needed.
union x_foo = { .bar = data_as_foo );
What is important about return trip for bytes without alignment to foo is to use memcpy().
foo bytes_to_foo(const unsigned char *data) {
foo y;
memcpy(&y, data, sizeof y);
return y;
}
If the bytes are aligned, as a member of union x_foo, than an assignment is sufficient.
union x_foo data_as_bytes;
// data_as_bytes.array_o_bytes populated somehow
foo data_as_foo = x_foo data_as_bytes.bar;
You can simply make a pointer to the address, cast it and handle it from there.
A full code snipping demonstrating what you asked:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct foo
{
int x;
float y;
} typedef foo;
int main () {
char *mem = malloc(1000); // preallocated memory as requested
foo bar; // initial struct
bar.x = 10; // initialize struct
bar.y = 12;
char *ptr =(char*)(&bar); //cast a char ptr to bar's address
memcpy(mem, ptr, sizeof(foo)); // copy it over
foo *result = (foo *)(mem); // cast the memory to a pointer to foo
printf("%d, %f\n", result->x,result->y); // and it works!
return 0;
}
If you wanted to cast the pointer and copy it in one line, you could also do
memcpy(mem,(char*)(&bar), sizeof(foo));
For the same effect.
All variables and struct in C are stored in memory, and memory is already array of bytes.
So, in contrast to Java or C#, you do not need to do any additional transformation:
// to get struct's bytes just convert to pointer
struct foo tmp;
unsigned char* byte_array = (unsigned char*)&tmp;
// from bytes to struct
_Alignas(struct foo) unsigned char byte_array2[sizeof(struct foo)];
struct foo* tmp2 = (struct foo*)byte_array2;
as people are pointing in comments - conversion from array to struct could lead to UB on some platforms, so its better to avoid it unless you allocated properly aligned block

assign value to member of struct pointer, within multiple struct pointers and arrays

long title. but it is the exact problem i am having.
it may be a misunderstanding of how the struct pointer works, or a problem using tthe correct format. i have the following typedefs of structs combined in a big 'box' for easy passing around the configuration.
typedef struct NTC_network{
unsigned char NET_ID;
unsigned char DEV_ADDR;
}NTC_network;
typedef struct NTC_io_trx_link{
enum NTC_IO_LINK own_io;
unsigned char ADDR;
enum NTC_IO_LINK trx_io;
}NTC_io_trx_link;
//struct to hold status of I/O. 0==OFF 1==ON
typedef struct NTC_config_stpio{
unsigned char L1:1;
unsigned char L2:1;
unsigned char L3:1;
unsigned char L4:1;
unsigned char E1:1;
unsigned char E2:1;
unsigned char T1:1;
unsigned char T2:1;
}NTC_config_stpio;
typedef struct NTC_header {
unsigned char NET_ID;
unsigned char DST; //destination address
unsigned char SRC; //source address
unsigned char PCKT;
}NTC_header;
typedef struct NTC_default_setup{
unsigned char DEFAULT_SETUP:1;
}NTC_default_setup;
typedef struct NTC_data{
unsigned char E1; //resistor value to emulate on E1
unsigned char E2; //resistor value to emulate on E2
unsigned char T1; //resistor value of temperature sensor on T1
unsigned char T2; //resistor value of temperature sensor on T2
unsigned char D1; //230VAC detection circuit on/off
unsigned char D2; //230VAC detection circuit on/off
unsigned char ALRM; //alarm on off 0xFF=alarm on, 0x00=alarm off
}NTC_data;
typedef struct NTC_ack{
unsigned char ACK; //ACK field 0x00=no ack 0xFF= ack
}NTC_ack;
typedef struct NTC_config {
NTC_default_setup *DEFAULT_STP;
NTC_config_stpio *STPIO;
NTC_config_network *NETWORK;
NTC_io_trx_link *NTC_link_io;
}NTC_config;
//struct for payload to send via LoRa
typedef struct NTC_payload{
NTC_header *Header;
enum NTC_dc DC;
NTC_config *Config;
NTC_data *Data;
NTC_ack *Ack;
}NTC_payload;
typedef struct NTC_runtime_data{
NTC_payload *pPayload;
}NTC_runtime_data;
and allocating the whole thing at runtime as such:
NTC_runtime_data* init_struct_runtime_data(void){
NTC_runtime_data *DATA = calloc(1, sizeof(NTC_runtime_data));
DATA->pPayload = calloc(2, sizeof(NTC_payload));
for(int i = 0 ; i < 2; i++){
DATA->pPayload[i].Header = calloc(1, sizeof(NTC_header));
DATA->pPayload[i].DC = NONE;
DATA->pPayload[i].Config = calloc(1, sizeof(NTC_config));
DATA->pPayload[i].Config->DEFAULT_STP = calloc(1, sizeof(NTC_default_setup));
DATA->pPayload[i].Config->STPIO = calloc(1, sizeof(NTC_config_stpio));
DATA->pPayload[i].Config->NETWORK = calloc(1, sizeof(NTC_config_network));
DATA->pPayload[i].Config->NETWORK->NTC_NETWORK = calloc(1, sizeof(NTC_network));
DATA->pPayload[i].Config->NTC_link_io = calloc(11, sizeof(NTC_io_trx_link));
for(int j = 0; j < 11; j++){
DATA->pPayload[i].Config->NTC_link_io[j].own_io = j + 1;
}
DATA->pPayload[i].Data = calloc(1, sizeof(NTC_data));
DATA->pPayload[i].Ack = calloc(1, sizeof(NTC_ack));
}
return DATA;
}
i am allocating 2 pPayload. one for TX data and one for RX.
all this works fine and there is no problem what so ever assigning values like so:
NTC_runtime_data *pDATA;
pDATA = init_struct_runtime_data();
and then where ever i might pass this struct i can assign as follows:
pData->pPayload[0].Header->NET_ID = 0x20;
but i am having problems with trying to assign from a struct containing an array as a buffer which looks like this:
typedef struct TRX_buffer{
size_t used;
size_t size;
unsigned char *array;
}TRX_buffer;
and initializing and reallocating as so:
TRX_buffer* init_struct_trx_buffer(void){
TRX_buffer *trx_buffer = malloc(sizeof(TRX_buffer));
trx_buffer->array = malloc(4 * sizeof(unsigned char));
trx_buffer->size = 4;
trx_buffer->used = 0;
return trx_buffer;
}
//inserts a byte of data in the buffer and dynamically allocates the buffer
void insert_array(TRX_buffer *trxbuffer, unsigned char data){
if(trxbuffer->used == trxbuffer->size){
trxbuffer->size *= 2;
trxbuffer[0].array = realloc(trxbuffer[0].array, trxbuffer->size * sizeof(unsigned char));
}
trxbuffer[0].array[trxbuffer->used] = data;
trxbuffer->used++;
}
so the problem is, some where in my program ,in a function, where i am creating a new instance of the buffer and load data from the radio, which i can see when debugging, i want to load it to my struct and i do it like this
NTC_payload* get_payload(NTC_payload *pPayload){
TRX_buffer *rx_buffer;
rx_buffer = init_struct_trx_buffer();
r_FIFO(rx_buffer);
pDATA->pPayload[1].Header->NET_ID = trx_buffer->array[0];
the correct data is in the trx_buffer after my r_FIFO() function. but this isn't working. i have tried different methods. but cant get it to take the value from my buffer and assign it to my struct.
what is wrong??
You are not returning anything from init_struct_runtime_data(), so pDATA = init_struct_runtime_data(); gets whatever happened to be in the return register.
Any decent compiler should flag this, if yours doesn't do yourself a favour and uninstall it.
ps: there is a faq around here somewhere that talks about posting complete programs so people can try them with their tools. It is a good idea, because simply reducing the problem to a publishable version reveals the problem.

Array/Pointer: Left operand must be l-value

I've just started out with C and I'm struggling to get to grips when mixing pointers and arrays.
I am getting the following error:
error C2106: '=' : left operand must be l-value
#include <stdio.h>
struct PersonDetails {
char *name;
int *phoneNumber;
};
int* getPhoneNumber(struct PersonDetails *phoneBook[], char* name);
int main() {
struct PersonDetails a;
struct PersonDetails b;
struct PersonDetails people[2];
struct PersonDetails *ptr[2];
char aName = 'T';
int aNum = 123;
char bName = 'O';
int bNum = 456;
a.name = &aName;
a.phoneNumber = &aNum;
b.name = &bName;
b.phoneNumber = &bNum;
people[0] = a;
people[1] = b;
ptr = &people;
printf("%d", *getPhoneNumber(ptr, aName));
return 0;
}
int* getPhoneNumber(struct PersonDetails *phoneBook[], char* name) {
int i;
for (i = 0; i < 2; i++) {
if (*phoneBook[i]->name == *name) return phoneBook[i]->phoneNumber;
}
return 0;
}
It's happening on the line:
ptr = &people;
Edited Code:
#include <stdio.h>
struct PersonDetails {
char *name;
int *phoneNumber;
};
int* getPhoneNumber(struct PersonDetails *phoneBook[], char* name);
int main() {
struct PersonDetails a;
struct PersonDetails b;
struct PersonDetails people[2];
struct PersonDetails *ptr;
char aName = 'T';
int aNum = 123;
char bName = 'O';
int bNum = 456;
a.name = &aName;
a.phoneNumber = &aNum;
b.name = &bName;
b.phoneNumber = &bNum;
people[0] = a;
people[1] = b;
ptr = people;
printf("%d", *getPhoneNumber(ptr, aName));
return 0;
}
int* getPhoneNumber(struct PersonDetails *phoneBook, char* name) {
int i;
for (i = 0; i < 2; i++) {
if (*phoneBook[i].name == *name) return phoneBook[i].phoneNumber;
}
return 0;
}
Transferring sundry comments of mine in dialogue with the OP into an answer
Because the method getPhoneNumber() requires the parameter struct PersonDetails *phoneBook[].
Why does getPhoneNumber() require that eccentric type? There must be a reason why you chose to use it (like "the teacher set that in the question I'm working on"). Otherwise, it seems more likely that the parameter should be either struct PersonDetail *who or struct PersonDetail who[] — which, in the context of a function's parameter list (and only in the context of a function's parameter list) amounts to the same thing.
Originally it was PersonDetails *phoneBook, but I didn't think that would work? Am I wrong in thinking that, and how would I go about using that to find a number using a name?
Assuming you mean struct PersonDetails *phoneBook (there isn't a type PersonDetails in your code, but there is the type struct PersonDetails), then that would work fine. It is a pointer parameter that can either point to a single person's details, or to the start of an array of people's details. Inside the function, as long as you know that the array is big enough, you can use phoneBook[i].name or phoneBook[i].number with care. (Or, indeed, phoneBook->name and phoneBook->number, which refer to the single element pointed at by phoneBook, or you can think of it as using an effective subscript of 0.)
Oh wow, thank you, that helps so much. So I would change ptr to just struct PersonDetails *ptr; as opposed to an array of pointers?
Yes — using struct PersonDetails *ptr; is all you need. You are (accidentally) delving into more complex structures which do have a place in more complex situations, which is why no-one could say "this is wrong", but they're currently beyond what you need, or what you currently understand. That's OK; what you've just learned probably covers 95% or more of real life use cases.
Okay, it all compiles now, but crashes when executed. I have a feeling it has something to do with how I'm assigning both ptr and people. Do I just delete the people array? I've added an edited section in the question if you could have a look for me please?
You are now passing a char value, aName, where the function expects a char *, which would be &aName. The function prototype at the top also doesn't match the function definition; the definition is correct. You need to remove either the * or the [] but not both from the prototype. With that, it 'works'.
Be aware that you don't have strings (the char * values do not point to null terminated arrays of characters) so you can't do string comparison (strcmp()), but fixing that is probably the next phase of development.
Your compiler should have been generating warnings; pay heed. Remember, it knows a lot more about C than you do at the moment!
Working code
#include <stdio.h>
struct PersonDetails
{
char *name;
int *phoneNumber;
};
int *getPhoneNumber(struct PersonDetails *phoneBook, char *name);
int main(void)
{
struct PersonDetails a;
struct PersonDetails b;
struct PersonDetails people[2];
struct PersonDetails *ptr;
char aName = 'T';
int aNum = 123;
char bName = 'O';
int bNum = 456;
a.name = &aName;
a.phoneNumber = &aNum;
b.name = &bName;
b.phoneNumber = &bNum;
people[0] = a;
people[1] = b;
ptr = people;
printf("%d\n", *getPhoneNumber(ptr, &aName));
return 0;
}
int *getPhoneNumber(struct PersonDetails *phoneBook, char *name)
{
int i;
for (i = 0; i < 2; i++)
{
if (*phoneBook[i].name == *name)
return phoneBook[i].phoneNumber;
}
return 0;
}
Note that printing the result directly as shown will fail horribly (usually) if the 'name' is not found. You'll be dereferencing a null pointer, which invokes undefined behaviour — A Bad Thing™! You really need to use:
int *p_number = getPhoneNumber(ptr, &name);
if (p_number == NULL)
printf("No entry for name %c\n", name);
else
printf("Number for %c is %d\n", name, *p_number);
You should also review why you have int *number; instead of just int number; or char *number;. The former is better if you simply store an unformatted integer; the latter is better if you might need to store +44 1395 276679 or something like that, though you should then consider the relative merits of char number[MAX_PHONE_NUMBER_STRING_LEN]; instead of a pointer.
Also, for more nearly general-purpose code, your function should probably be told how many entries there are in the phone-book, rather than using a hard-wired size of 2 (which is a pretty minimal phone-book by any standard):
int *getPhoneNumber(int n_entries, struct PersonDetails *phoneBook, char *name)
{
int i;
for (i = 0; i < n_entries; i++)
{
if (*phoneBook[i].name == *name)
return phoneBook[i].phoneNumber;
}
return 0;
}
Where the number of entries in the array is a parameter. Assuming you have C99 or C11, you could also sensibly write that as:
int *getPhoneNumber(int n_entries, struct PersonDetails phoneBook[n_entries], char *name)
{
for (int i = 0; i < n_entries; i++)
{
if (*phoneBook[i].name == *name)
return phoneBook[i].phoneNumber;
}
return 0;
}
In both these last samples, I've not changed the data types in the structure (even though I think they should be changed). I've also not added const qualifiers to the pointer/array or the name, even though both could legitimately be const-qualified.
struct PersonDetails *ptr[2];
ptr is an array of pointers and array itself is never a modifiable value. lvalue should be some location where you store values(like variable). So this is an error.
You define as follows -
struct PersonDetails people[2];
struct PersonDetails *ptr[2];
which means the people is a 2-element array of structs of type PersonDetails, while ptr is a 2-element array of pointers to such structs.
You can't override the address of an array, it's not just some pointer (although there are some mutual semantics), it's allocated on the stack.
If you meant each element in ptr to point to the respective people element, use a loop:
for (i = 0; i < 2; ++i)
ptr[i] = &people[i];
Also note that one of the effects of passing around all these pointers to simple variables defined in main, is that you can return a null pointer from getPhoneNumber, and pass it to printf - that would segfault
ptr is an array of pointers to struct PersonDetails, so ptr[0] and ptr[1]
are pointers to struct PersonDetails, then you can asign the address of a variable of the type struct PersonDetails to each element of ptr.
in C an array is something like a pointer (but it's not exactly the same) which points to a part of the
memory (with the size of the type of variables times the numbers of elements of the array) where you can store one or more variables of one type, so in
your example, you could see people like a pointer to struct PersonDetails, and ptr like a pointer to a pointer to struct PersonDetails.
So, with all that said, what you can do is ptr[0] = people or ptr[1] = people.

Resources