-2

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

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Stary
  • 3
  • 1
  • 2
    What do you think `st->b = "foo";` does? – Beta Jan 05 '22 at 00:41
  • `st->b = malloc(20*sizeof(char));` assigns a pointer variable. `st->b = "foo";` assigns this variable again; the previous pointer value will be lost. – wildplasser Jan 05 '22 at 00:41
  • 1
    You could use calculate an offset by casting to `char *` and then adding — `(char *)st + 4`, rather than adding and then casting. – Jonathan Leffler Jan 05 '22 at 00:46
  • 1
    What are you really trying to do? You already have access to the pointer by using `st->b`. So what benefit would you gain by trying to calculate the offset yourself? There is a standard macro to provide the offsets of members within a structure, but it is for use when members need to be access dynamically, which occurs in very limited circumstances. – Eric Postpischil Jan 05 '22 at 00:47
  • @EricPostpischil i have linked list and need to sort them by every data field in structure, so i wrote `bubbleSortList(node** list, size_t fieldOffset, int(*test)(node* n1, node* n2, size_t offset))` function which commits sorting, and some callbacks, for example `sortStringAscending(node* n1, node* n2, size_t offset)` which take nodes to "compare" and offset to field which they neet to actually compare. It's a lot less code if i write it using offsets rather than writing comparing function for every field. – Stary Jan 05 '22 at 10:20

3 Answers3

0

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.

Tomasz Kalisiak
  • 101
  • 2
  • 7
0

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?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • The solution works, thank you! I need to access it through offset because i need to sort linked list by lots of fields, and it's easier to write callback function `sortStringAscending(node* n1, node* n2, size_t offset)` and pass it as argument to my `bubbleSortList(node** list, size_t fieldOffset, int(*test)(node* n1, node* n2, size_t offset))` function, rather than writing custom sorting function for every field. – Stary Jan 05 '22 at 10:33
-1

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