3

In general, i'm trying to allocate values of first.a and first.b to a array's in struct secon.

typedef struct {
    int a;
    int b;
} firs; 

//secon is my struct which contains dynamic array
//can i use int here ? 

typedef struct {
    int *aa;
    int *bb;
} secon;

//pointer to secon intialised to NULL;
secon* sp=NULL;

int main() 
{
    firs first;

    //plz assume 2 is coming from user ;
    sp=malloc(sizeof(secon)*2);

    //setting values 
    first.a=10;
    first.b=11;


    /* what i'm trying to do is assign values of first.a and first.b to my 
        dynamically created array*/

    /* plz assume first.a and first.b are changing else where .. that means ,not 
        all arrays will have same values */


    /* in general , i'm trying to allocate values of first.a and first.b
        to a array's in struct second. */

    for(int i=0; i<2; i++) {
        *( &(sp->aa ) + (i*4) ) = &first.a;
        *( &(sp->bb ) + (i*4) ) = &first.b;
    }

    for(int i=0; i<2; i++) {
        printf("%d %d \n", *((sp->aa) + (i*4) ),*( (sp->bb) +(i*4) ) );
    }

    return 0;
}

MY output :

10 11 

4196048 0

Problems with my code: 1. whats wrong with my code? 2. can i use int inside struct for dynamic array? 3. what are the alternatives? 4. why am i not getting correct answer?

Eziz Durdyyev
  • 1,110
  • 2
  • 16
  • 34
