从我所看到的,这应该按预期工作:
void greet(){
char c[] = "Hello";
greetWith(c);
return;
}
但这会导致未定义的行为:
char *greet(){
char c[] = "Hello";
return c;
}
如果我是正确的,那么如何修复第二个问候函数?在嵌入式环境中?在桌面上?
void greet(){
char c[] = "Hello";
greetWith(c);
return;
}
但这会导致未定义的行为:
char *greet(){
char c[] = "Hello";
return c;
}
如果我是正确的,那么如何修复第二个问候函数?在嵌入式环境中?在桌面上?
你说得完全正确。第二个例子中的 c 数组是在堆栈上分配的,因此内存将立即被重用。特别是,如果你有像下面这样的代码:
printf("%s\n",greet());
如果您使用printf调用并重复使用了数组的一些空间,那么您将获得奇怪的结果。
解决方法是在其他地方分配内存。例如:
char c[] = "Hello";
char * greet() {
return c;
}
可以工作。另一个选择是在范围内静态分配它:
char * greet() {
static char c[] = "Hello";
return c;
}
char * greet() {
char * c = (char *) malloc(strlen("Hello")+1); /* +1 for the null */
strcpy(c, "Hello");
return c;
}
但现在你必须确保内存得到释放,否则就会出现内存泄漏。
有些事情比我预期的更加令人困惑,其中一个就是“内存泄漏”的确切含义。当你动态分配内存,但丢失了地址以至于无法释放时,就会发生泄漏。这些示例中没有一个必然会出现泄漏,但只有第三个示例有可能会出现泄漏,因为它是唯一一个动态分配内存的示例。所以,假设使用第三个实现,你可以编写以下代码:
{
/* stuff happens */
printf("%s\n", greet());
}
这里存在一个内存泄漏问题;指向动态分配的内存的指针被返回,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
方法也充满了危险。
const
并在全局范围内定义,那么就会更加安全。 - ChrisW这要取决于嵌入式环境是否具有堆内存。如果有,你应该按照以下方式使用 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;
}
std::string
绝对是最简单和可维护的策略。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 c[]
是不必要的;通常在使用这种方法时,数据会直接复制到 buf
中。 - congusbonguschar *c = "Hello";
,这样就不会在栈上创建字符串字面量的不必要副本了。 - j_random_hacker您可以使用以下任一选项:
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<char> getIt() {
char str[] = "hello";
shared_array<char> thing(new char[sizeof str]);
std::strcpy(thing.get(), str);
return thing;
}
按照其他回答所建议的在函数中返回malloc'd内存只会导致内存泄漏。调用者需要知道你使用了malloc并调用free来释放内存。如果他们错误地调用delete,则结果是未定义的(尽管可能没有问题)。
更好的方法是强制调用者为您提供内存,然后将字符串复制到内存中。这样调用者就知道他/她需要清理内存。
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!
}
在堆中分配字符数组?
能否使用malloc
取决于您所说的“嵌入式环境”的具体含义。