get函数返回无效值

时间:2018-05-05 04:22:16

标签: c++ getline

我正在研究一个学校项目的代码,我不能使用字符串 我在获取hourlyPay的价值方面遇到了问题 该程序的输出: 5 Christine Kim 4.94066e-324
虽然,该文件包含以下内容:
5 Christine Kim 30.00

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>

using namespace std;

//Class decleration
class Employee 
{
  private:
    int id;            //Employee ID.
    char name[21];        //Employee name.
    double hourlyPay;   //Pay per hour.

  public:
    Employee(int initId=0, char [] =0, double initHourlyPay=0.0);  //Constructor.

    bool set(int newId, char [], double newHourlyPay);
    int getId() { return id; }
    const char * getName() { return name;}
    double getHourlyPay() { return hourlyPay;}


};

Employee::Employee( int initId, char initName[], double initHourlyPay)
{
  bool status = set( initId, initName, initHourlyPay);

  if ( !status )
  {
    id = 0;
    strcpy(name, "");
    hourlyPay = 0.0;
  }
}

bool Employee::set( int newId, char newName[], double newHourlyPay)
{
  bool status = false;

  if ( newId > 0)
  {
    status = true;
    id = newId;
    strcpy(name, newName);
    hourlyPay = newHourlyPay;
  }
  return status;
}

const int MAX_SIZE = 100;


int main()
{

    int id;             //Employee ID.
    char newName[21];

    double hourlyPay;   //Pay per hour.


    Employee list[15];  //Array to store


    ifstream masterFile;        //Opens master file.

    masterFile.open("master10.txt");

    int count = 0;
    if (masterFile)
    {
        for (count; count < 2; count++)
        {
            masterFile >> id;
            masterFile.ignore();
            masterFile.getline(newName, 21);
            masterFile >> hourlyPay;
            list[count].set(id, newName, hourlyPay);
        }
    }

    masterFile.close(); //Close master file.

    cout << list[0].getId() << "   " << list[0].getName() << "  " << list[0].getHourlyPay();
}

原始文件包含更多行,但我将其缩小以找出错误 我做错了什么?

4 个答案:

答案 0 :(得分:0)

在行中包含带空格的名称不是一个好主意,如果你坚持这样做,我想我们可以阅读该行并拆分名称和hourlyPlay。更好的方法是在名称中不包含空格,但使用_之类的字符,并在阅读后用空格替换字符,您可以简单地使用>>来读取每个字段

我修改了一点以支持多行阅读&amp;打印,检查来源:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
#include <vector>

using namespace std;

//Class decleration
class Employee
{
private:
    int id;            //Employee ID.
    char name[21];        //Employee name.
    double hourlyPay;   //Pay per hour.

public:
    Employee(int initId = 0, const char* = 0, double initHourlyPay = 0.0);  //Constructor.

    bool set(int newId, const char*, double newHourlyPay);
    int getId() { return id; }
    const char * getName() { return name; }
    double getHourlyPay() { return hourlyPay; }


};

Employee::Employee(int initId, const char* initName, double initHourlyPay)
{
    bool status = set(initId, initName, initHourlyPay);

    if (!status)
    {
        id = 0;
        strcpy(name, "");
        hourlyPay = 0.0;
    }
}

bool Employee::set(int newId, const char* newName, double newHourlyPay)
{
    bool status = false;

    if (newId > 0)
    {
        status = true;
        id = newId;
        strcpy(name, newName);
        hourlyPay = newHourlyPay;
    }
    return status;
}

int main()
{
    int id;                 //Employee ID.
    double hourlyPay;       //Pay per hour.
    vector<Employee> list;  //Array to store
    ifstream masterFile;    //Opens master file.
    char line[256];

    masterFile.open("master10.txt");
    if (masterFile)
    {
        while (!masterFile.eof())
        {
            masterFile >> id;
            masterFile.getline(line, sizeof(line));
            char* last_word = strrchr(line, ' ');
            line[last_word - line] = 0;
            hourlyPay = atof(last_word + 1);
            list.push_back(Employee(id, line, hourlyPay));
        }
    }

    //Close master file.
    masterFile.close();
    for (size_t i = 0; i < list.size(); ++i)
        cout << list[i].getId() << "   " << list[i].getName() << "  " << list[i].getHourlyPay() << endl;
}

答案 1 :(得分:0)

文件中的数据未正确输入代码中的变量。这是一个自我解释的解决方案。

