2009-11-17 25 views
3

我有以下代码:C:访问从一个指针的函数外

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);)之前,它按预期工作,但为什么当我尝试从函数的外部访问指针时,我从表面上看不到这些值地址?

回答

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

您还可以take a look at this question从C-FAQ与您的问题还涉及:

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

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

+0

呵呵,条件需要是'(!(* nums%2))';我现在解决了这个问题 – 2009-11-17 10:38:14

2

函数结尾处的新列表与您在调用该函数时所具有的不同。

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

您需要使用一个指针指针作为参数,以便您可以通过双向间接来设置ourtside one指向的位置。

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

char *myptr; 
use_pointed_memory(&myptr); 

所以有效地你给的功能,你存储你想要什么,并要求该函数存储有一个有效的内存指针的地址信息的地方。

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

比需要更多的变化。 – caf 2009-11-17 10:24:37

0

在C中,所有东西都按值传递。因此,您正在将evenNums的副本传递给该函数。无论你修改它在函数内部都不会反映到外部。您需要将int**作为第三个参数。

+0

不完全如此。如果我声明'int foo [10]; int bar(int ar [10]);'然后用foo调用bar,它不会按值传递foo,数组退化为指向它的第一个元素的指针。但是我相信你知道这一点:-) – 2012-03-15 15:05:31