【问题标题】:Passing arrays in c在 c 中传递数组
【发布时间】:2013-08-22 18:07:33
【问题描述】:

我有一个关于将 c 中的数组传递给函数的问题。

当我运行这个程序时,它给了我一个分段错误

int main()
{

  char **ptr= NULL;
  test(ptr);
  printf("%s", ptr[0]);
  return 0;
}

void test(char **ptr)
{
  ptr = (char **) malloc(sizeof(char *));
  ptr[0] = (char *) malloc(sizeof(char)*5);
  strcpy(ptr[0], "abc");
  return;

}

但这工作得很好

int main()
{

  char **ptr= NULL;
  test(&ptr);
  printf("%s", ptr[0]);
  return 0;
}

void test(char ***ptr)
{
  *ptr = (char **) malloc(sizeof(char *));
  *ptr[0] = (char *) malloc(sizeof(char)*5);
  strcpy(*ptr[0], "abc");
  return;

}

有人能解释一下原因吗?

【问题讨论】:

  • 因为公开编程至少需要三颗星?
  • 第一个 sn-p 通过值传递指针到指针,因此设置值 sans-deference 相当于修改本地 var 仅此而已。建议您查看 C 中的按地址传递参数,这是您的第二个 sn-p 正在做的事情。 (注意:第二个 sn-p 中的第一个 sizeof 在技术上是错误的。它应该是 sizeof(char**),或者更容易记住,sizeof(*ptr)。(和 @KerrekSB,+1,太棒了)。
  • 你基本上是在test()函数中修改ptr。制定一个经验法则 - 如果您正在修改函数中的变量,则在其中传递变量的地址。因此address of char ** 将在此处传递,即char ***

标签: c arrays pointers segmentation-fault


【解决方案1】:

您正在传递参数ptr 按值test 中的形式参数ptrmain 中的实际参数ptr 是一个不同的对象,因此更改test::ptr 的值不会反映在main::ptr 中。

因此,您需要将一个指向ptr指针 传递到test,并且test 需要取消引用该指针以写入正确的对象。

对于任何类型T,如果要修改函数参数的值,需要进行如下操作:

void foo( T *param )
{
  *param = ...;
 }

 void bar( )
 {
   T obj;
   foo( &obj );
 }

在这个特定的例子中,Tchar **

【讨论】:

    【解决方案2】:

    在 C 中,当您将数组传递给函数时,数组“衰减”为指针。该函数接收指向数组第一个元素的指针。它不接收数组本身。在被调用函数中对指针分配所做的任何更改都不会反映在调用函数中。

    在您的第一个示例中,test() 接收字符串数组,并在函数内部更改该指针指向的内容。因此ptr 的本地副本,即NULL,在函数内部获得分配的内存,ptr[0] 也是如此。但是,这些更改是 test() 的本地更改。它们不会反映在调用函数中。当test()执行完毕并返回时,调用函数中ptr的值仍然是NULL。而且您有内存泄漏,因为无法访问在test() 中分配的内存。

    为了使更改反映在调用函数中,您必须传递一个指向字符串数组的指针:因此调用中的&ptrtest() 定义中的三级指针。另一种更简单的方法是:

    int main()
    {
    
        char **ptr= NULL;
        ptr = test();
        printf("%s", ptr[0]);
        return 0;
    }
    
    char** test(void)
    {
          char **ptr = (char **) malloc(sizeof(char *));
          ptr[0] = (char *) malloc(sizeof(char) * 5);
          strcpy(ptr[0], "abc");
          return ptr;
    
    }
    

    一个澄清:我说“对被调用函数中的指针分配所做的任何更改都不会反映在调用函数中。”这与说“对数组元素的任何更改都不会反映在调用函数中”不同。考虑一下:

    int main (void) {
    
        int array [] = { 0, 1, 2, 3, 4 };
    
        test1 (array);
        printf ("%d\n", *array);
    
        test2 (array);
        printf ("%d\n", *array);
    
        return 0;
    }
    
    void test1 (int* array) {
    
        int new_array[] = { 3, 4, 5, 6, 7 };
        array = new_array;
        return;
    }
    
    void test2 (int* array) {
    
        array [0] = 5;    // or *array = 5
        array [1] = 6;
        array [2] = 7;
        array [3] = 8;
        array [4] = 9;
    
        return;
    }
    

    输出:

    0
    5
    

    test1() 中,更改的是数组指针本身指向的位置,这不会反映在调用者中。所以在调用函数中,*test 仍然是 0。在test2() 中,变化的是数组元素,这些变化反映在调用者身上。因此输出的差异:*test 现在是 5。这一切都使用静态而不是动态内存分配,但原理是一样的。

    【讨论】:

      【解决方案3】:

      这是因为你希望你的函数不返回值,而是修改你已经在另一个作用域中创建的变量。

      您希望从您的函数中传递ptr 并最终得到以下结构:

      ptr -> b -> []
      

      其中b 是指向数组[] 的指针。

      在第一个示例中,您不是在修改函数内部的外部 ptr,而是它的副本。在这种情况下,要获得所需的结构,您需要您的函数返回一个 char** 以便您可以返回分配的指针。而且您不需要传递原始 ptr。

      另一方面,在第二个示例中,您将指针传递给外部 ptr,因此该函数将修改外部 ptr 使用的相同内存空间。

      我希望这能有所帮助。

      【讨论】:

        【解决方案4】:

        考虑下面的代码来理解

        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        void test(char **ptr);
        
        int main()
        {
          char *ptr= NULL;
          test(&ptr);
          printf("%s\n", ptr);
          return 0;
        }
        
        void test(char **ptr)
        {
          *ptr = malloc(sizeof(char *));
          strcpy(*ptr, "abc");
          return;
        }
        

        在函数定义中所做的任何事情都必须反映在主函数中。因此,如果您想更改 ptr 变量,您必须传递 ptr 变量的地址。

        ptr 是单指针(char ptr) 变量,我们需要传递指针(&amp;ptr) 变量的地址。

        在函数定义中,我们接收的是指针变量的地址,所以参数必须是双指针的类型。

        这个概念类似于引用调用。

        您的代码中也会发生类似的事情。

        你需要传递双指针的地址来改变指针变量。

        函数定义中双指针的地址必须被三指针占用。

        【讨论】:

          【解决方案5】:

          扩展来自@rcrmn 的答案。

          让数据“向上”传递到调用结构是一个很好的程序设计。在这种情况下,main() 需要释放它从测试中收到的存储空间。

          请注意,此代码避免原始问题中的所有双指针,并且仍然满足要求。这就是优秀编程的精髓,编写清晰、简单的代码来完成工作。

          #include <stdio.h>
          char *test();
          int main()
          {
            char *ptr = test();
            printf("%s", ptr);
            free(ptr);
            return 0;
          }
          
          char *test()
          {
            char *ptr = (char *) malloc(sizeof(char) * 5);
            strncpy(ptr, "abc", 3);
            return ptr;
          }
          

          【讨论】:

            猜你喜欢
            • 2010-12-24
            • 1970-01-01
            • 2014-07-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-30
            • 2020-05-23
            • 2011-04-20
            • 2013-04-02
            相关资源
            最近更新 更多