for (count; count < 1; count++)
{
    char secondname[11];
    masterFile >> id;
    masterFile.ignore();
    masterFile >> newName;
    masterFile >> secondname;
    masterFile >> hourlyPay;

    strcat(newName, " ");
    strcat(newName, secondname);

    list[count].set(id, newName, hourlyPay);
}

答案 2 :(得分:0)

我已经弄清楚了。

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>

using namespace std;

//Class decleration
class Employee 
{
  private:
    int id;            //Employee ID.
    char name[21];        //Employee name.
    double hourlyPay;   //Pay per hour.

  public:
    Employee(int initId=0, char [] =0, double initHourlyPay=0.0);  //Constructor.

    bool set(int newId, char [], double newHourlyPay);
    int getId() { return id; }
    const char * getName() { return name;}
    double getHourlyPay() { return hourlyPay;}


};

Employee::Employee( int initId, char initName[], double initHourlyPay)
{
  bool status = set( initId, initName, initHourlyPay);

  if ( !status )
  {
    id = 0;
    strcpy(name, "");
    hourlyPay = 0.0;
  }
}

bool Employee::set( int newId, char newName[], double newHourlyPay)
{
  bool status = false;

  if ( newId > 0)
  {
    status = true;
    id = newId;
    strcpy(name, newName);
    hourlyPay = newHourlyPay;
  }
  return status;
}

const int MAX_SIZE = 100;


int main()
{

    int id;             //Employee ID.
    char newName[21];

    double hourlyPay;   //Pay per hour.


    Employee list[15];  //Array to store


    ifstream masterFile;        //Opens master file.

    masterFile.open("master10.txt");

    int count = 0;
    if (masterFile)
    {
        for (count; count < 2; count++)
        {
            masterFile >> id;
            masterFile.ignore();
            masterFile.get(newName, 21);
            masterFile >> hourlyPay;
            list[count].set(id, newName, hourlyPay);


        }

    }

    masterFile.close(); //Close master file.

    cout << list[0].getId() << "   " << list[0].getName() << "  " << list[0].getHourlyPay();
}

我只更改了getline,现在它可以在一行中间读取,限制为20个字符。 我感谢大家的关注和帮助。

答案 3 :(得分:0)

那么..你真的想用一个普通的Employee数组和普通的旧字符数组cstring来做这个吗?

这样做完全没有错 - 它肯定会让你欣赏使用stringvector的便利性。但是,也就是说,通过从每行数据中走一个指针(或几个指针)来解析每行数据中的id, name & hourlyPay,可以获得大量有价值的学习。

整个解析过程中的软膏不知道spaces中可能包含多少name(它可能没有,一,二,三...... )。虽然,事情并不像他们可能出现的那样可怕。您知道有int开始数据行,最后有double - int之后和double之前的空格之间的所有内容都是你的name

这里的关键是将每行数据作为cstring读入缓冲区(字符数组)。然后,您可以使用标准工具strtol来阅读id并将指针前进到id中的最后一位数字1。然后,您可以简单地逐个字符地逐步检查if (isspace(*p))并继续前进,直到找到非空白字符(或者您点击 nul-terminatedating 字符结束)。找到非空白字符后 - 将指针设置为name的开头。

现在您必须在另一端工作并备份,直到找到space之前的hourlyPay。没那么难。您将需要strlen (buf),但至少使用masterFile.getline(..),您可以通过使用 nul-terminatedating '\n'的需要。 >性格。只需将结束指针设置为buf + len - 1,您就坐在hourlyPay的最后一位数字上。然后以类似的方式,只需要备份while (ep > sp && !isspace (*p))(你知道你的结束指针是否已经到达你的起始指针 - name解析失败了)

现在请记住,在hourlyPay开头之前你是1个字符,所以当你使用hourlyPay转换strtod时,你必须记住使用p + 1作为cstring-segment的开头来转换hourlyPay。与任何strtoX转换一样,您有两个主要测试(1),在转换之后,起始指针不等于endptr参数,表示数字实际上已转换为数字和(2)转换期间未设置errno - 表示实际转换失败。 (当转换为比转换更小的类型时 - 例如使用int转换为strtol - 在分配给您的值之前,您必须检查转换后的值是否在int范围内

现在你有了idhourlyPay - 剩下的就是从hourlyPay的开头到{{1}的结尾备份 }}。你这样做会以同样的方式检查name,直到它不再成立,并且指向isspace()末尾的指针仍然大于指向name开头的指针。现在,您可以使用name通过复制strncpy字符将name复制到newName的变量中(请记住,您正坐在p - sp + 1的最后一个字符上您需要添加p才能获取名称中的所有字符。

完全放下并在下面提供注释,您可以执行以下操作(注意原始的1和成员函数保持不变 - 只有class的解析id, name & hourlyPay 1}}受到了极大的影响)一如既往 - 关键是验证每一步 - 然后您就可以对正在处理的数据充满信心。

