2014-02-17 75 views
1

我願做這樣的事情:ç傳遞字符數組的功能,計算與另一個字符數組複製

#include <stdio.h> 

char * myfunction(char * in); 
void myfunction2(char * in, const char ** content); 

int main(){ 
    char * name="aName"; 
    char * result = myfunction(name); 
    return 0; 
} 

char * myfunction(char * in) { 
    const char *test = NULL; 
    myfunction2(in, &test); 
    return test; // I would like to return the value of test 
} 

void myfunction2(char * in, const char ** content) { 
    char input[1024]; 
    //do some stuff to fill input 
    *content = input; 
} 

但我不能夠做到這一點,一些奇怪的字符,有時反而印...

謝謝你的回覆,我現在明白了,但我被困在我的問題的另一面。我沒有精確寫出我的用例,所以我編輯它是完整的。

+0

什麼是印刷?另外,你在使用什麼編譯器?它在Linux上使用gcc可以正常工作。 – McLovin

+2

放在主要之前的原型。 – BLUEPIXY

回答

0

這對我來說很好。我可以建議給它一個原型或在main()之前移動你的myfunc()定義。聲明時還要爲結果賦值。如果函數沒有達到你期望的水平,那將會給你一個更好的想法。

3

最明顯的事情錯在這段代碼是:

  1. 您的指針myfunction作爲int myfunction();
  2. 不正確的常量性的隱性聲明。
  3. 提供main()

myfunction隱宣佈爲int myfunction();

這是很容易解決的,你的編譯器應該在你這個時候大聲算是找無返回值發生。作爲C的遺留功能,當遇到函數調用時,無論是通過原型還是定義,都不知道正式聲明,則假定函數返回int並接受可變數目的參數。因此,在main()你的電話被認爲是看起來像這樣的功能:

int myfunction(); 

後來遇到真正myfunction時,至少你的編譯器應該在你的警告有關的聲明怎麼沒有按尖叫不符合預期類型(因爲此時它認爲它是int myfunction())。然而,即使如此,這次電話會議仍應該通過,但依靠這一點是可怕的做法。在使用之前正確地爲您的功能製作原型。


所有指針的數據類型都不正確。

函數中的字符串文字未綁定到本地數組空間。它是一個只讀數據緩衝區,位於程序數據塊的某個只讀段中。正確的聲明是這樣的:

const char *test = "mytest"; 

,但有需要修改這個代碼,你會看到一個時刻其餘的連鎖反應。


提供main()

沒有返回值在你的main()結論明確。顯然C99允許你跳過這個,實現是假設爲你返回0。不要給他們那種歡樂;抓住它自己。


解決以上所有的...

#include <stdio.h> 

void myfunction(const char** in); 

int main() 
{ 
    const char *result = NULL; 
    myfunction(&result); 
    printf("in main() %p : %s\n", result, result); 
    return 0; 
} 

void myfunction(const char** in) 
{ 
    const char* test = "mytest"; 
    printf("in myfunction() %p : %s\n", test, test); 
    *in = test; 
} 

輸出(通過執行不同)

in main() 0x8048580 : mytest 
in myfunction() 0x8048580 : mytest 

See it live

+0

請記住,C99定義瞭如果'main()'在沒有顯式'return'的情況下落入'底部',它就等價於'return 0;' - 一個從C++ 98複製的錯誤(IMNSHO)。 –

+0

@JonathanLeffler你是認真的?他們究竟如何維持這一點?即編譯器必須「檢測」缺少的「return」,並且如果未找到,則替換爲0,但僅限於「main()」**?那是*可怕的*。很明顯,ideone上的gcc並不符合這個要求,因爲除非我明確地加上'return 0;'''main()''完成後報告運行時錯誤。 – WhozCraig

+0

是的,我很認真。在ISO/IEC 9899:2011中,§5.1.2.2.3**程序終止**它說:_如果'main'函數的返回類型是與'int'兼容的類型,則返回從 初始調用到'main'函數等同於用'main'函數返回的值 作爲參數調用'exit'函數;到達終止 main函數的'}'返回值爲0._腳註11表示:_根據6.2.4,在主' 中聲明的具有自動存儲持續時間的對象的生命週期將在前一種情況下結束,即使他們不會在後者._ –

0

出於某種原因,其他的答案只是指出,技術細節這是錯誤的,但沒有注意到什麼是真的錯了:你正在返回堆棧上的數組的地址。但是當函數返回時,訪問該數組變成未定義的行爲。其他代碼可以自由覆蓋內存,從而留下最糟糕的垃圾,或者相反,向返回指針後面的內存寫入內容可能會破壞代碼中某些其他完全未連接的部分的重要變量。

如果你想返回一個指針,則必須返回一個指向一個static對象,也必須返回一個指向東西就堆。這裏是static情況:保證爲staticArray保留的內存[]將保持其在整個程序的執行預留

char* foo() { 
    static char staticArray[1024]; 
    return staticArray; 
} 

使用static這裏。有,但是,三個缺點呢:

  1. 數組大小是固定在編譯時

  2. 這通常不是多線程安全的,因爲所有的線程將使用相同的全局分配的內存

  3. 您通常無法期望返回的指針後面的數據在函數調用中保持不變。考慮以下代碼:

    void bar() { 
        char* temp = foo(); 
        temp[0] = 7; 
    } 
    
    void baz() { 
        char* temp = foo(); 
        temp[0] = 3; 
        bar(); 
        //now temp[0] is 7 ! 
    } 
    

這可能是在某些罕見的情況下可取的,但是,在大多數不是這樣的。

所以,如果你想能夠自由地使用返回的指針後面的內存,你必須爲它的malloc()內存(當然,它後free())。就像這樣:

char* foo(int size) { 
    return malloc(size); 
} 

void baz() { 
    char* sevenBytes = foo(7); 
    //Do something with seven bytes 
    free(sevenBytes); 
} 

void bar() { 
    char* threeBytes = foo(3); 
    threeBytes[0] = 3; 
    baz(); 
    assert(threeBytes[0] == 3); //baz() worked on it's own memory 
    free(threeBytes); 
} 

在字符串處理的情況下,有一些在POSIX-2008標準,做內存分配給你,其中strdup()asprintf()提供方便的功能。下面是一些用法示例:

int main() { 
    char* hello = strdup("Hello"); 
    char* greeting; 
    if(0 > asprintf(&greeting, "%s World!\nMemory for hello was allocated at %llx", hello, (long long)hello)) { 
     //error handling 
    } 
    printf(greeting); 
    free(hello); 
    free(greeting); 
} 

這將打印出類似這樣:

Hello World! 
Memory for hello was allocated at c726de80 
+0

謝謝。是的,其他答案沒有完成,因爲我編輯了我最初的問題。 您的回答非常好,謝謝。你是否建議我儘可能經常使用strdup和asprintf? – PacDroid

+0

只要知道它們可用,我就會使用它們。不幸的是,到處都不是這樣,因爲並非所有系統都符合POSIX標準。他們也被提議用於C11標準,但由於一些不明確的原因,它們未被包括在其最終版本中。不過,它們可以在任何GNU/Linux系統上使用。 – cmaster

+0

好的,因爲我使用的是CentOS 6,它是可用的。 – PacDroid

相關問題