对字符串进行标记,识别char时出错

时间:2012-02-12 17:57:58

标签: c++

我在为C ++上课时遇到了一些麻烦。我遇到的具体问题涉及从包含一系列5到6个等级的文件中读取行。每个学生的成绩一起显示在学生姓名和身份证号码后面的一行中。这里的挑战是等级之间可以有不同数量的空格,如果只有5个等级,则需要生成错误消息以进行筛选,但程序将继续运行并平均5个等级。输入示例:23 46 68 85 98

我很容易得到学生姓名和身份证,但数字串给我带来了麻烦。我的计划是getline然后将字符串标记化并将每个标记分配给数组中的单元格。这适用于6个等级,但是当只有5个等级时,它会将垃圾分配给第六个等级。

以下是与此部分相关的代码段:

fin.getline(gradeList, 200);

grade = strtok (gradeList, " ");


while (grade != '\0')
{         
      gradeArr[cycler] = atoi(grade);
      grade = strtok(NULL, " ");
      cycler++;
}

我尝试在将每个令牌转换为int之前对每个令牌执行isdigit检查,并为未通过isdigit检查的任何令牌写入0,但这根本不起作用。当只有5个等级存在时,它似乎从下一行拉出名称,然后当它在atoi的时候,它将它改变为一个巨大的数字。

我认为当程序执行getline时,它只会抓住该行,直到它看到endline终结符。这不是发生了什么事吗?

2 个答案:

答案 0 :(得分:3)

废弃C废话并使用真正的C ++:

#include <string>
#include <sstream>
#include <fstream>
#include <vector>

// ...

std::vector<int> grades;

std::string line;

while (std::getline(fin, line))
{
    std::istringstream iss(line);
    int grade;

    while (iss >> grade)
    {
        grades.push_back(grade);
    }
}

使用istream-iterators和back-inserters,这是一个更紧凑和更优雅的方法:

#include <iterator>
#include <algorithm>
// other headers as before

std::vector<int> grades;

for (std::string line; std::getline(fin, line); )
{
    std::istringstream iss(line);
    std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(),
              std::back_inserter(grades));
}

重点是来自流的格式化令牌提取(>>)已经完全符合您的要求,并且它包含令牌化和解析为整数。

istream_iterator封装了令牌提取,并允许您将流处理为好像它已经是一系列已解析的令牌。然后,copy算法只是将此序列复制到一个向量中,将其插入容器的末尾。

答案 1 :(得分:0)

如果您使用strtolstrtod,它会返回指向您刚刚处理完的内容的指针,因此您可以从那里继续。无需标记化:)

但听起来你的问题是你正在读错线。在开始解析之前打印出gradeList变量。

你应该得到这样的东西:

fin.getline(grade_text, 200);
const char* grade = grade_text;
const char* next_grade;

double grade_sum = 0;
for( int grade_count = 0; grades[grade_count] = strtol(grade, &next_grade, 10), next_grade > grade; ++grade_count )
    grade_sum += grades[grade_count];
double mean_grade = grade_sum / grade_count;