【问题标题】:How do I change a pointers value in a function in C如何更改 C 函数中的指针值
【发布时间】:2012-03-13 21:20:51
【问题描述】:

代码是:

     int main(int argc, const char* argv[] )
     {
        struct node * initialpointer=NULL;
        insert("asd", initialpointer, 1);
        if(initialpointer!=NULL)
            printf("isnotnull");
        if (initialpointer==NULL)
            printf("isnull");
     }
     insert(char* x,struct node * initialpointer, int numberofelements){
        struct node B;
        B.word = x;
        B.parent = NULL;
        B.leftchild = NULL;
        B.rightchild = NULL;
        printf("%d", 12);
        if ( initialpointer == NULL){
           initialpointer = &B;
           B.parent = NULL;
        }
     }

所以最后我希望initialpointer 指出 nde B 所在的位置,但在 main 方法中它打印为 null。那么如何永久更改函数插入中的initialpointer

【问题讨论】:

  • B 在函数退出时被删除。你应该为你的initialpointer 节点分配内存(malloc)。
  • 你能去掉你代码中所有不相关的部分吗? numberofelements 值似乎与问题无关,例如,与 parent/leftchild/rightchild 值有关。
  • 这些方法比它们看起来的要复杂。我已经剪掉了不相关的部分。但我不想改变函数和函数调用的结构。

标签: c pointers pass-by-value


【解决方案1】:

不要返回指向局部变量的指针,这会导致指针悬空:

struct node B;
...
initialpointer = &B;

您需要将指向struct node 的指针传递给insert()malloc()insert() 内的新struct node

insert(char* x,struct node ** initialpointer, int numberofelements)
{
    if (NULL == *initialpointer)
    {
        *initialpointer = malloc(sizeof(struct node));
        if (*initialpointer)
        {
            /* Note: you should probably make a copy of 'x',
               using 'strdup()' or similar, otherwise there
               is requiremenet that 'x' exist for the lifetime
               of '*initialpointer': which would be error prone. */
            (*initialpointer)->word       = x;
            (*initialpointer)->parent     = NULL;
            (*initialpointer)->leftchild  = NULL;
            (*initialpointer)->rightchild = NULL;
        }
    }
}

这保留了原始insert() 的逻辑,因为只有当initialpointerNULL 时才应创建node 并将其分配给initialpointer

并调用它:

struct node * initialpointer=NULL;
insert("asd", &initialpointer, 1);

不再需要时记得free()它:

free(initialpointer);

【讨论】:

  • 元素的数量被忽略了。但也许他不需要它。
  • @vulkanino,是的。 OP 可能只是在努力使用它,并希望确保他可以返回一个新节点。
【解决方案2】:
struct node * initialpointer=NULL;
insert("asd", &initialpointer, 1);
...
void insert(char* x,struct node ** initialpointer, int numberofelements){
...
if ( *initialpointer == NULL){
    *initialpointer = &B;

但请记住,这也不适用于您当前的 B 作为自动(本地)变量。

你必须malloc()B

而您的if 语句中缺少else 分支。

【讨论】:

    【解决方案3】:

    根据@Paul Mitchell 的评论编辑。

     int main(int argc, const char* argv[] )
     {
        struct node* initialpointer = insert("asd");
        if ( initialpointer == NULL )
           /* handle the error */
    
        /* remember to free() all the allocated nodes */
     }
    
    
     struct node* insert(char* x)
     {
        struct node* initialpointer = (struct node*)malloc(sizeof(struct node));
        if ( initialpointer == NULL)
            return NULL;  
    
        initialpointer.word = x;
        initialpointer.parent = NULL;
        initialpointer.leftchild = NULL;
        initialpointer.rightchild = NULL;
        return initialpointer;
     }
    

    这将分配一个 single 节点(我已经删除了numberofelements 参数)。

    要为多个节点分配空间,您必须将指针传递给指针。但是,如果我理解您的意图,您希望节点成为链接结构的一部分,也许是一棵树,因此您无需为节点创建容器,因为您可以遍历结构来访问节点。

    【讨论】:

      【解决方案4】:

      您的代码存在一些问题。

      首先是您遇到的问题。您传递给insert 的指针是通过副本传递的;该函数得到一个副本,main 看不到您的更改。对此的解决方案是将指针传递给指针。请参阅 POSIX 函数 strtol 了解其外观的标准库示例。

      第二个问题是您要返回一个指向本地自动(即堆栈分配)变量的指针。由于堆栈在函数退出时被释放,当它返回main 时,该指针指向无效内存。因此,您需要从堆中分配B

      所以,解决问题:

       int main(int argc, const char* argv[] )
       {
          struct node * initialpointer=NULL;
          insert("asd", &initialpointer, 1);
          if(initialpointer!=NULL)
              printf("isnotnull");
          if (initialpointer==NULL)
              printf("isnull");
       }
       insert(char* x,struct node ** initialpointer, int numberofelements){
          struct node *B;
          B = (struct node*)malloc(sizeof(struct node));
          B->word = x;
          B->parent = NULL;
          B->leftchild = NULL;
          B->rightchild = NULL;
          printf("%d", 12);
          if ( *initialpointer == NULL){
             *initialpointer = B;
             B->parent = NULL;
          }
       }
      

      【讨论】:

      • 谢谢你,它似乎工作正常。你能提供更多关于这个想法的信息吗?为什么我要传递initialpointer的地址?
      • 因为,当您调用一个函数时,该函数只会获得您传递给它的内容的副本。传递一个整数?该函数得到一个副本,并且可以随意更改它,而调用代码什么也看不到。传递指针?一样;函数得到一个副本。所以在这种情况下,你传递一个指向指针的指针(即struct node **)。然后传递给函数的副本指向原始struct node *,函数可以更改它。一般准则是:如果函数需要改变它,你需要传递一个指向它的指针。
      【解决方案5】:

      这有两个问题。

      首先,您正在更改一个局部范围的变量,因为initialpointer 是您的函数的参数。这意味着,无论其类型如何,您写入变量本身的内容仅在您的 insert 函数中可见。如果你写信给*initialpointer,那就完全不同了。

      现在,更成问题的是B 是一个位于函数内部堆栈上的局部变量。一旦离开该功能,B 的存储位置将失效。因此,如果您返回指向B 的指针,则在insert 之外访问该对象将调用未定义的行为,并且很可能无法正常工作(您很有可能该特定位置尚未改变了,但这纯粹是运气)。

      你可能想要什么而不是

      initialpointer = &B;
      

      这是:

      *initialpointer = B;
      

      这会将B 对象复制到指针变量引用的存储位置。现在B 超出范围是可以的,因为您将所有内容复制到位于 ma​​in 内的 initialpointer 变量。

      请注意,main 中的 initialpointer 变量与 insert 中的变量完全不同!


      最后一件事,以大写字母开头的变量名称在我目前遇到的任何命名方案中都是无效的。

      【讨论】:

      • 那行不通。你说把 B 放到初始指针指向的地方。然而,它通常指向内存中的关键部分,当我这样做时,我会遇到分段错误
      • 是的,没错。在某些时候,您必须为它分配一些内存。这可以在main 的堆栈上完成(通过声明一个实际的struct node 变量——不是指针)或通过调用malloc 动态地完成。一旦你有一个有效的地方来放置你的数据,你就可以在你的 insert 函数中写入它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 2020-10-20
      • 2011-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多