bbcbbc1
  • 95
  • 7
  • Why `(i*4)`? `(sp->aa)` is `int*`. Also, I am pretty sure `&(sp->aa) + (i*4)` is not what you wanted to do. `aa` and `bb` don't point to anything after allocating the struct. Are you sure you want them to *point* to `first.a` and `first.b`? Because `&first.a` is not the value of `first.a`, it's its address. Do you understand how [pointer arithmetic](https://stackoverflow.com/q/394767/69809) works? – vgru Feb 15 '18 at 09:56
  • There's a lot of weird stuff in this question but I am really interested in the answer – Shinra tensei Feb 15 '18 at 10:00
  • Since the code is going in a completely wrong direction, it might be a better idea to describe what you wanted to accomplish. Even if you get it running, I don't think it will make sense. – vgru Feb 15 '18 at 10:02
  • All I'm trying to do is , create dynamic array which are in struct secon. And since this is dynamic array ,for now I assume array of size 2 which I gave statically while using malloc . Now , I want aa[0] to have value of first.a and bb[0] to have first.b . Similarly for aa[1] and bb[1] but .. please assume struct first is being used in some other file.c with 'extern' so any changes to first.a and first.b will be reflected here (complier linkage). So it's not always guaranteed that aa[1],bb[1] will have same values as aa[0] and bb[0] . This is all I want to do.Thanks . – bbcbbc1 Feb 15 '18 at 11:01
  • 1
    @bbcbb1 it does not make your code correct. Even if the address calculation was correct, it does not make your code portable. You cannot assume `int` is always four bytes wide, that's bad practice. Either use `siezof(int)`everywhere or add `assert(sizeof(int) == 4)` somewhere; but in the first place, make sure you understand where `pointer + integer` points to. Your code can be rewritten so that it does not need to know size of `int` type **at all** and still work correctly everywhere. – Grigory Rechistov Feb 15 '18 at 11:06

3 Answers3

3

It looks like your understanding how pointer arithmetic works in C is wrong. There is also a problem with data layout assumptions. Finally, there are portability issues and a bad choice of syntax that complicates understanding.

I assume that wit this expression: *( &(sp->aa ) + (i*4) ) you are trying to access the i-th item in the array by taking address of the 0-th item and then adding a byte offset to it. This is wrong of three reasons:

  1. You assume that after sp[0].aa comes sp[1].aa in memory, but you forget that there is sp[0].bb in between.
  2. You assume that size of int is always 4 bytes, which is not true.
  3. You assume that adding an int to secon* will give you a pointer that is offset by specified number of bytes, while in fact it will be offset in specified number of records of size secon.

The second line of output that you see is random junk from unallocated heap memory because when i == 1 your constructions reference memory that is outside of limits allocated for *secon.

To access an i-th item of array referenced by a pointer, use []:

secon[0].aa is the same as (secon +0)->aa, and secon[1].aa is equal to (secon+1)->aa.

Grigory Rechistov
  • 2,104
  • 16
  • 25
3

Grigory Rechistov has done a really good job of untangling the code and you should probably accept his answer, but I want to emphasize one particular point.

In C pointer arithmetic, the offsets are always in units of the size of the type pointed to. Unless the type of the pointer is char* or void* if you find yourself multiplying by the size of the type, you are almost certainly doing it wrong.

If I have

int a[10];
int *p = &(a[5]);
int *q = &(a[7]);

Then a[6] is the same as *(p + 1) not *(p + 1 * sizeof(int)). Likewise a[4] is *(p - 1)

Furthermore, you can subtract pointers when they both point to objects in the same array and the same rule applies; the result is in the units of the size of the type pointed to. q - p is 2, not 2 * sizeof(int). Replace the type int in the example with any other type and the p - q will always be 2. For example:

struct Foo { int n ; char x[37] ; };
struct Foo a[10];
struct Foo *p = &(a[5]);
struct Foo *q = &(a[7]);

q - p is still 2. Incidentally, never be tempted to hard code a type's size anywhere. If you are tempted to malloc a struct like this:

struct Foo *r = malloc(41); // int size is 4 + 37 chars

Don't.

Firstly, sizeof(int) is not guaranteed to be 4. Secondly, even if it is, sizeof(struct Foo) is not guaranteed to be 41. Compilers often add padding to struct types to ensure that the members are properly aligned. In this case it is almost a certainty that the compiler will add 3 bytes (or 7 bytes) of padding to the end of struct Foo to ensure that, in arrays, the address of the n member is aligned to the size of an int. always always always use sizeof.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
2

This is a complete mess. If you want to access an array of secons, use []

for(int i=0;i<2;i++)
{
  sp[i].aa = &first.a; // Same pointer both times
  sp[i].bb = &first.b;
}

You have two copies of pointers to the values in first, they point to the same value

for(int i=0;i<2;i++)
{
  sp[i].aa = malloc(sizeof(int)); // new pointer each time
  *sp[i].aa = first.a; // assigned with the current value 
  sp[i].bb = malloc(sizeof(int));
  *sp[i].bb = first.b;
}

However the compiler is allowed to assume that first does not change, and it is allowed to re-order these expressions, so you are not assured to have different values in your secons

Either way, when you read back the values in second, you can still use []

for(int i=0;i<2;i++)
{
  printf("%d %d \n",*sp[i].aa ),*sp[i].bb );
}
Caleth
  • 52,200
  • 2
  • 44
  • 75
  • I'd be a little more explicit: *"they point to the same value"*: i. e. sp[0] and sp[1] will *always* "see" the same values, the ones of first, no matter if and when first changes. *"sp[i]->aa = malloc(sizeof(int));"*: Assuming we do not need a real array, I'd rather recommend replacing the pointer by a simple value. At least, I'll show this as alternative, too... Please hint to not forgetting to free malloced values. – Aconcagua Feb 15 '18 at 10:31
  • hi , i tried what you said but i get this error. prog.c: In function ‘main’: prog.c:26:7: error: invalid type argument of ‘->’ (have ‘secon {aka struct }’) sp[i]->aa = &first.a; ^~ prog.c:27:7: error: invalid type argument of ‘->’ (have ‘secon {aka struct }’) sp[i]->bb = &first.b; ^ – bbcbbc1 Feb 15 '18 at 14:08
  • I think I messed up between `.` and `->` because of all the pointers. See edit – Caleth Feb 15 '18 at 14:11
  • thanks a lot,it worked.but can you please explain why it worked whe used . and doesnt work when used -> ? – bbcbbc1 Feb 15 '18 at 14:17
  • because `->` is "member access through pointer" and `.` is "member access through value". `sp[i]` is a `secon`, `sp + i` is a `secon *`. Note the `*` – Caleth Feb 15 '18 at 14:20
  • i got it , sp[1].aa is equivalent to (sp+1)->aa .Thanks – bbcbbc1 Feb 15 '18 at 14:31