我可以使用" int"作为结构中的动态数组?

时间:2018-02-15 09:48:07

标签: c arrays pointers struct dynamic-arrays

一般来说,我试图分配first.a和first.b的值         到结构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输出:

10 11 

4196048 0

我的代码出现问题: 1.我的代码怎么了? 2.我可以在struct里面使用int for dynamic array吗? 3.有哪些替代方案? 4.为什么我没有得到正确答案?

3 个答案:

答案 0 :(得分:3)

看起来您理解指针算术在C中的工作原理是错误的。数据布局假设也存在问题。最后,存在可移植性问题和错误的语法选择,这使得理解变得复杂。

我假设有这个表达式:*( &(sp->aa ) + (i*4) )您试图通过获取第0个项的地址然后向其添加字节偏移来访问数组中的i项。这有三个原因:

  1. 你假设在sp [0]之后.aa在内存中出现sp [1] .aa,但是你忘了它们之间有sp [0] .bb。
  2. 您认为int的大小始终为4个字节,这不是真的。
  3. 您认为向int添加secon*将为您提供一个指定字节数偏移的指针,而实际上它将在指定数量的大小{{1}的记录中进行偏移}}。
  4. 您看到的第二行输出是来自未分配堆内存的随机垃圾,因为当secon您的构造引用超出为i == 1分配的限制的内存时。

    要访问由指针引用的第*secon项数组,请使用i

    []secon[0].aa相同,(secon +0)->aa等于secon[1].aa

答案 1 :(得分:3)

Grigory Rechistov在解开代码方面做得非常好,你应该接受他的回答,但我想强调一点。

在C指针算术中,偏移量始终以指向的类型的大小为单位。除非指针的类型是char*void*,否则如果你发现自己乘以类型的大小,那么你几乎肯定做错了。

如果我有

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

然后a[6]*(p + 1) 不是 *(p + 1 * sizeof(int))相同。同样,a[4]*(p - 1)

此外,当指针指向同一数组中的对象且应用相同规则时,可以减去指针;结果是以指向的类型大小为单位。 q - p2,而不是2 * sizeof(int)。将示例中的类型int替换为任何其他类型,p - q将始终为2。例如:

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

q - p仍为2。顺便说一句,永远不要试图在任何地方硬编码类型的大小。如果您想要malloc这样的结构:

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

唐&#39;吨。

首先,sizeof(int)不能保证为4.其次,即使它是,sizeof(struct Foo)也不能保证为41.编译器通常会向struct类型添加填充以确保成员正确对齐。在这种情况下,几乎可以肯定的是,编译器会在struct Foo的末尾添加3个字节(或7个字节)的填充,以确保在数组中n成员的地址对齐大小为int。始终始终使用sizeof

答案 2 :(得分:2)

这是一个完整的混乱。如果您想访问secon的数组,请使用[]

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

您有两个指向first中值的指针副本,它们指向相同的

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

但是,允许编译器假设第一个不会更改,并且允许重新排序这些表达式,因此您无法保证在secon中具有不同的值

无论哪种方式,当您以秒为单位回读值时,仍然可以使用[]

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