#include <time.h>
#include <stdio.h>
#include <stdlib.h>
char *czas()
{
time_t rawtime;
struct tm * timeinfo;
char buffer [80];
time ( &rawtime );
timeinfo = localtime ( &rawtime );
strftime (buffer,80,"Now it's %I:%M%p.",timeinfo);
return buffer;
}
int main()
{
printf("%s",czas());
system("PAUSE");
}
我不知道为什么,但这个程序的结果只是“按任意键(...)”。我也尝试将其打印为%c但它仍然无法正常工作。这个程序有什么问题?
答案 0 :(得分:10)
您正在返回指向本地变量('缓冲区')的指针,这是无效的,我很惊讶您没有收到有关它的警告。
当函数退出时,所有局部变量都不再存在(称为超出范围),并且它们的内存将用于其他目的。你正在返回一个指向这个记忆的指针,但不能保证现在会有什么。
在这种情况下,似乎在printf调用时,内存包含一个被视为空字符串的0。这实际上是非常幸运的,你可能很容易因为打印垃圾或程序崩溃而结束。
要解决此问题,您可以将缓冲区传递给czas,或者让czas在堆上分配一个缓冲区,稍后您将释放该缓冲区。我会推荐前者,因为它与几乎所有库函数的工作方式一致。它还避免了调用者必须稍后释放指针的内存分配。
E.g:
size_t czas(char* buffer, size_t buffer_size)
{
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
return strftime (buffer, buffer_size,"Now it's %I:%M%p.",timeinfo);
}
int main()
{
char buffer [80];
if (czas(buffer, 80))
{
printf("%s\n",buffer);
}
else
{
printf("Call to czas failed");
}
system("PAUSE");
}
更新:我没有注意到strftime采用了一个大小参数,我已经更新了代码以使用它并正确地从strftime传回结果。因此,它更加强大,您不会意外地溢出缓冲区。
答案 1 :(得分:4)
语句char buffer [80];
使buffer
在csas的堆栈中分配。将其替换为malloc
(char *buffer = malloc (80)
),您应该没问题。你以后必须自己释放缓冲区。
答案 2 :(得分:4)
函数中的返回缓冲区应该不在堆栈上。由于您已将自动变量声明为固定大小的数组,因此它位于堆栈中。你返回一个指向它的指针,但是,那个空格可以被随后的函数调用“潦草地写下”。
或者:
两种选择都有缺点。在我列举之前你将得到17个答案: - )
答案 3 :(得分:3)
因为缓冲区是一个局部变量,当函数返回时会蒸发 - 你所看到的是未定义的行为。对此进行快速而肮脏的修复是使缓冲区静止,以便在函数调用后挂起 - 更改:
char buffer [80];
为:
static char buffer [80];
答案 4 :(得分:2)
不要使用静态缓冲区,除非您确定永远不会在多线程代码中使用它,并且在使用第一个答案之前绝不会再调用它。
Malloc是一个选项,但是强制调用者释放被调用者分配的内存可能会留下未解决的所有权问题,并且除了缓冲区的堆内存之外不会使用任何东西。
在我看来,你最好的选择是修改安德鲁·格兰特的建议,但也可以通过缓冲区的长度:
char *czas(char *buffer, size_t bufferLength)
{
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
strftime (buffer, bufferLength, "Now it's %I:%M%p.",timeinfo);
return buffer;
}
int main()
{
char buffer [80];
printf("%s",czas(buffer, sizeof(buffer)));
system("PAUSE");
}
或
#define TIME_BUFFER_LENGTH 80
int main()
{
char *buffer = malloc(TIME_BUFFER_LENGTH);
if (buffer)
printf("%s",czas(buffer, TIME_BUFFER_LENGTH));
free(buffer);
system("PAUSE");
}
这使得更容易跟踪潜在的内存泄漏和缓冲区溢出。您可以查看czas
并查看只要参数正确,该函数就不会溢出任何缓冲区,也不会泄漏任何内存。接下来,您可以查看main
的任一版本,并查看没有内存泄漏,并且传递给czas的参数是正确的(bufferLength参数准确指定缓冲区指向的空间量。)
答案 5 :(得分:0)
你调用czas()但是在返回之后,czas创建的缓冲区不再存在。
答案 6 :(得分:0)
您正在返回在堆栈上分配的“缓冲区”。但是一旦函数返回,堆栈的那部分就不再有效了。
为堆上返回的字符串分配内存,或者使用std :: string作为返回值。