strtok如何正确提取字符串元素并对变量赋值

现在写了个单片机倒计时小程序,时间传送格式为12-34-56,对应时分秒。但是串口助手那边返回来是正常d12-34-56,单片机数码管上面就只是从54秒倒计时,这是为什么?其他模块的功能没有问题。如果直接对hou、min、sec赋值都是正常倒计时的,就是通过串口传输不行。屎山就屎山吧,能跑就行。希望能够得到解答,谢谢大家。
代码如下

void uart() interrupt 4 //串口通信中断函数(先不要动)
{    
    RI = 0;            //清除接收中断标志位
    rec_data[12]=SBUF;    //存储接收到的数据
    SBUF=rec_data[12];    //将接收到的数据放入到发送寄存器,检查是否正常接收
    while(!TI);        //等待发送数据完成
    TI=0;            //清除发送完成标志位
}

void Select()//提取出时分秒
{    
    char str[8] = rec_data; //要分割的字符串
        const char del[2] = "-"; //分隔符
        char *p; //用于存储子串首地址

        p = strtok(str, del); //第一次调用strtok,传入要分割的字符串和分隔符
    hou = atoi(p); //将第一个子串转换为整数并存入变量a中
        p = strtok(NULL, del); //再次调用strtok,传入NULL和分隔符,继续切割字符串
        min = atoi(p); //将第二个子串转换为整数并存入中
        p = strtok(NULL, del); //再次调用strtok,传入NULL和分隔符,继续切割字符串
        sec = atoi(p); //将第三个子串转换为整数并存入变量c中*/
}

void main()
{    
    UartInit(0XFA);
    Timer0Init();
    Select();
    hou = u[0];
    min = u[1];
    sec = u[2];
                
        
    while(1)
    {
        datapros();
        DigDisplay();
    }
    
        
}

参考GPT和自己的思路:

根据代码中的描述,问题可能出在以下几个方面:

  1. 对于传输格式的不同,需要对接收到的字符串进行处理后才能正确提取出时分秒的数值。当前代码中使用了 strtok 函数来分割字符串,但是没有考虑串口助手返回数据中可能存在的前缀,导致提取的字符串中包含了不可转换为数字的字符,从而出现倒计时异常的情况。

  2. 在 Select 函数中,分割的字符串存放在一个名为 str 的数组中,但是没有考虑这个数组的长度是否足够容纳接收到的数据。如果接收到的数据超出了数组的长度,可能会导致程序出现异常。

针对上述问题,可以采取以下措施来解决:

  1. 在接收到字符串数据后,先对其进行处理,将前缀字符去除,并将剩余部分存放在一个新的字符串变量中。可以使用 strchr 函数查找字符串中第一个出现的指定字符,并返回其指针位置。代码片段:
char* p = strchr(rec_data, 'd');
if (p != NULL) {
    strncpy(new_data, p+1, sizeof(new_data)); // 将字符串复制到新的变量中
}
  1. 在使用 strtok 函数之前,先检查存放字符串的数组是否足够长,可以使用 sprintf 函数将接收到的数据格式化输出到字符串中,然后计算其长度,判断是否超过数组长度的限制。如果超过,可以选择忽略多余的数据或者进行数据的截取。代码片段:
char str[8]; // 分割的字符串
char tmp[15]; // 存放格式化后的字符串
sprintf(tmp, "%02d-%02d-%02d", hou, min, sec); // 格式化输出时间
if (strlen(tmp) > sizeof(str)) {
    strncpy(str, tmp, sizeof(str)-1); // 复制到分割字符串中,只保留前面的部分
    str[sizeof(str)-1] = '\0'; // 添加结束符
} else {
    strcpy(str, tmp);
}

以上代码片段仅供参考,具体实现方式可能需要根据项目的具体情况进行调整。