2017-08-02 157 views
2
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <ctype.h> 

char * upperCase(const char* s) 
{ 
    char * ret = NULL; 
    size_t length = strlen(s) + 1; 
    ret = (char*)malloc(sizeof(char) * length); 
    for (size_t i = 0; i < length; i++) { 
     ret[i] = toupper(s[i]); 
    } 
    return ret; 
} 

int main() 
{ 
    char* ret = NULL; 
    char* input = "HelloWorld"; 
    ret = upperCase(input); 
    printf("value = %s", ret); 
    free(ret); 
} 

上述代碼將字符串作爲參數並複製該字符串。它 然後將複製的字符串的每個元素轉換爲大寫,然後 返回它。我可以使用「malloc」作爲局部變量來返回局部變量嗎?

編譯器GCC = 6.2

如果使用malloc函數,是可以返回一個局部變量來終止功能和釋放內存?我對於仍然有記憶的範圍沒有足夠的瞭解。

+4

是的,你可以做到這一點。問題在於返回指向不存在的事物的指針,但是你的'malloc'繼續存在,直到你釋放它。另一種選擇是將輸出指針作爲參數,這樣內存管理留給調用者。 – Ryan

+0

'sizeof(char)'的定義是1。 – melpomene

+2

'toupper(s [i])'具有未定義的行爲,如果s [i]'爲負數。你應該把它轉換成'unsigned char'。 – melpomene

回答

2

是的,你可以。

malloc內存在堆上,所以當upperCase結束時它不會釋放。

但是變量char *ret在棧上,當upperCase結束時會彈出。但中的ret的值通過ret = upperCase(input)main()中複製。也就是說,你仍然可以獲得分配的內存地址,它仍然在堆上。完成使用此內存後,您可以撥打free(ret)


檢查What and where are the stack and heap?約棧&堆細節。

+0

非常感謝。我能理解一些我不確定的事情。它幫助了很多。 – YunjinJang

4

簡短的回答:是的,這是可能的

龍回答malloc(some_size)分配some_size空間,並返回一個指向分配塊的開始(或NULL失敗時)的地址。在做ret = (char*)malloc(sizeof(char) * length); ret時,指定內存塊的指針指向內存塊lengthchar s(請注意,sizeof(char) == 1因此您可以將其刪除)。

內存是你的,直到你釋放它,即使在函數返回後,所以,在執行完upperCase(...)之後,該內存仍然屬於你。唯一的問題是,指針ret被分配在本地存儲的(auto)堆棧上,這意味着當它的作用域爲「死」(在你的情況下 - upperCase(...)函數的作用域),因此,你將不知道該內存的位置是但是由於您從函數返回ret,它所保存的值(這是您分配的內存的地址)將傳遞到mainret,這基本上意味着您很好。

我認爲我應該強調的最後一件事是,返回局部變量始終完成。例如int increment_by_one(int x){int y = x + 1; return y;}。這是一個非常簡單的函數,返回當地的值int y。由於返回的值是我們需要的全部值(即值爲x+1),因此值(值)存儲在局部變量中是可以的。因爲ret裏面upperCase包含分配的地址,所以「die」結束後,upperCase結束,因爲它保存的值(地址)被傳遞。

char * upperCase(const char* s) 
{ 
    char * ret = NULL;        // local variable -> will die after upperCase ends 
    size_t length = strlen(s) + 1;     // local variable -> will die after upperCase ends 
    ret = (char*)malloc(sizeof(char) * length); // ret assigned with address to memory 
    for (size_t i = 0; i < length; i++) {   // local variable -> will die after it's scope (the for loop) ends 
     ret[i] = toupper(s[i]); 
    } 
    return ret;          // said address is returned to main (local variable ret now dies peacefully after fulfilling its duty) 
} 

int main() 
{ 
    char* ret = NULL;    // local variable -> will die after main ends 
    char* input = "HelloWorld";  // local variable -> will die after main ends 
    ret = upperCase(input);   // ret gets the address allocated in upperCase 
    printf("value = %s", ret); 
    free(ret);      // address is freed 
} 

2注:

  1. 無需鑄造malloc的返回值,這意味着ret = (char*)malloc(sizeof(char) * length);ret = malloc(sizeof(char) * length);
  2. 沒有必要sizeof(char),因爲它是1,這意味着你可以進一步縮短至ret = malloc(length);
  3. malloc可能會失敗。在這種情況下,它會返回NULL所以每次ret = malloc(...);後,你應該檢查值像if(!ret){// handle error}if(ret != NULL){// do something}和這樣
+0

沒有必要施放'malloc'的返回,這是沒有必要的。請參閱:[**我是否投出了malloc **的結果](http://stackoverflow.com/q/605845/995714),***總是***驗證'malloc'的返回值(例如,在' main()'(在'printf'和'free'之前),至少需要'if(ret){/ * do stuff * /}'或'if(!ret){/ *處理錯誤,或者退出* /}'。否則好的回答和努力。 –

+0

@ DavidC.Rankin說不需要malloc是我的意思,我會編輯它以使其更清晰。關於'if(!ret)',我提到'malloc '可以返回NULL,但我不想更改OP的代碼 – CIsForCookies

+2

是的,它看起來像原始問題中的複製/粘貼問題,但它總是值得清理,所以OP的學習或許多可能會遵循的意願發生';)' –