2009-11-17 55 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