我正在研究一个学校项目的代码,我不能使用字符串
我在获取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();
}
原始文件包含更多行,但我将其缩小以找出错误 我做错了什么?
答案 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
来做这个吗?
这样做完全没有错 - 它肯定会让你欣赏使用string
和vector
的便利性。但是,也就是说,通过从每行数据中走一个指针(或几个指针)来解析每行数据中的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
范围内
现在你有了id
和hourlyPay
- 剩下的就是从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
仔细看看,如果您有其他问题,请告诉我。