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

C语言GTK串口读取程序:字符串分割后首字符丢失问题排查

串口接收字符串分割后首字符丢失问题分析

我正在使用C语言结合GTK API开发串口读取程序,遇到如下问题:从串口接收的原始字符串在分割为子字符串后,首字符丢失。相关代码如下:

while (1) {
    memset(buffer, 0, sizeof(buffer));
    int len = read(fd, buffer, sizeof(buffer)-1);
    if (len > 0) {
        buffer[len] = '\0';
        printf("Received: %s\n", buffer);


        char splittedBuffer[5][1024];

        int dataIndex = 0;
        int bufferIndex = 0;
        
        printf("len is %d\n", len);

        for (int i = 0; i < len; i++){
            if(buffer[i] == ';'){
                
                splittedBuffer[dataIndex][bufferIndex] = '\0';
                dataIndex ++;
                bufferIndex = 0;
                
            }else{
                splittedBuffer[dataIndex][bufferIndex] = buffer[i];
                bufferIndex++;

            }

            
        }

        printf("data0 : %s\n",splittedBuffer[0]);
        printf("data1 : %s\n",splittedBuffer[1]);
        printf("data2 : %s\n",splittedBuffer[2]);
        printf("data3 : %s\n",splittedBuffer[3]);
        printf("data4 : %s\n",splittedBuffer[4]);

        printf("after op: %s\n", buffer);
        
        
        
        
    } else if (len < 0) {
        perror("Error reading from serial port");
    }
}

程序运行输出如下:

Received: 23;10;20;30;40;

len is 16
data0 : 23
data1 : 10
data2 : 20
data3 : 30
data4 : 40
after op: 
3;10;20;30;40;

Received: 24;10;20;30;40;

len is 16
data0 : 24
data1 : 10
data2 : 20
data3 : 30
data4 : 40
after op: 
4;10;20;30;40;

问题原因分析

首字符丢失的核心原因是栈内存损坏,具体触发点如下:

  1. 栈上大数组的风险:你在栈上声明了char splittedBuffer[5][1024];,这会一次性分配5120字节的栈空间。栈的默认大小通常有限(多数系统为几MB),如果当前栈帧中还有其他变量,这么大的数组可能导致栈空间溢出,破坏相邻变量(比如buffer)的内存,最终导致buffer的首字节被意外覆盖。
  2. 未初始化的数组:splittedBuffer没有初始化,内存中存在随机垃圾值,虽然当前输出中分割后的子串显示正常,但垃圾值可能在栈内存中引发不可预测的越界覆盖。
  3. 潜在的越界写入风险:循环中未限制bufferIndex的最大值,如果串口传入的单字段长度超过1023,会直接越界写入splittedBuffer的内存区域,进一步破坏栈上其他变量。

修复建议

  1. 改用动态内存分配:避免在栈上分配大数组,改用malloc分配堆内存:
// 分配二维数组
char **splittedBuffer = malloc(5 * sizeof(char*));
for (int i = 0; i < 5; i++) {
    splittedBuffer[i] = malloc(1024 * sizeof(char));
    memset(splittedBuffer[i], 0, 1024); // 初始化内存为0
}

// 使用完成后释放内存
for (int i = 0; i < 5; i++) {
    free(splittedBuffer[i]);
}
free(splittedBuffer);
  1. 限制写入边界:在循环中添加bufferIndex的上限检查,防止越界:
else{
    if (bufferIndex < 1023) { // 预留一个位置给终止符'\0'
        splittedBuffer[dataIndex][bufferIndex] = buffer[i];
        bufferIndex++;
    }
}
  1. 补全最后字段的终止符:如果串口数据最后没有以;结尾,循环结束后手动给最后一个字段添加\0:
// 循环结束后处理最后一个未闭合的字段
if (dataIndex < 5 && bufferIndex > 0) {
    splittedBuffer[dataIndex][bufferIndex] = '\0';
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:15:56