C语言中snprintf函数导致程序暂停并终止的问题排查
问题排查:snprintf调用导致程序崩溃的原因及修复
问题场景
编写to_string函数将customer结构体格式化为字符串,通过print_cus调用该函数时,程序在Windows系统运行时出现暂停终止,调试确认问题出在snprintf调用阶段。相关代码如下:
原to_string函数
char* to_string(customer cus) { char* buffer = (char*) malloc(BUFFER_SIZE); snprintf(buffer, BUFFER_SIZE, "||%-30s||%2d/%2d/%4d||%-30s||%-10s||%2d/%2d/%-4d||%-10.4lf||%-16s||" , cus.name, cus.birth.date, cus.birth.month, cus.birth.year, cus.address, cus.phone, cus.opening.date, cus.opening.month, cus.opening.year, cus.opening, cus.balance, cus.cardnum); return buffer; }
相关结构体及宏定义
#define FONE_SIZE 10 #define CARD_SIZE 16 #define NAME_SIZE 50 #define ADDRESS_SIZE 100 #define MAXCUS_SIZE 300 #define CHOICE_SIZE 18 #define BUFFER_SIZE 255 typedef struct { int date; int month; int year; } date; typedef struct { char name[NAME_SIZE]; date birth; char address[ADDRESS_SIZE]; char phone[FONE_SIZE]; date opening; double balance; char cardnum[CARD_SIZE]; } customer;
调用函数print_cus
void print_cus(customer* cus_arr, int cus_num) { printf("||%-30s||%-10s||%-30s||%-10s||%-10s||%-10s||%-16s||\n", "Customer's name", "Birth day", "Customer's address", "Phone number", "Open date", "Balance", "Card number"); for(int i = 0; i < cus_num; i++) { char* buffer = to_string(cus_arr[i]); puts(buffer); free(buffer); } }
错误分析
格式化符与参数不匹配(直接触发崩溃)
snprintf参数列表中错误传入了cus.opening这个date结构体变量,但对应的格式化符%-4d仅支持整数类型。将结构体直接传入需要整数的参数位置,会导致内存访问越界,直接引发程序崩溃。同时,此处多传了一个参数:开户日期部分的格式化符%2d/%2d/%-4d仅需要3个整数参数,代码中额外传入的cus.opening导致参数数量与格式化符数量不匹配,进一步加剧未定义行为。字符串数组未预留终止符空间
phone数组定义为FONE_SIZE=10,但格式化时使用%-10s,而C语言字符串必须以\0结尾。如果phone存满10个字符,会没有空间存放终止符,导致%s读取时越界访问内存,引发潜在崩溃或乱码。malloc未做空指针检查
to_string中调用malloc后未检查返回值,若内存分配失败,buffer会是NULL,后续snprintf写入NULL指针会直接导致程序崩溃。
修复方案
- 修正snprintf参数匹配问题:删除多余的
cus.opening参数,确保格式化符与参数一一对应。 - 调整字符串数组长度:为
phone、cardnum等字符串数组各增加1位长度,预留\0的存储空间。 - 添加malloc返回值检查:在使用
buffer前确认内存分配成功,避免写入NULL指针。
修复后的代码
修正后的宏定义和结构体
#define FONE_SIZE 11 // 预留1位存'\0' #define CARD_SIZE 17 // 预留1位存'\0' #define NAME_SIZE 50 #define ADDRESS_SIZE 100 #define MAXCUS_SIZE 300 #define CHOICE_SIZE 18 #define BUFFER_SIZE 255 typedef struct { int date; int month; int year; } date; typedef struct { char name[NAME_SIZE]; date birth; char address[ADDRESS_SIZE]; char phone[FONE_SIZE]; date opening; double balance; char cardnum[CARD_SIZE]; } customer;
修正后的to_string函数
char* to_string(customer cus) { char* buffer = (char*) malloc(BUFFER_SIZE); if (buffer == NULL) { // 检查内存分配是否成功 return NULL; } // 移除多余的cus.opening参数,确保参数与格式化符匹配 snprintf(buffer, BUFFER_SIZE, "||%-30s||%2d/%2d/%4d||%-30s||%-10s||%2d/%2d/%4d||%-10.4lf||%-16s||" , cus.name, cus.birth.date, cus.birth.month, cus.birth.year, cus.address, cus.phone, cus.opening.date, cus.opening.month, cus.opening.year, cus.balance, cus.cardnum); return buffer; }
优化后的print_cus函数(增加NULL检查)
void print_cus(customer* cus_arr, int cus_num) { printf("||%-30s||%-10s||%-30s||%-10s||%-10s||%-10s||%-16s||\n", "Customer's name", "Birth day", "Customer's address", "Phone number", "Open date", "Balance", "Card number"); for(int i = 0; i < cus_num; i++) { char* buffer = to_string(cus_arr[i]); if (buffer != NULL) { // 检查buffer是否有效 puts(buffer); free(buffer); } } }
内容的提问来源于stack exchange,提问作者Hibiki Supersanta
相关产品推荐
相关产品推荐

