Referencing a struct member with pointer arithmetic - c

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);

Related

Access structure member char* using offsets

If I have a code:
typedef struct s_ {
int a;
char* b;
} s;
int main()
{
s* st = malloc(sizeof(s));
st->b = malloc(20*sizeof(char));
st->a = 1;
st->b = "foo";
}
Is it possible here to access data in char array using offset?
For example offset here is 4 bytes, I know it and can calculate using for example offsetof() macro, but I can't access data using pointer arithmetics like:
printf("%s", (char*)(st+4));
I would be very happy if someone could help here :)
The answer may be surprising: st+4 actually increments the pointer by 32 bytes!
This is because the type of st is struct s_ * and when you add 4 to that, it is incremented by 4 times the size of the struct.
In order to move by 4 bytes, you need to cast the pointer to char* first and then increment it.
Try this: printf("%s", *(char**)((char*)st + 4));
Edit:
Added *(char**).
It is needed because by incrementing the pointer, we don't get the beginning of the string, we get the address of the pointer to the beginning of the string.
So we need to cast it to the proper type and dereference it.
You can calculate the byte address of the char * element b (which is a char ** value) using (char *)st + offsetof(s, b); therefore you can access the string using code like this:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct s_
{
int a;
char *b;
} s;
int main(void)
{
s *st = malloc(sizeof(s));
st->b = malloc(20 * sizeof(char));
st->a = 1;
strcpy(st->b, "foo");
char *str = *(char **)((char *)st + offsetof(s, b));
printf("[%s]\n", str);
return 0;
}
The output is a line containing [foo].
Now you know why you don't want to have to do this — let the compiler solve it for you:
printf("[%s]\n", st->b);
This question is getting close to Is it possible to dynamically define a struct in C?
If you use printf("%s", (char*)(st+4));,result have been offset 4*struct s
You want to printf the fourth character,could write like this
char *ptr = null;
ptr = st;
printf("[%s]",ptr);

How to assign value to multiple member a structure at once

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);

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

Creating, returning, and casting a struct with a char pointer in C

