C:从函数外部访问指针

时间:2009-11-17 09:29:39

标签: c arrays pointers segmentation-fault

我有以下代码:

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

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

5 个答案:

答案 0 :(得分:6)

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

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

...

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

答案 1 :(得分:3)

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

您的测试中还存在偶数错误:

#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);

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

答:你确定该功能初始化了你的想法吗?请记住,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

答案 2 :(得分:2)

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

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

您需要使用指针指针作为参数,以便您可以设置ourtside指向双重间接的位置。

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

char *myptr;
use_pointed_memory(&myptr);

因此,您可以将函数放在存储所需地址的位置,并要求函数存储有效的内存指针。

答案 3 :(得分:1)

你在这里按值传递一个指针:

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);

答案 4 :(得分:0)

在C中,所有内容都按值传递。所以你要将evenNums的副本传递给该函数。无论你在函数内修改它,都不会在外面反映出来。您需要int**作为第三个参数。