首页 > 解决方案 > 程序吃掉一行的第一个字母

问题描述

所以我正在练习使用 C++ 处理文件。我创建了一个简单的程序,它从 加载学生的姓名、索引号、出生日期和成绩STUDENT.txt,计算学生的平均成绩,然后以下面的表格将其全部写到不同的文件中。

这一切都像一个魅力,除了一件事:它吃掉了每一行的第一个字母。示例:我有一个 STUDENT.txt 文件,如下所示:

Alice Cooper
225883
21/6/1986
6,6,8,9,10
Zakk Wylde
27568
14/5/1978
6,6,6,6,6

因此,第一个学生 Cooper 将被正确处理,但文件中的其他所有人都不会。他们将被写成'akk Wylde'......所以除了名字之外的一切都可以。我希望有人能告诉我到底发生了什么,我猜它正在吃掉一个 '\n' 和另一个字符,但我无法通过调试找到它。

// Student_datoteka.cpp : 定义控制台应用程序的入口点。//

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>

std::string toString(int day, int month, int year) {
    std::string d, m, g, ret;
    d = std::to_string(day);
    m = std::to_string(month);
    g = std::to_string(year);
    ret += d;
    ret += "/";
    ret += m;
    ret += "/";
    ret += g;

    return ret;
}


int main()
{
    std::fstream load("STUDENTI.txt", std::ios::in);
    std::ofstream write("IZVJESTAJ.txt");
    write << std::setw(30) << std::left << "Student"
          << std::setw(10) << "Indeks" 
          << std::setw(20) << "Datum rodjenja"
          << std::setw(10) << "Prosjek" << std::endl;
    write << std::setw(30) << std::left << "-------"
          << std::setw(10) << "------" 
          << std::setw(20) << "--------------"
          << std::setw(10) << "-------" << std::endl;
    if (!write)
        std::cout << "ERROR!";
    std::string name;
    int indeks(0), day(0), month(0), year(0);
    char sign(0), sign2(0);
    int grades[30];
    double average(0);
    while (std::getline(load, name)) {
        if (load.eof()) break;
        load >> indeks;
        load >> day >> sign >> mjesec >> sign2 >> year;
        int i(0);
        while (load >> grades[i]) {
            load >> sign;
            average += grades[i];
            i++;
        }

        average /= double(i);
        std::string datum = toString(day, month, year);
        write << std::setw(30) << std::left << name
              << std::setw(10) << indeks
              << std::setw(20) << datum
              << std::setw(10) << std::setprecision(2) 
              << average<< std::endl;
        average = 0;
        if (load.eof()) break;

        load.clear();
    }  
    return 0;
}

这是输出: http: //prntscr.com/jvm3jn

标签: c++file

解决方案


我对您的代码做了一些小的改进,所以如果您不喜欢,请只使用工作部分。请注意,我的代码可以进一步改进和推广,但我将把它留给你。

希望你喜欢我的解决方案:

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

typedef struct Student
{
    std::string name;
    int index_no;
    int day_of_birth;
    int month_of_birth;
    int year_of_birth;
    std::vector<int> grades;
    double avg_grade;
} Student;

std::string date_to_string(int day, int month, int year)
{
    std::string d, m, g, ret;
    d = std::to_string(day);
    m = std::to_string(month);
    g = std::to_string(year);
    ret += d;
    ret += "/";
    ret += m;
    ret += "/";
    ret += g;

    return ret;
}

void get_date_from_str(int& day, int& month, int& year, std::string const& str)
{
    std::stringstream ss(str);
    ss >> day;
    ss.ignore(1);
    ss >> month;
    ss.ignore(1);
    ss >> year;
}

void get_numbers_from_str(std::vector<int>& vec, std::string  const& str)
{
    std::stringstream ss(str);
    int i;
    while (ss >> i)
    {
        vec.push_back(i);
        ss.ignore(1);
    }
}

double calculate_avg(std::vector<int> const& vec)
{
    int sum = 0;
    for (auto item : vec)
    {
        sum += item;
    }
    return (double) sum / vec.size();
}

int main()
{
    std::ifstream students_file("students.txt");
    std::ofstream report_file("report.txt");

    if (students_file.is_open() && report_file.is_open())
    {
        report_file << std::setw(30) << std::left << "Student"
                    << std::setw(10) << "Indeks"
                    << std::setw(20) << "Datum rodjenja"
                    << std::setw(10) << "Prosjek" << std::endl;
        report_file << std::setw(30) << std::left << "-------"
                    << std::setw(10) << "------"
                    << std::setw(20) << "--------------"
                    << std::setw(10) << "-------" << std::endl;

        std::vector<Student> students;
        std::string name;

        while (std::getline(students_file, name))
        {
            std::string index_no;
            std::string date_of_birth;
            std::string grades;

            Student student;
            student.name = name;

            std::getline(students_file, index_no);
            std::stringstream(index_no) >> student.index_no;

            std::getline(students_file, date_of_birth);
            std::getline(students_file, grades);

            get_date_from_str(student.day_of_birth, student.month_of_birth, student.year_of_birth, date_of_birth);
            get_numbers_from_str(student.grades, grades);

            student.avg_grade = calculate_avg(student.grades);
            students.push_back(student);
        }

        for (auto student : students)
        {
             report_file << std::setw(30) << std::left << student.name
                         << std::setw(10) << student.index_no
                         << std::setw(20) << date_to_string(student.day_of_birth, student.month_of_birth, student.year_of_birth)
                         << std::setw(10) << std::setprecision(2)
                         << student.avg_grade << std::endl;
        }
    }
    else
    {
        std::cout << "Unable to open one of the files!" << std::endl;
    }

    return 0;
}

首先,我认为你已经把你的代码复杂化了,阅读和理解它,而你有一些 C++ 特性可以通过符号和解析日期和等级来简化这部分。

我还创建了struct Student一些代码并将其拆分为函数。

而且,关于您的解决方案。正如评论中已经提到的那样,错误在于以下几行:

while (load >> grades[i])
{
    load >> sign;
    average += grades[i];
    i++;
}

你比你需要的多“吃”了一个角色。而这个字符就是第二个学生名字的第一个字符。因此,如果您将代码更改为以下代码,您将看到我在说什么:

while (load >> grades[i])
{
    if (i != 4) // just a temporary solution, since the first student has 5 grades
        load >> sign;
    average += grades[i];
    i++;
}

推荐阅读