由于我无法返回局部变量,从C或C ++函数返回字符串的最佳方法是什么?

作为这个问题的后续行动:

从我所看到的,这应该按预期工作:

void greet(){ char c[] = "Hello"; greetWith(c); return; } 

但这会导致未定义的行为:

 char *greet(){ char c[] = "Hello"; return c; } 

如果我是对的,那么修复第二个问候语function的最佳方法是什么? 在嵌入式环境中? 在桌面上?

你是绝对正确的。 第二个示例中的c数组正在堆栈中分配,因此内存将立即重用。 特别是,如果你有像这样的代码

  printf("%s\n",greet()); 

你会得到奇怪的结果,因为对printf的调用会重用你arrays的一些空间。

解决方案是在其他地方分配内存。 例如:

 char c[] = "Hello"; char * greet() { return c; } 

会工作。 另一种选择是在范围内静态分配:

 char * greet() { static char c[] = "Hello"; return c; } 

因为静态内存是在数据空间中与堆栈分开分配的。

你的第三个选择是通过malloc在堆上分配它:

 char * greet() { char * c = (char *) malloc(strlen("Hello")+1); /* +1 for the null */ strcpy(c, "Hello"); return c; } 

但现在你必须确保以某种方式释放内存,否则你会有内存泄漏。

更新

其中一件似乎比我预料的更令人困惑的是“内存泄漏”到底是什么。 泄漏是指您动态分配内存,但丢失地址以便无法释放。 这些示例都不一定有漏洞,但只有第三个漏洞甚至可能有漏洞,因为它是唯一一个动态分配内存的漏洞。 因此,假设第三个实现,您可以编写以下代码:

 { /* stuff happens */ printf("%s\n", greet()); } 

这有泄漏; 返回指向malloc的内存的指针, printf使用它,然后丢失; 你不能再释放它了。 另一方面,

 { char * cp ; /* stuff happens */ cp = greet(); printf("%s\n", cp); free(cp); } 

不会泄漏,因为指针保存在自动变量cp足够长,可以调用free() 。 现在,即使cp在执行通过后立即消失,但由于已经调用了free,因此内存被回收并且没有泄漏。

如果您使用的是C ++,那么您可能需要考虑使用std::string从第二个函数返回字符串:

 std::string greet() { char c[] = "Hello"; return std::string(c); // note the use of the constructor call is redundant here } 

或者,在单线程环境中,您可以执行以下操作:

 char *greet() { static char c[] = "Hello"; return c; } 

static在这里分配全局内存区域中的空间,它永远不会消失。 不过,这种static方法充满了危险。

取决于嵌入式环境是否有堆,如果是,你应该malloc如下:

 char* greet() { char* ret = malloc(6 * sizeof(char)); // technically " * sizeof(char)" isn't needed since it is 1 by definition strcpy(ret,"hello"); return ret; } 

请注意,您应该稍后调用free()进行清理。 如果您无权访问动态分配,则需要将其设置为堆栈中的全局变量或变量,但需要进一步调用堆栈。

如果你需要在C ++中这样做,那么使用Greg Hewgill建议的std::string绝对是最简单和可维护的策略。

如果你正在使用C,你可以考虑返回一个指向空间的指针,该空间已经按照Jesse Pepper的建议动态分配了malloc() ; 但另一种可以避免动态分配的方法是让greet()接受一个char *参数并将其输出写入:

 void greet(char *buf, int size) { char c[] = "Hello"; if (strlen(c) + 1 > size) { printf("Buffer size too small!"); exit(1); } strcpy(buf, c); } 

size参数是为了安全起见,以帮助防止缓冲区溢出。 如果你确切知道字符串的长度,那就没有必要了。

您可以使用以下任一方法:

 char const* getIt() { return "hello"; } char * getIt() { static char thing[] = "hello"; return thing; } char * getIt() { char str[] = "hello"; char * thing = new char[sizeof str]; std::strcpy(thing, str); return thing; } shared_array getIt() { char str[] = "hello"; shared_array thing(new char[sizeof str]); std::strcpy(thing.get(), str); return thing; } 

第一个要求您不要写入返回的字符串,但也是最简单的。 最后一个使用shared_array,如果对内存的引用丢失(最后一个shared_array超出范围),它会自动清理内存。 如果每次调用函数时都需要新字符串,则必须使用last和last。

从几个其他响应建议的函数返回malloc内存只是要求内存泄漏。 调用者必须知道你malloc’d它然后免费拨打电话。 如果他们碰巧在其上调用了删除,结果是不确定的(尽管可能没问题)。

最好强制调用者为您提供内存,然后将字符串复制到其中。 通过这种方式,呼叫者注意到他/她需要清理。

从我读过的最安全的选项是让调用者负责分配内存来保存字符串。 您还必须检查缓冲区是否足够大以容纳您的字符串:

 char *greet(char *buf, int size) { char *str = "Hello!" if (strlen(str) + 1 > size) { // Remember the terminal null! return NULL; } strcpy(buf, str); return buf; } void do_greet() { char buf[SIZE]; if (greet(buf, SIZE) == NULL) { printf("Stupid C"); } else {} // Greeted! } 

为一项简单的任务做了大量工作……但是你有C :-)哎呀! 猜猜我被random_hacker殴打了……

在堆中分配字符数组?

是否可以使用malloc取决于“嵌入式环境”的含义。