最近,我一直在学习哈佛大学的CS50 2020课程,作为C编程的入门。我对语言或整体编码不是很有经验,所以我在努力弄清楚我的代码有什么问题。
我编写了这个小函数,该函数应该接收字符串,然后通过调用另一个函数,使用凯撒密码对文本进行加密,然后将其作为字符串返回。问题是,我不知道如何将字符数组作为字符串返回。在阅读了一些有关该问题的信息后,我尝试在数组的末尾添加一个NUL char,它可以正确编译,但是当我运行该程序时,出现以下错误消息:
error: address of stack memory associated with local variable 'result' returned [-Werror,-Wreturn-stack-address]
return result;
^~~~~~
我的代码:
string encypher(string text)
{
int length = strlen(text);
char result[length];
for(int i = 0; i < length; i++)
{
int letter_c = test_char(text[i]);
result[i] = (char)letter_c;
}
result[length + 1] = '\0';
return result;
}
这里的问题是,result
是一个数组,在表达式中使用时会衰减到指向其第一个元素的指针,这就是从函数返回的内容。而且由于函数的返回时间会终止数组的生存期,因此该指针现在指向无效的内存位置,并且尝试使用它会调用undefined behavior。
不是创建本地数组,而是使用malloc
函数动态分配内存。该内存在程序有效期内有效,或者直到返回的指针传递给free
为止有效:
string result = malloc(length + 1);
此外,请注意,您需要为用于终止字符串的空字节预留一个额外的字节。
在线
return result;
指向指针的数组decays,因此实际上是以下内容:
return &result[0];
此数组在函数encypher
中的堆栈上分配,因此在函数返回时它将不再存在。因此,返回的指针是dangling pointer,这意味着它指向不再分配的内存,并且可能被其他内容覆盖。因此,不应使用此类指针。
为了分配在函数返回后仍然存在的内存,您可以:
malloc
malloc
的函数的堆栈上分配内存(而不是在函数encypher
本身中分配内存,并更改函数encypher
的参数以接受指向该数组的指针。我认为第二种解决方案是更清洁的解决方案,因为它允许调用方决定在何处以及如何分配内存。使用该解决方案,您的代码将如下所示:
encypher
现在可以这样调用该函数:
void encypher( char *cyphertext, const char *plaintext )
{
int length = strlen(plaintext);
//removed: char result[length];
for(int i = 0; i < length; i++)
{
int letter_c = test_char(plaintext[i]);
cyphertext[i] = (char)letter_c;
}
cyphertext[length + 1] = '\0';
}