【问题标题】:Returning a structure array using pointers使用指针返回结构数组
【发布时间】:2010-12-21 07:56:09
【问题描述】:
    typedef struct unit_class_struct {
        char *name;
    } person;



person * setName() {
       person * array;
       array = malloc (2 * sizeof(person));

       array->name = strdup("Robert");
       array++;
       array->name = strdup("Jose");
       return array;
}


    int main()
    {
        person *array;

        array = setName();

        printf("First name is %s\n", array[0].name);
        printf("Second name is %s\n", array[1].name);

        return 0;
    }

在此示例中,array[0].name 返回 Jose,而不是我预期的 Robert,并且 array[1].name 为空。

但是如果我使用

person * setName() {
       person * array;
       person * array_switch;
       array = malloc (2 * sizeof(person));
       array_switch = array;
       array_switch->name = strdup("Robert");
       array_switch++;
       array_switch->name = strdup("Jose");
       return array;
}

它按预期工作。 array.name[0] 返回 Robert,array.name[1] 返回 Jose。

为什么这个例子需要第二个指针才能工作?我可以在不使用第二个指针的情况下仍然使用指针算术吗?

我已经知道这也是另一种方法:

person * setName() {
       person * array;
       array = malloc (2 * sizeof(person));
       array[0].name = strdup("Robert");
       array[1].name = strdup("Jose");
       return array;
}

【问题讨论】:

  • 再次按array[1].name 之类的索引访问元素有什么问题?
  • 没什么,我只是已经知道怎么做,我正在努力了解如何用指针算术来做

标签: c arrays data-structures pointers return


【解决方案1】:

在您的代码中:

person * setName() {
   person * array;
   array = malloc (2 * sizeof(person));

   array->name = strdup("Robert");
   array++;
   array->name = strdup("Jose");
   return array;
}

您为数组中的两个元素分配空间并设置array 指向第一个:

+-------+      +----------+
| array | ---> | array[0] |
+-------+      +----------+
               | array[1] |
               +----------+

然后用array++ 递增元素指针,that 是最后返回给调用函数的内容。该指针指向 second 数组元素,这就是为什么它看起来是错误的(以及为什么当您稍后尝试释放该内存时几乎肯定会崩溃):

+-------+      +----------+
| array | -+   | array[0] |
+-------+  |   +----------+
           +-> | array[1] |
               +----------+

你需要的是:

person * setName() {
   person * array;
   array = malloc (2 * sizeof(person));

   array[0].name = strdup("Robert");
   array[1].name = strdup("Jose");
   return array;
}

正如您已经指出的那样。这个解决方案不会改变array 指针。但是,如果您真的想使用指针,您可以在返回之前使用 array-- 反转 array++ 的操作,以便将 array 设置回正确的值:

person * setName() {
   person * array;
   array = malloc (2 * sizeof(person));

   array->name = strdup("Robert");
   array++;
   array->name = strdup("Jose");
   array--;
   return array;
}

或者,另一种不改变原始指针、不使用数组索引并且不使用第二个指针的方法是使用指针算法。编译器知道指针指向的类型,因此可以正确调整指针以找到下一个元素(您已经知道它知道如何执行此操作,因为 array++array = array + 1 的简写,并且该语句将值调整为正确的量也):

person * setName() {
   person * array;
   array = malloc (2 * sizeof(person));

   (array+0)->name = strdup("Robert");
   (array+1)->name = strdup("Jose");
   return array;
}

【讨论】:

    【解决方案2】:

    您也只需进行简单的算术指针运算,例如加法和减法:

        array->name = "Robert";
        (array+1)->name = "Jose";
        return array;
    

    【讨论】:

      【解决方案3】:

      指针实际上只是一个数字(内存中的地址)。您正在修改此指针以指向其他位置,然后将其返回。

      【讨论】:

      • 这就是答案,但对于任何提出这个问题的人来说,这可能是完全无法理解的。
      【解决方案4】:

      这将使用指针算法,并保留原始数组指针:

      person * setName() {
             person * array;
      
             array = malloc (2 * sizeof(person));
             (array+0)->name = strdup("Robert");
             (array+1)->name = strdup("Jose");
      
             return array;
      }
      

      【讨论】:

        【解决方案5】:

        是的


        由于您增加了array,您不再拥有指向[0] 元素的指针,而是指向[1] 元素的指针。这样做:

           array->name = strdup("Robert");
           array++;
           array->name = strdup("Jose");
           return array - 1;
        

        请记住,在 C 中,p[x] 只不过是 *(p + x),或者,如果您愿意,请考虑一下:(p + x)[0]。最后一种情况是您的程序实际上正在执行的操作,x == 1。所以(p + 1)[1]p[2] 相同,并且没有任何内容,因此您的结果为 null。

        (你也可以写成...

           array++->name = strdup("Robert");
           array--->name = strdup("Jose");
           return array;
        

        ...但如果你这样做了,就会有一群人过来投票给你。阅读真的有那么难吗?我们的目标真的是只编写没有灵感的笨拙代码吗?)

        【讨论】:

        • -1 用于使用像 array++->namearray--->name 这样的晦涩构造
        • “真的那么难读吗?” array--->name 怎么可能被理解为易于阅读?
        • 我想你们会很高兴我修复了主要示例以按照您的方式进行操作。
        猜你喜欢
        • 1970-01-01
        • 2013-08-02
        • 2014-12-30
        • 1970-01-01
        • 2014-08-26
        • 1970-01-01
        • 2015-08-25
        • 1970-01-01
        • 2021-11-30
        相关资源
        最近更新 更多