-5

I am trying to assign char array value in a structure and retrieving the data but facing some problem while retrieving.

struct first {
    int a;
    int b; 
};

struct second {
    int c;
    int d;
    struct first * f_t[2]; 
};

int main()
{
    struct second *p;
    char a[24] = {1, 0, 0, 0, 
                  2, 0, 0, 0, 
                  3, 0, 0, 0, 
                  4, 0, 0, 0,
                  5, 0, 0, 0,
                  6, 0, 0, 0};
    p = (struct second *)a;
    p->f_t[0] = (struct first *) (a + 8);
    p->f_t[1] = (struct first *) (a + 16);
    printf("%d %d %d %d %d %d", 
         p->c, p->d, p->f_t[0]->a, p->f_t[0]->b, p->f_t[1]->a, p->f_t[1]->b);
}

Output:

1 2 1245008 1245016 1245024 6

First two values are coming properly (1 and 2) but the rest seems like some garbage values.

Please help to identify some wrong initialization or some other method for the same.

Student
  • 805
  • 1
  • 8
  • 11
avi
  • 7
  • 2
  • Have you tried any debugging? – 9769953 Aug 03 '18 at 11:41
  • 3
    You have two `Struct first`. what is `Struct` (capital S) anyway? It doesn't appear your code is runnable as is. – 9769953 Aug 03 '18 at 11:42
  • 1
    With `p = (struct second *)a;` you break *strict aliasing* and have *undefined behavior*. Don't ever do anything like that. Also, how sure are you that there's no padding in your structures? – Some programmer dude Aug 03 '18 at 11:42
  • I am using structure formatting of data using buffer to structure that why I am using this way. – avi Aug 03 '18 at 11:48
  • 1
    This is clearly a question posed with precision enough to allow specific responses and answers, and enough work to indicate a sincere attempt was made to understand the topic (albeit with some compile errors). The question indicates newness to the topic. That said, surprised at number of down votes. ( Consider offering advice, and links to SO standards over down votes for newer users. ) – ryyker Aug 03 '18 at 13:32
  • Along with a clear question describing the problem you are having with your code, providing a [mcve] is an expected minimum on this site. The code you posted does not compile for several reasons, the most blatant IMO is the usage of `Struct` instead of `struct`, (which I have edit out in your post for you) clearly indicating that posted code is not likely actual code you have been working with. Suggest editing your post to contain same code you have been working with. – ryyker Aug 03 '18 at 13:47

3 Answers3

0

First of all, never assume the padding in a struct. It works fairly reliably, but is technically undefined behavior.

And much more importantly, you are breaking the strict aliasing rule. This is an assumption by the compiler that you never access the same memory location with pointers of different types (in this case, struct first* and char*). You can get around this with the -fno-strict-aliasing or use unions to do type-punning, as it's usually called. Go here for more info.

The more correct version of this code will be -

#include <stdio.h>
#include <stdlib.h>
#include <alloca.h>
#include <string.h>

struct first {
  int a;
  int b; 
};
struct second {
  int c;
  int d;
  struct first * f_t[2]; 
};
int main()
{
  struct second *p;
  char a[24] =        {1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,5,0,0,0,6,0,0,0};
  p = alloca(sizeof(struct second));
  memset(p, 0, sizeof(struct second));
  memcpy(p, a, sizeof(int)*2);
  p->f_t[0]= alloca(sizeof(struct first));
  p->f_t[1]= alloca(sizeof(struct first));
  memset(p->f_t[1], 0, sizeof(struct first));
  memset(p->f_t[0], 0, sizeof(struct first));
  memcpy(p->f_t[0], a + 8, sizeof(struct first));
  memcpy(p->f_t[1], a + 16, sizeof(struct first));
  printf("%d %d %d %d %d %d",p->c,p->d,p->f_t[0]->a,p->f_t[0]->b,p->f_t[1]->a,p->f_t[1]->b);

}

NOTE: Using alloca() is bad practice. Don't use it unless you know what you're doing. It's fine here since it's simply one small struct being allocated on the stack, but in general steer away from it and use malloc() or just use local variables.

This still technically falls under undefined behavior, since we're assuming how the structs are padded, which is implementation specific, but most platforms use self aligned data types and are a lot faster when using properly aligned structures, so it's easy to guess. For more information on this, go here. I still strongly discourage this as this is undefined behavior, and it's very easy to mess up.

