You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:40:09