【问题标题】:C pointer math with structures带有结构的 C 指针数学
【发布时间】:2011-04-09 14:57:56
【问题描述】:

为了更好地学习指针数学,我编写了这段代码。目的是增加指针抛出的结构并打印它的成员。我知道如何以更简单的方式打印它的成员,但我真的很想知道我的指针数学是如何搞砸的。谢谢。

typedef struct{ 
  int num;
  int num2;
  char *string;
} astruct ;

int main (int argc, const char * argv[])
{
  astruct mystruct = { 1234, 4567,"aaaaaaa"};

  astruct *address;
  address = &mystruct;

  // this does print 1234
  printf("address 0x%x has value of:%i\n",address, *address); 
  address = address + sizeof(int);

  //this does NOT print 4567
  printf("address 0x%x has value of:%i\n",address, *address); 
  address = address + sizeof(int);

  //this crashes the program, I wanted to print aaaaaaaa
  printf("address 0x%x has value of:%s\n",address, **address); 

  return 0;
}

【问题讨论】:

    标签: c pointers structure


    【解决方案1】:

    指针算法将指针增加指向的字节数。例如,

    int a[2];
    int *p = a;
    
    assert( &a[0] == p )
    assert( &a[1] == p + 1 )
    

    因此,你的行

    address = address + sizeof(int);
    

    实际上将address 更改为address + sizeof(int) * sizeof(astruct)(使用普通算法,而不是指针算法)。

    没有保证可以做你正在尝试的事情,因为允许编译器在结构中引入填充。考虑结构

    struct A {
        char a;
        int b;
    };
    

    编译器很可能会为这个结构提供以下布局:

    +------------+-------------------+-------------+
    | a (1 byte) | (3 bytes padding) | b (4 bytes) |
    +------------+-------------------+-------------+
    

    因此,您无法通过获取结构实例的地址并添加 1 来到达 b

    在您的特定情况下,编译器可能不会引入填充,因此您可以使用这些行来更新address

    address = (char *) address + sizeof(int); // OR...
    address = (int *) address + 1;
    

    不过,这完全取决于编译器以您认为的方式布局结构,任何小的更改都可能会破坏它,因此您真的不应该依赖这种类型的行为。

    【讨论】:

    • 不保证这两个整数至少是连续的吗?
    • 该标准对填充做了 mo 保证。 (这就是所有可能的原因)
    • 新手 C 问题在这里:地址 (astruct*) 到 (int*) 的转换不违反别名规则吗?
    【解决方案2】:

    当你添加一个指针时,你实际上添加了n * sizeof(*ptr)字节。

    因此在 32 位机器上,您的结构将占用 12 个字节,添加 sizeof(int) 字节实际上会为指针添加 48 个字节。

    要指向num2,您首先必须将地址转换为指向整数的指针:

    int *iaddress = (int *)address;
    

    然后添加 one 以达到您的 4567 值。

    【讨论】:

      【解决方案3】:

      这些结构旨在避免此类计算。您可以使用mystruct.nummystruct.num2mystruct.string,而不是遍历内存。这仍然是一个段错误,因为您没有为“aaaaaaa”分配内存。

      【讨论】:

        猜你喜欢
        • 2023-03-07
        • 1970-01-01
        • 2013-05-30
        • 2012-09-28
        • 2016-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多