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

C++字符串分词代码陷入while循环无法退出,求排查解决

问题分析:while循环无法退出的原因及修复方案

问题描述

任务要求:找出字符数组s中所有包含数字的单词(单词以空格分隔,数组末尾始终带有一个句号)。使用测试输入qw6wqe esd9f 0gfgkj.时,代码中的while循环始终无法退出,调试发现token值有变化但循环停不下来。

原代码

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cctype>

using namespace std;
void Numbers(char s[], vector<pair<int, char>>& nums){
    char *token;
    int zero = 0;
    token = strtok(s, " ");
    for(int i = 0; i < strlen(token); i++){
        if(isdigit(token[i])){
            nums.emplace_back(zero, *token);
        }
    }
    while(token != NULL){
        zero ++;
        token = strtok(NULL, " ");
        for(int i = 0; i < strlen(token); i++){
            if(isdigit(token[i])){
                nums.emplace_back(zero, *token);
            }
        }
    }
}
int main() {
    vector<pair<int, char>> nums;
    char s[256];
    gets(s);
    Numbers(s, nums);
    cout << nums.size();
    for (int i = 0; i < nums.size(); i ++){
        cout << nums[i].first << " " << nums[i].second << endl;
    }
    return 0;
}

循环无法退出的核心原因

  1. strtok调用逻辑错误:原代码先进入while(token != NULL)循环,再调用strtok(NULL, " ")获取下一个token。当最后一个token处理完后,strtok返回NULL,但此时循环体仍会执行strlen(token)——传入NULL指针会触发未定义行为,导致程序崩溃或进入死循环。
  2. 循环条件与执行顺序不匹配:正确逻辑应该是先获取下一个token,再判断是否为NULL,而非先进入循环再获取。
  3. 额外问题:nums.emplace_back(zero, *token)存储的是单词首字符而非数字,不符合任务要求;gets函数存在缓冲区溢出风险。

修复后的代码

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <string>

using namespace std;

void Numbers(char s[], vector<pair<int, string>>& nums) {
    char *token;
    int wordIndex = 0;
    // 把空格和句号设为分隔符,自动处理末尾的句号
    token = strtok(s, " .");
    
    // 先获取token再判断,避免处理NULL指针
    while (token != NULL) {
        bool hasDigit = false;
        string digits;
        // 遍历单词,收集所有数字
        for (int i = 0; i < strlen(token); i++) {
            if (isdigit(token[i])) {
                hasDigit = true;
                digits += token[i];
            }
        }
        // 若单词含数字,记录索引和对应数字
        if (hasDigit) {
            nums.emplace_back(wordIndex, digits);
        }
        wordIndex++;
        token = strtok(NULL, " .");
    }
}

int main() {
    vector<pair<int, string>> nums;
    char s[256];
    // 替换gets为安全的fgets,避免缓冲区溢出
    fgets(s, sizeof(s), stdin);
    // 移除fgets读取的换行符(若存在)
    size_t len = strlen(s);
    if (len > 0 && s[len-1] == '\n') {
        s[len-1] = '\0';
    }
    
    Numbers(s, nums);
    cout << "含数字的单词数量:" << nums.size() << endl;
    for (auto& item : nums) {
        cout << "单词索引:" << item.first << ",包含的数字:" << item.second << endl;
    }
    return 0;
}

修复说明

  • 修正循环逻辑:调整为先获取token→判断是否为NULL→处理token的顺序,彻底避免死循环。
  • 优化分隔符:用" ."作为分隔符,自动过滤末尾的句号,无需额外处理。
  • 修正数据存储:记录单词索引和其中所有数字,符合任务要求。
  • 替换不安全函数:用fgets替代gets,并处理换行符,消除缓冲区溢出风险。

内容的提问来源于stack exchange,提问作者Михайло Горак

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 11:05:20