2017-08-02 113 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的学习或许多可能会遵循的意愿发生';)' –