Also, the next time onward, make sure to provide a minimal, complete and compilable example.

Shahe Ansar
  • 127
  • 5
  • 1
    *Using alloca() is bad practice.* Bah. `alloca()` is not much different from a [VLA](https://en.wikipedia.org/wiki/Variable-length_array). Have you ever stated that using a VLA is "bad practice"? – Andrew Henle Aug 03 '18 at 12:37
  • @AndrewHenle Yup. I'm not really against using alloca(), but it should be used with caution, since most people just tend to use it like malloc. This can blow off the stack. Of course allocating an array that's too large is also going to do that. It's just that I wanted to make it clear that it isn't very beginner friendly if you're not very familiar with how C works. Both alloca and VLAs are fine as long as they're used right. Problem is, they usually aren't. – Shahe Ansar Aug 03 '18 at 12:44
  • When we are analysing our network. We are receiving packets (tcp and UDP ) in char buffer and for packet data formating we are aliasing same data using packet structure. – avi Aug 06 '18 at 04:52
  • @avi if that stuff is in production code, then god knows what will happen. You never ever ever just alias with stuff you receive off of a TCP/UDP socket. Aliasing is just one of the problems with it. What about endianness? That's a bug, get it fixed. Please – Shahe Ansar Aug 06 '18 at 15:02
0

Well, you have a lot of (potential) problems with strict aliasing rule, possible padding, size of variables, alignment.

But let's assume that your compiler is set to no-strict-aliasing and that all sizes, padding and alignment match.

Then look at these lines:

p->f_t[0]=(Struct first *) (a+8);
p->f_t[1]=(Struct first *) (a+16);

What they will do is to overwrite a[8] and forward with the value of the pointer (aka address). Consequently a is no longer equal to the initialized value.

Try this to see for your self:

// Print all element in a
p->f_t[0]=(Struct first *) (a+8);
// Print all element in a
p->f_t[1]=(Struct first *) (a+16);
// Print all element in a

So your problem is that you try to use a[8] to a[23] for storing

a) two pointers

and

b) two struct first

Of cause that's impossible

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
0

Other comments and posts have already addressed the strict aliasing problems that accompany casting one type to another, and have detailed other issues as well.

It is appears from your existing code that you are attempting to reference each member of an array of struct usingpointer variables.

This answer is limited to an illustration of how to do what I think you are trying to do in simple terms: (read in-line comments for explantions)

typedef struct  { //using struct instead of Struct
  int a;
  int b; 
}FIRST;           //create typedef tag (improved readability throughout code)
typedef struct  {
  int c;
  int d;
  FIRST f_t[2]; // changed from *[] to [] 
}SECOND;        // (the rest of your post indicates that is what you meant) 

int main()
{
  SECOND *p1; //for illustration, create two pointers to reference 2 elements of arr[2]
  SECOND *p2;

  //Create array of SECOND, populate with unique values in each location
  //to provide verification during printf that assignments were made correcly.                                                                                                                                             
  SECOND arr[2] = {{1,2,{3,4,5,6}},{7,8,{9,10,11,12}}}; 
                  //note values are arranged to follow the definitions of 2 elements of SECOND arr[2]. 

  //Create 2 pointers, 1 for each element of SECOND arr[2]
  p1 = &arr[0]; //assigns address of 1st element of SECOND arr[0], to pointer p1

  p2 = &arr[1];//assigns address of 1st element of SECOND arr[1], to pointer p2

  printf("Elements of p1[0]:\n%d, %d, %d, %d, %d, %d\n", p1[0].c, p1[0].d, p1[0].f_t[0].a,p1[0].f_t[0].b,p1[0].f_t[1].a,p1[0].f_t[1].b );
  printf("Elements of p2[0]:\n%d, %d, %d, %d, %d, %d\n", p2[0].c, p2[0].d, p2[0].f_t[0].a,p2[0].f_t[0].b,p2[0].f_t[1].a,p2[0].f_t[1].b );
  getchar();//stop execution to view result (needed in my environment)

}
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • I have already tried this method and it was working fine. This code I was written just for example. Actually first pointer is a big structure and each time it is getting variable no of element. If we assign maximum memory then it's waste of memory that's why I am using pointer so we can save some memory using dynamic allocation. – avi Aug 06 '18 at 05:00