我有一些应该调用函数并返回字符串的C代码。我在某个地方读到这很困难,因为内存分配不恒定或什么?无论如何,我被告知我宁愿将指针返回到字符串。但是,我无法解释为什么printf有时会产生乱码,有时却不会:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * execTasks() {
int d, m, y;
char str[6] = {};
d = 10; m = 5; y = 18;
memset(&str, 0, sizeof(str));
sprintf(str, "%02d%02d%02d", d, m, y);
printf("Works fine: %s\n", str); // Works fine even with additions
char *s_ptr = str;
return s_ptr;
}
int main() {
char * str;
str = execTasks();
printf("%s", str); // works fine!
printf("%s\n", str); // produces gibberish!
printf("%s,%s", str, str); // also gibberish!
return 0;
}
有人可以向我解释为什么printf("%s", str);
可以正常工作,而printf("%s\n", str);
和变化形式却显示出乱码吗?
还是我在返回指针时做错了什么?本质上,该函数应以字符串DDMMYY的格式返回日期。稍后我需要在main函数中将此字符串附加到另一个字符串。
答案 0 :(得分:2)
数组char str[6]
在execTasks
函数的本地。 execTasks
返回之后,该内存将被回收,并且可以由其他代码使用。碰巧printf
中的最后两个main
使用了该内存并破坏了字符串,而printf
中的第一个main
没有使用。但是,此代码仍然无效(如“未定义行为”),因为在适当的情况下(例如,不同的编译器,体系结构或标准库实现),它也会产生乱码或崩溃。
要解决的问题是,您不应返回指向局部变量的指针,而应使用动态分配的字符串副本:
char * execTasks() {
int d, m, y;
char str[7] = {};
// ...
return strdup(str); // mallocs a copy of str
}
int main() {
char * str = execTasks();
printf("%s,%s", str, str);
free(str); // reclaim memory
}
或使用main
局部变量:
int execTasks(char *str, size_t size) {
int d, m, y;
d = 10; m = 5; y = 18;
return snprintf(str, size, "%02d%02d%02d", d, m, y);
}
int main() {
char str[7];
execTasks(str, sizeof(str));
printf("%s,%s", str, str);
}
此处execTasks
返回保存结果所需的字符数(不包括空终止符)。它可以用来检测何时提供的缓冲区太小,尽管在这个简单的示例中我没有这样做(如果太小,字符串将被截断)。
还请注意,字符串所需的内存量为七个char
,因为您需要为空终止符增加一个字节。