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

C语言字符串拼接出现意外结果的原因排查

问题分析与解决:C语言路径拼接重复问题

问题现象

这段C程序意图为argv传入的路径末尾补加/(若路径未以/结尾),再拼接文件名,但出现以下异常:

  • 循环首次迭代输出正常路径,第二次迭代会出现重复拼接,例如输出/home/developer/folder/anotherfolder/test.shtest.sh
  • 线程版本运行到第三次迭代会因内存/资源不足报错

问题代码

#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void *full_path();
typedef struct th_ar
{
    int argc;
    char **argv;
};

int main(int argc, char **argv)
{
    // pthread_t thread_id;
    while (1)
    {
        sleep(5);
        struct th_ar ta = {.argc = argc, .argv = argv};
        // pthread_create(&thread_id, NULL, full_path, (void *)&ta);
        full_path((void *)&ta);
    }

    return 0;
}

void *full_path(void *args)
{
    struct th_ar *ta = (struct th_ar *)args;
    char *path = ta->argv[1];
    printf("path: %s\n", path);
    char *filename = "test.sh";
    char *full_path = (char *)malloc(strlen(path) + strlen(filename) + 2); // 此处计算的长度是正确的
    // char *full_path = (char *)malloc(strlen(path) + strlen(filename) + 4096);
    if (full_path == NULL)
        return (void *)1;
    strcpy(full_path, path);
    char last_char = path[strlen(path) - 1];
    if (last_char == '/')
    {
        // printf("%s\n", "It ends in /");
    }
    else
    {
        // printf("%s\n", "It does not end in /");
        // printf("%s\n", "Appending / at the end");
        full_path[strlen(full_path)] = '/';
    }
    strcat(full_path, filename);
    printf("full_path: %s\n", full_path);
    free(full_path);

    return (void *)0;
}

错误根源

核心问题是手动添加/后未补全字符串结束符\0:

  1. 当路径不以/结尾时,执行full_path[strlen(full_path)] = '/',这一步将/覆盖了原字符串的结束符\0,导致full_path变成了没有终止符的“无效字符串”。
  2. 后续调用strcat(full_path, filename)时,strcat会从full_path起始位置一直找\0,找不到就会越界访问内存。
  3. 第一次运行时,malloc分配的内存后恰好有\0,结果看似正常;第二次运行时,malloc复用了之前释放的内存,这块内存残留了上一次的test.sh内容,strcat就会从错误位置拼接,导致重复。
  4. 线程版本的资源不足问题,是因为创建线程后未调用pthread_join等待线程结束,线程资源无法回收,多次创建后耗尽系统线程资源。

解决方法

1. 修复字符串结束符问题

两种可选方案,确保字符串始终有\0:

  • 方案一:手动添加/后补终止符
    else
    {
        int len = strlen(full_path);
        full_path[len] = '/';
        full_path[len + 1] = '\0'; // 必须补终止符
    }
    
  • 方案二:用strcat添加/,自动处理终止符
    else
    {
        strcat(full_path, "/");
    }
    

2. 修复线程版本资源泄漏

每次创建线程后调用pthread_join等待线程结束,回收资源:

int main(int argc, char **argv)
{
    pthread_t thread_id;
    while (1)
    {
        sleep(5);
        struct th_ar ta = {.argc = argc, .argv = argv};
        pthread_create(&thread_id, NULL, full_path, (void *)&ta);
        pthread_join(thread_id, NULL); // 等待线程结束,回收资源
    }

    return 0;
}

额外优化建议

  • 减少重复调用strlen(path):提前计算一次路径长度,提升效率
    size_t path_len = strlen(path);
    char *full_path = (char *)malloc(path_len + strlen(filename) + 2);
    char last_char = path[path_len - 1];
    
  • 增加空路径判断:避免path[strlen(path)-1]访问越界
    size_t path_len = strlen(path);
    if (path_len == 0) {
        strcpy(full_path, "/");
    } else {
        // 原逻辑
    }
    

内容的提问来源于stack exchange,提问作者Eduard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 07:18:26