获取函数 returns 无效值

get function returns invalid value

我正在为一个不能使用字符串的学校项目编写代码。
我在获取 hourlyPay 的值时遇到问题。
该程序的输出: 5 克里斯汀·金 4.94066e-324
虽然,该文件包含以下内容:
5 克里斯汀·金 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();
}

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

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

稍微修改一下,支持多行阅读打印,查看来源:

#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;
}

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

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);
}

我想通了。

#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改成了get,现在可以在一行中间读取,限制为20个字符。 感谢大家的关注和帮助。

所以..你真的想用一个普通的旧数组 Employee 和普通的旧字符数组和 cstring?

这样做绝对没有错——它肯定会让您欣赏使用 stringvector 的便利。但是,就是说,通过每行数据遍历一个指针(或几个指针)以解析每行数据中的 id, name & hourlyPay,可以获得大量有价值的学习。

整个解析过程的美中不足是不知道name中可能包含多少spaces(可能有none,一个,两个, 三, ...)。虽然,事情并不像看起来那么可怕。你知道你有一个开始数据行的 int 和一个结束的 double - int 之后和 double 之前的空白之间的所有内容都是你的 name.

这里的关键实际上是将每一行数据作为cstring读取到缓冲区(字符数组)中。然后,您可以使用标准工具 strtol 读取 id 并将指针前进到 id 中最后一个数字的 1-过去。然后您可以简单地逐个字符地向前迭代检查 if (isspace(*p)) 并继续前进直到找到非空白字符(或者您点击 nul-terminating字符在末尾)。一旦你找到你的非空白字符——你有一个指向 name.

开头的指针

现在您必须在另一端工作并备份,直到找到hourlyPay 之前的space。没那么难。您将需要 strlen (buf),但至少使用 masterFile.getline(..) 时,您无需通过用 nul-terminating[ 覆盖来从缓冲区末尾修剪 '\n' =102=]字符。只需将结束指针设置为 buf + len - 1,您就位于 hourlyPay 的最后一位。然后以类似的方式,备份 while (ep > sp && !isspace (*p)) 只是一个问题(你知道你的终点指针是否到达位于 name 开头的起点指针,解析失败)

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

现在您有了 idhourlyPay -- 剩下的就是 hourlyPay 开始备份 name 结束。您以类似的方式检查 isspace() 直到它不再为真,并且指向 name 末尾的指针仍然大于指向 name 开头的指针。现在您可以使用 strncpy 通过复制 p - sp + 1 个字符将 name 复制到 newName 的变量中(记住您正坐在最后一个带有 p 的字符上,所以您将需要添加 1 以获取名称中的所有字符。

把它放在一起并在下面提供内联注释,你可以做类似下面的事情(注意你原来的 class 和成员函数保持不变——只有 id, name & hourlyPay 的解析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';
}

(现在你明白为什么 string 和其他 C++ 工具让事情变得更好了吗?)

示例输入文件

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

$ cat dat/master10.txt
5 Christine Kim 30.00

例子Use/Output

$ ./bin/employeepay
5   Christine Kim  30

检查一下,如果您还有其他问题,请告诉我。