time_t与char*变量意外被覆盖问题及解决方案咨询
先看你给出的代码:
{ time_t t; t = time(NULL); char *A; A = ctime(&t); printf("%s -", A); sleep(2); time_t t1; t1 = time(NULL); printf("%s HERE A =", A); char *B = ctime(&t1); printf("%s HERE B =", B); printf("%s", B); }
实际输出:
Sat Mar 30 19:10:33 2019 - Sat Mar 30 19:10:33 2019 HERE A = Sat Mar 30 19:10:35 2019 HERE B = Sat Mar 30 19:10:35 2019
预期输出:
Sat Mar 30 19:10:33 2019 - Sat Mar 30 19:10:33 2019 HERE A = Sat Mar 30 19:10:33 2019 HERE B = Sat Mar 30 19:10:35 2019
为什么A指向的内容会被修改?
核心原因是ctime()返回的指针指向的是一个全局静态缓冲区。这个缓冲区是C标准库内部维护的,所有调用ctime()、asctime()这类函数的地方,都会复用同一块内存空间。
第一次调用ctime(&t)时,这个静态缓冲区被写入了19:10:33的时间字符串,A指向的就是这块内存。当你过了2秒调用ctime(&t1)时,标准库直接把新的时间字符串(19:10:35)覆盖到了同一个缓冲区里。而A依然指向这块缓冲区,所以你后续打印A的时候,看到的就是被覆盖后的新内容。
为什么改成const char *A没用?
const char *A的意思是:你不能通过指针A去修改它指向的内存内容,但这并不限制其他代码(比如ctime()函数本身)修改这块内存。因为静态缓冲区的所有权在标准库手里,它有权随时修改,const只是给你的指针加了操作限制,改变不了缓冲区的本质。
怎么让A保持固定值?
解决思路很简单:把ctime返回的字符串复制一份到你自己管理的内存里,这样后续的ctime调用就不会影响到A的内容了。这里有两种常用方法:
方法1:用strdup()复制(简单但注意内存释放)
strdup()会自动分配足够的内存,把字符串复制进去,返回指向新内存的指针。代码修改如下:
{ time_t t; t = time(NULL); char *A = strdup(ctime(&t)); // 复制到新内存 printf("%s -", A); sleep(2); time_t t1; t1 = time(NULL); printf("%s HERE A =", A); char *B = ctime(&t1); printf("%s HERE B =", B); printf("%s", B); free(A); // 用完记得释放内存,避免泄漏 }
注意:strdup是POSIX标准函数,不是C标准,但几乎所有主流编译器和系统都支持它。
方法2:自己分配数组,用strcpy/strncpy复制(更可控)
如果你想避免使用非标准函数,可以自己定义一个足够大的字符数组(ctime返回的字符串固定是25个字符,包含换行符和终止符,所以数组开26个足够):
{ time_t t; t = time(NULL); char A[26]; // 足够容纳ctime的输出 strcpy(A, ctime(&t)); // 复制内容到自己的数组 // 或者更安全的strncpy(防止意外溢出) // strncpy(A, ctime(&t), sizeof(A)-1); // A[sizeof(A)-1] = '\0'; printf("%s -", A); sleep(2); time_t t1; t1 = time(NULL); printf("%s HERE A =", A); char *B = ctime(&t1); printf("%s HERE B =", B); printf("%s", B); }
这种方法不需要手动释放内存,因为数组是栈上分配的,函数结束后会自动回收。
内容的提问来源于stack exchange,提问作者raunaque patra

