【问题标题】:C - Can't initate a pointer that is passed as an argumentC - 无法启动作为参数传递的指针
【发布时间】:2011-02-10 06:08:03
【问题描述】:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
    unsigned length;
} List;
void init(List *l) {
    l = (List *) malloc(sizeof(List));
    l->length = 3;
}
int main(void) {
    List *list = NULL;
    init(list);
    if(list != NULL) {
        printf("length final %d \n", list->length);
        return 0;
    }
    return 1;
}

这是给我带来问题的代码的简化版本。我正在尝试从 *list 作为参数传递的方法构造指针 *list

我知道我可以通过将 void init(List *l) 更改为 void init(List **l) 来使其工作,但这是针对课堂教程的。我无法更改方法参数。我花了四个小时来解决这个问题。

我想确保在我与教授对质之前,没有办法让 void init(List *l) 工作。

提前致谢

【问题讨论】:

    标签: c pointers parameters constructor struct


    【解决方案1】:

    您将指针的副本传递给init,它正在分配内存,将其存储在本地副本中,并在init 返回时立即泄漏它。您不能以这种方式将数据传递回调用函数。您需要返回分配的数据,或者传入一个指向要修改的指针的指针,这两者都涉及修改函数签名。

    void init(List **l) {
        *l = (List *) malloc(sizeof(List));
        (*l)->length = 3;
    }
    
    init(&list);
    

    分配是否指定您必须从init 中分配List?如果没有,您始终可以将指针传递给已分配的 List 对象,并执行 length = 3 占位符的任何初始化:

    void init(List *l) {
      l->length = 3;
    }
    
    List list;
    init(&list);
    printf("length final %d \n", list.length);
    

    【讨论】:

    • PO特别提到如果可以避免“void init(List **l)”
    • 赋值确实指定它必须是构造函数。我要给我的教授发电子邮件,要求他更改要求。感谢您的帮助!
    【解决方案2】:

    问题是指针是按值传递的,所以你的更改被丢弃了。您确实需要一个指向指针的指针才能正确执行此操作。就像你会做的那样:

    void init(List** l) {
       *l = (List*) malloc(sizeof(List));
       // ...
    }
    

    当你调用它时,你会使用init(&amp;list) 而不是init(list)。当然,在这种情况下,直接返回结果而不是使用指向指针的指针是有意义的:

    List* init() {
        List* result = (List *) malloc(sizeof(List));
        result->length = 3;
        return result;
    }
    

    然后,根据上述内容,您可以简单地使用list = init();

    请注意,在 C++ 中,您可以使用引用而不是指针,但是混合引用和指针是非常混乱的。在这里,使用返回类型确实是最巧妙的做法。

    如果你绝对必须使用现有的签名,你可以偷偷摸摸地初始化列表,然后在init()函数中你可以让传入的列表的next指针指向你真正想要创建的列表。然后,在调用init() 之后,您可以获取下一个指针并处理您创建的原始列表对象。或者你总是可以通过一些虚拟元素来获得第一个元素。

    【讨论】:

      【解决方案3】:

      这个作业可能是在课堂上教授按值传递和按引用传递的好方法。如果要维护构造函数的签名,则需要修改 main 函数。

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      typedef struct {
          unsigned length;
      } List;
      
      
      void init(List *l) {
          l->length = 3;
      }
      int main(void) {
          List list;// x = NULL;
          memset(&list,0,sizeof(List));
          init(&list);
          printf("length final %d \n", list.length);
          return 1;
      }
      

      现在这里的列表是列表类型,而不是列表的地址。 init() 方法传递了 list 的地址,在 init 中您可以更改结构内容的值。

      ./a.out

      长度最后 3

      【讨论】:

      • 我认为 memset 违反了封装性。 init 负责初始化列表的内容;如果需要 memset,它应该这样做。事实上,它不是必需的。
      【解决方案4】:

      init 需要传递一个指向现有列表的指针。我怀疑这里真正的问题在于您的数据结构。你有一个叫做列表的东西,它包含一个长度,但是在任何地方都看不到列表。 List 可能应该包含一个指向给定长度数组的指针,并且 init 应该 malloc 该数组并设置指针。当您要求教授更正他没有违反的要求时,您可能会发现这一点——如果他们这样做了,他可能会从过去的学生那里听说过,并且现在已经更正了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-12
        • 1970-01-01
        • 1970-01-01
        • 2012-01-24
        • 1970-01-01
        相关资源
        最近更新 更多