I'm pretty bad at remembering C rules with structs. Basically, I have a struct like this:
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
Where the char* ptr will only be one character max.
In my program, I have to allocate and free memory to a fake disk (declared globally as char disk[100];) using my own functions:
char disk[100];
void disk_init() {
for(int i = 0; i < 100; ++i) {
disk[i] = memory[i] = 0;
}
}
struct Xalloc_struct* Xalloc(int size) {
// error checking
// ...
// run an algorithm to get a char* ptr back to a part of the global disk
// array, where index i is the index where content at disk[i] starts
char* ptr = &disk[i];
struct Xalloc_struct *ret = malloc(sizeof(struct Xalloc_struct));
ret->size = size;
ret->ptr = malloc(sizeof(char));
ret->ptr = ptr;
return ret;
}
int Xfree(void* ptr) {
struct Xalloc_struct* p = (struct Xalloc_struct*) ptr;
int size = p->size;
int index = *(p->ptr);
// .. more stuff here that uses the index of where p->ptr points to
free(p->ptr);
free(p);
return 0;
}
int main() {
disk_init();
struct Xalloc_struct* x = Xalloc(5);
Xfree(x);
return 0;
}
When this compiles I get quite a few errors:
error: invalid application of ‘sizeof’ to incomplete type ‘struct Xalloc_struct’
struct Xalloc_struct *ret = malloc(sizeof(struct Xalloc_struct));
^
error: dereferencing pointer to incomplete type
ret->size = size;
^
error: dereferencing pointer to incomplete type
free(x->ptr);
^
error: dereferencing pointer to incomplete type
int size = cast_ptr->size;
^
error: dereferencing pointer to incomplete type
int free_ptr = *(cast_ptr->ptr);
^
So, how should I be allocating and deallocating these structs? And how can I modify / edit what they contain?
First problem is Xalloc_struct is a type, not the name of a struct. You declared that type with this:
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
typedef is of the form typedef <type name or struct definition> <name of the type>. So you declared the type Xalloc_struct to be struct { char *ptr; int size; }.
That means you use it like any other type name: Xalloc_struct somevar = ...;.
Had you declared the struct with a name...
struct Xalloc_struct {
char* ptr;
int size;
};
Then it would be struct Xalloc_struct somevar = ...; as you have.
The rule of thumb when allocating memory for an array (and a char * is an array of characters) is you allocate sizeof(type) * number_of_items. Character arrays are terminated with a null byte, so for them you need one more character.
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->ptr = malloc(sizeof(char) * num_characters+1);
But if you're only storing one character, there's no need for an array of characters. Just store one character.
typedef struct {
char letter;
int size;
} Xalloc_struct;
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->letter = 'q'; /* or whatever */
But what I think you're really doing is storing a pointer to a spot in the disk array. In that case, you don't malloc at all. You just store the pointer like any other pointer.
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->ptr = &disk[i];
Then you can read that character with ret->ptr[0].
Since you didn't allocate ret->ptr do not free it! That will cause a crash because disk is in stack memory and cannot be free'd. If it were in heap memory (ie. malloc) it would probably also crash because it would try to free in the middle of an allocated block.
void Xalloc_destroy(Xalloc_struct *xa) {
free(xa);
}
Here's how I'd do it.
#include <stdio.h>
#include <stdlib.h>
char disk[100] = {0};
typedef struct {
char *ptr;
int idx;
} Disk_Handle_T;
static Disk_Handle_T* Disk_Handle_New(char *disk, int idx) {
Disk_Handle_T *dh = malloc(sizeof(Disk_Handle_T));
dh->idx = idx;
dh->ptr = &disk[idx];
return dh;
}
static void Disk_Handle_Destroy( Disk_Handle_T *dh ) {
free(dh);
}
int main() {
Disk_Handle_T *dh = Disk_Handle_New(disk, 1);
printf("%c\n", dh->ptr[0]); /* null */
disk[1] = 'c';
printf("%c\n", dh->ptr[0]); /* c */
Disk_Handle_Destroy(dh);
}
What you are attempting to accomplish is a bit bewildering, but from a syntax standpoint, your primary problems are treating a typedef as if it were a formal struct declaration, not providing index information to your Xalloc function, and allocating ret->ptr where you already have a pointer and storage in disk.
First, an aside, when you are specifying a pointer, the dereference operator '*' goes with the variable, not with the type. e.g.
Xalloc_struct *Xalloc (...)
not
Xalloc_struct* Xalloc (...)
Why? To avoid the improper appearance of declaring something with a pointer type, (where there is no pointer type just type) e.g.:
int* a, b, c;
b and c above are most certainly NOT pointer types, but by attaching the '*' to the type it appears as if you are trying to declare variables of int* (which is incorrect).
int *a, b, c;
makes it much more clear you intend to declare a pointer to type int in a and two integers b and c.
Next, in Xfree, you can, but generally do not want to, assign a pointer type as an int (storage size issues, etc.) (e.g. int index = *(p->ptr);) If you need a reference to a pointer, use a pointer. If you want the address of the pointer itself, make sure you are using a type large enough for the pointer size on your hardware.
Why are you allocating storage for ret->ptr = malloc(sizeof(char));? You already have storage in char disk[100]; You get no benefit from the allocation. Just assign the address of the element in disk to ptr (a pointer can hold a pointer without further allocation) You only need to allocate storage for ret->ptr if you intend to use the memory you allocate, such as copying a string or multiple character to the block of memory allocated to ret->ptr. ret->ptr can store the address of an element in data without further allocation. (it's unclear exactly what you intend here)
You are free to use a typedef, in fact it is good practice, but when you specify a typedef as you have, it is not equivalent to, and cannot be used, as a named struct. That is where your incomplete type issue arises.
All in all, it looks like you were trying to do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
char disk[100] = "";
Xalloc_struct *Xalloc (int size, int i) {
char *ptr = &disk[i];
Xalloc_struct *ret = malloc (sizeof *ret);
ret->size = size;
// ret->ptr = malloc (sizeof *(ret->ptr)); /* you have a pointer */
ret->ptr = ptr;
return ret;
}
int Xfree (void *ptr) {
Xalloc_struct *p = (Xalloc_struct *) ptr;
// int size = p->size; /* unused */
// int index = *(p->ptr); /* what is this ?? */
// .. more stuff here that uses the index of where p->ptr points to
// free (p->ptr);
free (p);
return 0;
}
int main (void) {
int i = 0;
Xalloc_struct *x = Xalloc (5, i++);
Xfree(x);
return 0;
}
Look at the difference in how the typedef is used and let me know if you have any questions.

C Dynamic Array of void pointers

OK, so I've got the following C code:
//for malloc
#include <stdlib.h>
//to define the bool type
#if __STDC_VERSION__ >= 199901L
#include <stdbool.h>
#else
typedef int bool;
#endif
//define structs
typedef struct A{
int integerValue;
char characterValue;
} A;
typedef struct B{
float floatValue;
bool booleanValue;
} B;
int main(int argc, const char * argv[])
{
//allocate a void pointer array
void* myArray[3];
//fill the array with values of different struct types
myArray[0] = malloc(sizeof(A));
myArray[1] = malloc(sizeof(B));
myArray[2] = malloc(sizeof(A));
}
but I want to be able to dynamically resize the array. I know that you can dynamically resize an array containing just one type like this:
int* myArray;
myArray = malloc(3*sizeof(int));
myArray[0] = 3;
myArray = realloc(myArray,4*sizeof(int));
printf("%i",myArray[0]);
but how would you do this in the upper situation (it needs to be able to handle a virtually infinite number of types). Would it work to reallocate the array with realloc(myArray,newNumberOfIndices*sizeof(ElementWithBiggestSize)), or is there a more elegant way to achieve this?
B* b_pointer = (B*) malloc (sizeof(B*));
void** arr = (void**) malloc (3 * sizeof(void*));
arr[0] = b_pointer;
void** new_arr = (void**) malloc (6 * sizeof(A*));
memcpy(new_arr, arr, 3 * sizeof(A*));
// now arr[0] == new_arr[0] == b_pointer;
free(arr);
// now new_arr[0] == b_pointer;
Note that if you're allocating pointers, it doesn't really matter which struct or array (or i don't know what) you want to point to.
PS: happy debugging using void pointer array with different structs
edit: renaming "b_instance to b_pointer", just trying to make it less confusing

Resources