解决C语言的内存释放机制

昨天在写代码的时候,要记录用户的行为日志,需要获取本地时间,就浅浅写了一个获取本地时间的函数,在控制台测试了一下没问题,就准备直接美美写入文件了,结束今天的码代码任务。

测试时正常输出的图如下:

但是(这个时候一般都有一个但是🤣),发现写入文件里面的就发现乱来了,下图是我文件中记录的日志:

为什么控制台输出好好的,写入文件就不行了。

一开始我觉得可能是我写的时间函数输入的编码问题,可能不是中文识别的编码,下面是我的时间函数代码:

perl 复制代码
char* currentTime(){
    time_t timep;
    struct tm *p;
    char time1[30];
    time(&timep);
    p=gmtime(&timep);
    sprintf(time1,"%d年%d月%d日 %d:%d:%d",1900+p->tm_year,1+p->tm_mon,p->tm_mday,8+p->tm_hour,p->tm_min,p->tm_sec);
    printf("当前时间为:%s\n",time1);
    return time1;
}

左看看,右看看,没有问题呀,而且写入文件的时候,除了时间,其他日志信息都是正常输出的,那应该不是编码的问题了。

然后我就开始debug了,一步步跟进,看到底是什么问题。

debug的阶段没有什么好看的,因为我用的都是char *类型,地址都是同一个地址,地址里面指向的内容也都是正确的时间,但是当我新写了一个main函数, 在main函数里面调用的时候currentTime函数时,经过printf函数后,发现time2变量里面指的内容被修改了,莫非,printf会改掉我的地址内容。

这是我加入main函数之后的代码,在经过第18句的printf函数后,time2指针指向的地址被修改掉了。

arduino 复制代码
#include <stdio.h>
#include <time.h>

char* currentTime1(){
    time_t timep;
    struct tm *p;
    char time1[30];
    time(&timep);
    p=gmtime(&timep);
    sprintf(time1,"%d年%d月%d日 %d:%d:%d",1900+p->tm_year,1+p->tm_mon,p->tm_mday,8+p->tm_hour,p->tm_min,p->tm_sec);
    printf("当前时间为:%s\n",time1);
	  return time1;
}

int main(){
	char* time2;
	time2 = currentTime1();
	printf("当前时间为:%s\n",time2);
	return 0;
}

下面是输出的截图:

但是,main函数输出的printf明明和currentTest1函数里面输出的printf函数一模一样啊,虽然我不知道C语言的底层原理是什么,但是printf函数和我"朝夕相处",它肯定是清白的。

然后我仔细查看我的代码,突然看到链表的添加节点函数时,总是用malloc函数去申请新节点,突然意识到可能是currentTest1函数里面time1数组申请的地址在退出当前函数时,变量被释放掉了,然后我开始大胆假设,小心求证阶段。

于是,我在main函数中加入了一些其他没用的函数,去频繁退出函数栈,看是不是因为退出函数栈自动释放变量的的原因。

下面是我验证的代码:

arduino 复制代码
#include <stdio.h>
#include <time.h>

char* currentTime1(){
    time_t timep;
    struct tm *p;
    char time1[30];
    time(&timep);
    p=gmtime(&timep);
    sprintf(time1,"%d年%d月%d日 %d:%d:%d",1900+p->tm_year,1+p->tm_mon,p->tm_mday,8+p->tm_hour,p->tm_min,p->tm_sec);
    printf("当前时间为:%s\n",time1);
	printf("当前时间为:%s\n",time1);
	return time1;
}

int test(char* a) {
	char *b = a;

	return 0;
}

int main(){
	char* time2,*aaaa;
	time2 = currentTime1();
	aaaa = time2;
	test(aaaa);
	printf("当前时间为:%s\n",time2);
	printf("当前时间为:%s\n",time2);
	test(aaaa);
	return 0;
}

我一行一行的debug,第25行运行结束,两个变量指向内容一致,正常!

第26行运行结束,好家伙,内容就全部改变了。异常!

第27行运行,内容再次改变,异常!

输出界面如下:

正好验证了我的猜想,然后去百度上翻阅了一些资料,原来在 C 语言中,临时变量的内存空间是在栈上分配的,它们的内存空间在变量作用域结束时会自动被释放。如果需要动态分配内存,可以使用 malloc 函数。当再需要这些内存时,可以使用 free 函数来释放它们,因为malloc函数都不会自动释放内存,所以需要手动调用它们来管理内存。

在我的代码中,我的currentTime 函数返回的是 time1 的地址,这是一个局部变量。当 currentTime 函数结束后,time1 将不再存在,也就是自动释放了,所以 time2 指向的内存区域是未定义的。这块地址可能被其他程序使用了,再次输出里面的值的时候,就是乱码了。

知道了错误,就开始修改啦。

我在main函数申请一个变量,然后将其地址传入currenTime函数中,再返回回来,就是正确的啦,和交换两个变量数字一样的原理。代码如下:

arduino 复制代码
#include <stdio.h>
#include <time.h>

void currentTime(char* time1){
    time_t timep;
    struct tm *p;
    time(&timep);
    p=gmtime(&timep);
    sprintf(time1,"%d年%d月%d日 %d:%d:%d",1900+p->tm_year,1+p->tm_mon,p->tm_mday,8+p->tm_hour,p->tm_min,p->tm_sec);
    printf("当前时间为:%s\n",time1);
}


int main(){
	char time2[30];
	currentTime(time2);
	return 0;
}

输出的界面如下:

然后我就将函数直接接入我的代码里面啦,现在就可以正常写入啦,日志文件截图如下,完美。

下班喽,美美休息,明天再卷。

(ps:对啦,最近在写一个小项目,学习巩固自己的C语言知识,之后写完就出一篇小文章讲讲我的代码,以及写代码遇到的困难呀)

相关推荐
陈随易7 分钟前
Lodash 杀手来了!es-toolkit v1.39.0 已完全兼容4年未更新的 Lodash
前端·后端·程序员
未来影子25 分钟前
SpringAI(GA):Nacos3下的分布式MCP
后端·架构·ai编程
Hockor37 分钟前
写给前端的 Python 教程三(字符串驻留和小整数池)
前端·后端·python
码农之王37 分钟前
记录一次,利用AI DeepSeek,解决工作中算法和无限级树模型问题
后端·算法
Wo3Shi4七38 分钟前
消息不丢失:生产者收到写入成功响应后消息一定不会丢失吗?
后端·kafka·消息队列
爱上语文39 分钟前
MyBatisPlus(3):常用配置
java·后端·mybatis
编程乐趣42 分钟前
C#实现Stdio通信方式的MCP Server
后端
程序猿本员44 分钟前
线程池精华
c++·后端
袁煦丞1 小时前
电子书阅读器界的"万能工具"Koodo Reader :cpolar内网穿透实验室第593个成功挑战
前端·后端·远程工作
懋学的前端攻城狮1 小时前
深入浅出JVM-03:Java虚拟机垃圾回收机制详解
java·jvm·后端