main()

(现在你明白为什么#include <iostream> #include <iomanip> #include <fstream> #include <cstring> #include <cctype> #include <limits> #define MAXLIST 16 /* if you need constants, define one (or more) */ #define MAXNM 64 #define MAXBUF 1024 #define FNAME "dat/master10.txt" using namespace std; //Class decleration class Employee { private: int id; //Employee ID. char name[MAXNM]; //Employee name. double hourlyPay; //Pay per hour. public: Employee (int initId=0, char [] =0, double initHourlyPay=0.0); bool set (int newId, char [], double newHourlyPay); int getId() { return id; } const char *getName() { return name;} double getHourlyPay() { return hourlyPay;} }; Employee::Employee (int initId, char initName[], double initHourlyPay) { bool status = set(initId, initName, initHourlyPay); if (!status) { id = 0; strcpy(name, ""); hourlyPay = 0.0; } } bool Employee::set (int newId, char newName[], double newHourlyPay) { bool status = false; if (newId > 0) { status = true; id = newId; strcpy(name, newName); hourlyPay = newHourlyPay; } return status; } int main (void) { int id, //Employee ID. count = 0; long tmp; /* tmp for strtol conversion */ char newName[MAXNM] = "", buf[MAXBUF] = ""; /* line buffer */ double hourlyPay; //Pay per hour. Employee list[MAXLIST]; //Array to store ifstream masterFile (FNAME); //Opens master file. if (!masterFile.is_open()) { /* validate file open for reading */ cerr << "error: file open failed '" << FNAME << "'\n"; return 1; } /* read each line in masterFile into buf */ while (count < MAXLIST && masterFile.getline (buf, sizeof buf)) { size_t len = strlen (buf); /* get length */ char *sp = buf, /* start pointer */ *p = buf + len - 1, /* working pointer */ *ep = NULL; /* end pointer for strtod conversion */ /* parse and convert id, leaving sp 1-past last digit */ errno = 0; /* zero errno before strtol conversion */ tmp = strtol (buf, &sp, 0); /* store conversion in tmp */ if (buf == sp) { /* validate characters were converted */ cerr << "error: no digits converted in id.\n"; return 1; } if (errno != 0) { /* validation errno not set */ cerr << "error: failed converstion for id.\n"; return 1; } /* validate tmp within range of integer */ if (tmp < numeric_limits<int>::min() || numeric_limits<int>::max() < tmp) { cerr << "error: id not within integer range.\n"; return 1; } id = (int)tmp; /* assign tmp to id */ /* advance sp to 1st char in name */ while (*sp && isspace (*sp)) sp++; /* parse hourlyPay */ /* work backward with p until space before hourlyPay found * always validate p > sp so you don't back up beyond the start of * name (or the beginning of buf). */ while (p > sp && !isspace (*p)) p--; if (p > sp && !isdigit(*(p + 1))) { /* validate next char is digit */ cerr << "error: failed to parse hourlyPay.\n"; return 1; } errno = 0; /* zero errno before strtol conversion */ hourlyPay = strtod (p+1, &ep); /* convert hourlyPay to double */ if (p + 1 == ep) { /* validate characters were converted */ cerr << "error: no digits converted in hourlyPay.\n"; return 1; } if (errno != 0) { /* validation errno not set */ cerr << "error: failed converstion for hourlyPay.\n"; return 1; } /* continue working backwards to end of name */ while (p > sp && isspace (*p)) p--; if (p <= sp) { /* validate chars between sp & p */ cerr << "error: failed to find end of name.\n"; return 1; } len = p - sp + 1; /* get number of chars in name */ if (len > MAXNM - 1) { /* validate it will fit in newName */ cerr << "error: name exceeds" << len << "characters.\n"; return 1; } strncpy (newName, sp, len); /* copy name to newName */ /* set values in list[count], on success, increment count */ if (list[count].set (id, newName, hourlyPay)) count++; } masterFile.close(); //Close master file. /* outoput all employee id and hourlyPay information */ for (int i = 0; i < count; i++) cout << list[i].getId() << " " << list[i].getName() << " " << list[i].getHourlyPay() << '\n'; } 和其他C ++工具让事情变得更好了?)

示例输入文件

您发布的唯一数据用作输入文件,例如

string

示例使用/输出

$ cat dat/master10.txt
5 Christine Kim 30.00

仔细看看,如果您有其他问题,请告诉我。