【问题标题】:C: Accessing a pointer from outside a functionC:从函数外部访问指针
【发布时间】:2010-12-17 09:12:58
【问题描述】:

我有以下代码:

int takeEven(int *nums, int numelements, int *newlist) {
    newlist = malloc(numelements * sizeof *newlist);
    int i, found = 0;
    for(i = 0; i < numelements; ++i, nums++) {
        if (!(*nums % 2)) {
            *(newlist++) = *nums;
            found++;
        }
    }
    newlist -= found;
    printf("First number found %d\n", *newlist); // <= works correctly
    return found;

}

int main()
{
    int nums[] = {1,2,3,4,5};
    int *evenNums;
    int i;
    int n = takeEven(nums, sizeof(nums) / sizeof(*nums), evenNums);
    for (i = 0; i < n; ++i) {
        printf("%d\n", *(evenNums++));
    }
    return 0;
}

以上代码的输出:

-1
2088999640
2088857728

如果我在返回函数 (printf("First number found %d\n", *newlist);) 之前尝试打印 newlist 指针的第一个元素,它会按预期工作,但为什么当我尝试从函数外部访问指针时我得到这些值来自看似未分配的地址?

【问题讨论】:

    标签: c arrays pointers segmentation-fault


    【解决方案1】:

    您正在按值传递 newList 指针,因此您的函数不会修改它。你应该这样做。

    int takeEven(int *nums, int numelements, int **newlist) {
        *newlist = malloc(numelements * sizeof *newlist);
        ...
    }
    
    ...
    
    int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
    

    【讨论】:

    • 比所需的更改更多。
    【解决方案2】:

    你需要传入一个指向指针的指针,即int **newlist。具体来说,newlist 按值传递给您的函数,因此main 中的 newlist 和您的函数内部是两个完全不同的变量。

    您的偶数测试中还有一个错误:

    #include <stdio.h>
    #include <stdlib.h>
    
    int takeEven(int *nums, int numelements, int **newlist) {
        int *list = malloc(numelements * sizeof **newlist);
        *newlist = list;  // this modifies the value of newlist in main
        int i, found = 0;
        for(i = 0; i < numelements; ++i, nums++) {
            if ((*nums % 2) == 0) {
                *(list++) = *nums;
                found++;
            }
        }
        list -= found;
        printf("First number found %d\n", *list); // <= works correctly
        return found;
    }
    
    int main()
    {
        int nums[] = {1,2,3,4,5};
        int *evenNums;
        int i;
        int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
        for (i = 0; i < n; ++i) {
            printf("%d\n", *(evenNums++));
        }
        return 0;
    }
    

    您也可以在 C-FAQ 中take a look at this question 处理您的问题:

    问:我有一个函数,它接受并应该初始化一个指针:

    void f(int *ip)
    {
        static int dummy = 5;
        ip = &dummy;
    }
    

    但是当我这样称呼它时:

    int *ip;
    f(ip);
    

    调用者中的指针保持不变。

    A:你确定这个函数初始化了你认为的那样吗?请记住,C 中的参数是按值传递的。在上面的代码中,被调用的函数只改变了指针的传递副本。为了使其按预期工作,一种解决方法是传递指针的地址(函数最终接受指向指针的指针;在这种情况下,我们基本上是在模拟通过引用传递):

    void f(ipp)
    int **ipp;
    {
        static int dummy = 5;
        *ipp = &dummy;
    }
    
    ...
    
    int *ip;
    f(&ip);
    

    另一种解决方案是让函数返回指针:

    int *f()
    {
        static int dummy = 5;
        return &dummy;
    }
    
    ...
    
    int *ip = f();
    

    另请参阅问题4.94.11

    【讨论】:

    • 哈哈,条件必须是(!(*nums % 2));我现在在问题中修复了它
    【解决方案3】:

    函数末尾的新列表与调用函数时的不同。

    您正在传递一个指针的副本,然后 malloc 更改该指针(函数内部的)以指向分配的内存,但外部的仍然未修改。

    您需要使用指向指针的指针作为参数,以便您可以通过双重间接设置我们的tside one指向的位置。

    int use_pointed_memory(char **pointer){
      *pointer = malloc();
    }
    
    char *myptr;
    use_pointed_memory(&myptr);
    

    如此有效地为函数提供了存储所需地址的位置,并要求函数在那里存储有效的内存指针。

    【讨论】:

      【解决方案4】:

      您在这里按值传递指针:

      int n = takeEven(nums, sizeof(nums) / sizeof(*nums), evenNums);
      

      这意味着指针的副本是在该函数中创建的。然后您覆盖该副本:

      newlist = malloc(numelements * sizeof *newlist);
      

      由于它只是一个副本,调用者不会看到您的分配结果。您在这里似乎想要的是通过引用传递一个指针 - 为此,您需要一个指向指针的指针:

      int takeEven(int *nums, int numelements, int **newlist) {
          *newlist = malloc(numelements * sizeof **newlist); // apply * to newlist
          ...
      }
      
      int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
      

      别忘了free:

      free(evenNums);
      

      【讨论】:

        【解决方案5】:

        在 C 中,一切都是按值传递的。因此,您将 evenNums 的副本传递给该函数。无论您在函数内部对其进行什么修改,都不会反映在外部。您需要将int** 作为第三个参数。

        【讨论】:

        • 不完全正确。数组在 C 中通过引用传递。如果我声明 int foo[10]; int bar( int ar[10] ); 然后使用 foo 调用 bar 它不会按值传递 foo,则数组会退化为指向它的第一个元素的指针。但我相信你知道 :-)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-06-14
        • 2013-10-13
        • 1970-01-01
        • 1970-01-01
        • 2017-09-29
        • 1970-01-01
        • 2019-09-22
        相关资源
        最近更新 更多