【问题标题】:Pointer to a struct accessed using index like an array指向使用索引访问的结构的指针,如数组
【发布时间】:2016-09-09 06:12:14
【问题描述】:
#include<stdio.h>

struct test{ 
    int a;
    int b;
}m;

int main()
{
    m.a=5;m.b=7; 
    struct test *p;
    p = &m;
    printf("p[0] = %d\n",*(p+0));
    printf("p[1] = %d\n",*(p+1));

    return 0;

}

我得到以下输出:

p[0] = 5 p[1] = 0

有人可以解释一下这种行为吗?有没有办法使用索引打印所有结构成员?

抱歉打错了。

(更新)

因为我可以使用索引 0 打印第一个元素,虽然指针的类型是“结构测试类型”并且第一个成员是整数,但我可以获得正确的值。因此,引发了有关此行为原因的问题。如果可以使用索引访问所有成员,就像访问第一个成员一样。

【问题讨论】:

  • 你能告诉我们你为什么这样做p = &amp;a;吗?
  • @hacks 先生,我认为 OP 的意思是 p = &amp;m.a;
  • @SouravGhosh; pstruct test * 类型,而 &amp;m.aint * 类型。
  • @hacks 对,但是地址可以用于引用整个结构或第一个变量,就类型而言,不是吗?
  • @SouravGhosh;你不认为这是不兼容的指针分配吗?另请注意,您在上一条评论中所说的仅适用于数组数据类型。

标签: c pointers struct printf pointer-arithmetic


【解决方案1】:

首先,您的代码中有错字。 请将p = &amp;a;更正为p = &amp;m;,以便消除编译器报错。

其次,我猜您希望输出为 p[0] = 5 和 p[1] = 7。 为此,请从

修改您的代码
printf("p[0] = %d\n",*(p+0));
printf("p[1] = %d\n",*(p+1));

printf("p[0] = %d\n",p->a);
printf("p[1] = %d\n",p->b);

可以工作。

【讨论】:

    【解决方案2】:

    在您的代码中,

    printf("p[0] = %d\n",*(p+0));
    printf("p[0] = %d\n",*(p+1));
    

    调用undefined behavior

    1. 您为 %d 格式说明符传递了错误类型的参数。
    2. *(p+1),您正在访问超出限制的内存

    因此,无法以任何方式解释或证明输出。


    现在,话虽如此,让我们稍微分析一下代码。

    首先,

      p = &a;
    

    是错误的,因为没有名为 a 的变量。结构变量m有一个成员变量a,可以通过m.a访问。所以,你可以以某种方式

     p = (struct test*) &m.a;
    

    现在,使用结构的第一个元素的地址作为结构地址是有效的,因为结构的开头没有填充。但这并不意味着,你可以直接对结构体指针p进行指针运算,得到每个成员变量,主要是因为

    • 两个元素之间可以有填充
    • 指针pstruct test 类型(虽然你可以通过强制转换来解决

    【讨论】:

      【解决方案3】:

      我用 gcc 编译了你的代码,我得到了。

      In function ‘main’:
      error: ‘a’ undeclared (first use in this function)
         p = &a;
              ^
      note: each undeclared identifier is reported only once for each function it appears in
       warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
             printf("p[0] = %d\n",*(p+0));
                    ^
      warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
          printf("p[0] = %d\n",*(p+1));
      

      假设你的意思是p=&amp;m,这是我的解释

      printf("p[0] = %d\n",*(p+0));
      printf("p[0] = %d\n",*(p+1));
      

      首先分析一下你在printf函数中做的延迟指针是否正确。

      *(p+0) 将使您能够访问结构测试变量m。因为,您已将struct test 类型变量的地址分配给指针p,延迟指针*p*(p+0) 将使您可以访问变量m。但是分配给指针的地址是单个变量,而不是struct test 类型的数组,推迟(p+1) 会给你未定义的行为。例如,如果 (not in printf statement),*(p+1) 会起作用

      struct test m[20];
      struct test *p;
      
      (*(p+0)).a=2;
      (*(p+1)).a=5;
      

      有没有办法使用索引打印所有结构成员?

      你可以。但是c中没有运算符的重载。所以,你可以通过 -

      printf("a=%d, b=%d", p->a, p->b);
      

      如果指针p指向struct test类型的数组,那么你可以在printf中使用索引作为

      printf("a=%d, b=%d of %dth element", p[i].a, p[i].b, i);
      

      我对您未来代码实验的建议是首先分析您的代码给出的警告和错误。警告可以帮助纠正代码中的大多数错误。我总是使用 gcc/g++ 编译器编译我的 c/c++ 代码,并使用 -Wall、-Wshadow、-Wextra 等标志。不明白的可以google一下警告。

      【讨论】:

        【解决方案4】:

        您将a 的地址直接分配给pam 的成员,因此无法直接访问。在您的代码中,您应该使用整数指针进行算术运算。

        您需要修改部分代码

        struct test *p;
        p = &a;
        

         int *p;
         p = &m.a;
        

        现在代码应该可以按您的意愿工作了。

        【讨论】:

          【解决方案5】:

          获取合适的编译器。在 GCC 5 上使用默认设置编译,编译结果如下:

          foo.c: In function ‘main’:
          foo.c:12:10: error: ‘a’ undeclared (first use in this function)
               p = &a;
                    ^
          foo.c:12:10: note: each undeclared identifier is reported only once for each function it appears in
          foo.c:13:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
               printf("p[0] = %d\n",*(p+0));
                      ^
          foo.c:14:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
               printf("p[0] = %d\n",*(p+1));
                      ^
          

          也许你的意思是p = &amp;m;


          之后,您的代码会调用未定义的行为。 %d 期望相应的参数是一个 int,但您提供了一个 struct test。此外,在后面的打印中,指针指向m 之后的未初始化内存,并打印垃圾。即使您在第一种情况下打印了5,也不能依赖这一事实。 C 标准没有解释 whywhy not 会发生这种情况,C 标准说“此时编译器可以生成打印 42342 的代码,crash程序,或者做任何其他事情,按照这个标准就可以了。”


          在 C 编译器中,警告通常意味着“违反标准”,在这种情况下,可能会出现未定义的行为。 C 编程语言的新手应该始终所有编译器警告,尤其是默认设置的警告都视为致命错误

          【讨论】:

            猜你喜欢
            • 2013-01-16
            • 1970-01-01
            • 2011-08-10
            • 1970-01-01
            • 2017-01-04
            • 2022-07-22
            • 2017-07-18
            • 2023-02-16
            相关资源
            最近更新 更多