C语言函数返回时栈溢出问题:附12小时转24小时转换程序
解决12小时制转24小时制程序的栈溢出问题
看起来你这个时间转换程序在get_tokens函数返回时触发了栈溢出(Stack smashing),我来帮你拆解问题根源,再给出可行的修复方案:
问题核心原因
你的get_tokens函数里有两个关键问题,其中一个直接导致了栈溢出:
- 栈数组越界写入:函数中
fields[num_f] = strtok(...)的操作完全依赖调用者传入的fields数组有足够容量。如果调用时你传入的是栈上分配的数组,且分割出的token数量超过了数组长度,程序就会往栈内存的非法区域写数据,触发栈溢出保护机制。 - 内存泄漏 + 截断风险:你用
malloc分配了ptr但没释放,会造成内存泄漏;另外strncpy(ptr, buf, 10)固定只复制10个字符,要是输入的时间字符串更长,会被截断,可能导致token分割不完整。
修复方案
方案1:限制token数量,避免栈数组越界
最简单的修复是给get_tokens加一个参数,限制最大可存储的token数,同时确保调用时传入的数组足够大:
修改后的get_tokens函数:
int get_tokens(char* buf, char *fields[], char *sep, int max_fields){ // 根据输入buf的实际长度分配内存,避免截断 size_t buf_len = strlen(buf); char* ptr = malloc(buf_len + 1); if (!ptr) { perror("malloc failed"); return -1; } strcpy(ptr, buf); int num_f = 0; // 增加max_fields检查,防止越界写入栈数组 while (num_f < max_fields && (fields[num_f] = strtok(ptr, sep)) != NULL) { ptr = NULL; num_f++; } // 注意:这里不能free(ptr)!因为strtok返回的指针指向ptr的内存区域,free后fields里的指针会变成野指针 // 若要避免内存泄漏,需在调用完get_tokens、处理完fields后,手动free这个ptr // 或者调整设计,让调用者传入可修改的缓冲区 return num_f; }
调用示例(假设时间格式最多分割为4个token,比如HH:MM:SS AM):
char time_str[] = "03:45:22 PM"; char *fields[4]; // 栈数组大小刚好容纳所有可能的token int num_tokens = get_tokens(time_str, fields, ": ", 4); // 处理完token后,记得free分配的ptr // 可调整函数返回ptr:char* get_tokens(...) { ... return ptr; } // 调用后:char* ptr = get_tokens(...); ... free(ptr);
方案2:重构为动态分配token数组(彻底避免栈依赖)
如果不想受限于栈数组的大小,可以让函数动态分配token数组,这样更安全也更灵活:
// 动态分配token数组,最后一个元素为NULL;调用者需用free_tokens释放 char** get_tokens(char* buf, char *sep, int *num_fields){ size_t buf_len = strlen(buf); char* ptr = malloc(buf_len + 1); if (!ptr) { perror("malloc failed"); *num_fields = -1; return NULL; } strcpy(ptr, buf); // 先统计token数量 int count = 0; char* temp = strtok(ptr, sep); while (temp != NULL) { count++; temp = strtok(NULL, sep); } // 重新分配ptr(因为strtok已经修改了原ptr的内容) free(ptr); ptr = malloc(buf_len + 1); strcpy(ptr, buf); // 分配token数组 char** tokens = malloc((count + 1) * sizeof(char*)); if (!tokens) { perror("malloc failed"); free(ptr); *num_fields = -1; return NULL; } // 填充token数组,同时复制每个token的内容(避免依赖ptr的内存) int i = 0; tokens[i] = strtok(ptr, sep); while (tokens[i] != NULL) { tokens[i] = strdup(tokens[i]); // 复制token到独立内存 if (!tokens[i]) { // 出错时回滚已分配的内存 for (int k = 0; k < i; k++) free(tokens[k]); free(tokens); free(ptr); *num_fields = -1; return NULL; } i++; tokens[i] = strtok(NULL, sep); } tokens[count] = NULL; *num_fields = count; free(ptr); // 现在可以安全释放ptr了 return tokens; } // 辅助函数:释放动态分配的token数组 void free_tokens(char** tokens){ if (!tokens) return; int i = 0; while (tokens[i] != NULL) { free(tokens[i]); i++; } free(tokens); }
调用示例:
int num_tokens; char** tokens = get_tokens("09:15:05 AM", ": ", &num_tokens); if (tokens) { // 处理每个token,比如提取小时、分钟、秒、AM/PM for (int i = 0; i < num_tokens; i++) { printf("Token %d: %s\n", i, tokens[i]); } free_tokens(tokens); // 记得释放内存 }
额外提醒
你的代码里char* tim...是截断状态,假设是时间转换的主逻辑部分,处理AM/PM转24小时制时,也要注意边界情况(比如12:00 AM要转成00:00,12:00 PM保持12:00),同时避免其他可能的内存越界操作。
内容的提问来源于stack exchange,提问作者Abhishek Jain
相关产品推荐
相关产品推荐

