不,在函数中返回指向本地字符串的指针是不安全的。C 不会阻止您这样做(尽管有时编译器会在您要求时警告您;在这种情况下,return_string
除非您将代码更改为 ,否则局部变量会阻止它发出警告return filled_buffer;
)。但这并不安全。基本上,该空间被其他函数重用,因此他们愉快地践踏了曾经整齐格式化的字符串。
你能更详细地解释这个评论吗?“不,这不安全……”
当函数返回时,局部变量(与字符串常量相反)超出范围。返回指向范围外变量的指针是未定义的行为,这是要不惜一切代价避免的事情。当你调用未定义的行为时,任何事情都可能发生——包括程序似乎可以工作——而且没有理由抱怨,即使程序重新格式化了你的硬盘驱动器。此外,不能保证相同的事情会在不同的机器上发生,甚至不能保证在当前机器上使用同一编译器的不同版本。
要么将输出缓冲区传递给函数,要么让函数用于malloc()
分配内存,这些内存可以返回给调用函数并由调用函数释放。
将输出缓冲区传递给函数
#include <stdio.h>
#include <string.h>
int reverse_string(char *input_string, char *buffer, size_t bufsiz);
int reverse_string(char *input_string, char *buffer, size_t bufsiz)
{
size_t j = 0;
size_t i = strlen(input_string);
if (i >= bufsiz)
return -1;
buffer[i] = '\0';
while (i != 0)
{
buffer[j] = input_string[i-1];
i--;
j++;
}
printf("%s\n", buffer);
return 0;
}
int main (void)
{
char buffer[16];
if (reverse_string("tasdflkj", buffer, sizeof(buffer)) == 0)
printf("%s\n", buffer);
return 0;
}
内存分配
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverse_string(char *input_string);
char *reverse_string(char *input_string)
{
size_t j = 0;
size_t i = strlen(input_string) + 1;
char *string = malloc(i);
if (string != 0)
{
string[--i] = '\0';
while (i != 0)
{
string[j] = input_string[i-1];
i--;
j++;
}
printf("%s\n", string);
}
return string;
}
int main (void)
{
char *buffer = reverse_string("tasdflkj");
if (buffer != 0)
{
printf("%s\n", buffer);
free(buffer);
}
return 0;
}
请注意,示例代码在每个格式字符串的末尾都包含一个换行符;它可以更容易地判断字符串的末端在哪里。
这是一种替代方法main()
,它表明即使在多次调用reverse_string()
函数后,返回的分配内存也是可以的(修改为采用 aconst char *
而不是普通char *
参数,但其他方面没有改变)。
int main (void)
{
const char *strings[4] =
{
"tasdflkj",
"amanaplanacanalpanama",
"tajikistan",
"ablewasiereisawelba",
};
char *reverse[4];
for (int i = 0; i < 4; i++)
{
reverse[i] = reverse_string(strings[i]);
if (reverse[i] != 0)
printf("[%s] reversed [%s]\n", strings[i], reverse[i]);
}
for (int i = 0; i < 4; i++)
{
printf("Still valid: %s\n", reverse[i]);
free(reverse[i]);
}
return 0;
}
另外(正如pwny在我添加此注释之前在他的回答中指出的那样),您需要确保您的字符串以空值结尾。返回指向本地字符串的指针仍然不安全,即使您可能不会立即发现示例代码的问题。这说明了输出末尾的垃圾。