问题描述
我一直在尝试将文本文件读入链接列表。我面临的唯一问题是它不会读取所有条目。
我的学生课:
class Student // Student class which hold student data
{
private:
char Name[15];
char Roll_no[8];
int Serial_no,FSC_marks,Entry_test_marks;
public:
void Print() // Print student data
{
cout << "\n" << Serial_no << "\t"<< Roll_no << " " << Name << "\t" << FSC_marks << "\t\t" << Entry_test_marks << endl;
}
void Read(fstream &infile)
{
infile >> Serial_no;
infile >> Roll_no ;
infile.get(Name,15);
infile >> FSC_marks >> Entry_test_marks;
}
}
链表类
class LinkList // Linked List
{
struct Node // structure for Node containing Object of Student class
{
Student info;
Node* link;
};
Node* head;
public:
Linklist() // default constructor
{
head = NULL;
}
};
打印功能如下:
void LinkList::print() // Prints List of Students
{
Node* temp = head;
if(temp != NULL)
{
while(temp != NULL)
{
temp->info.Print();
temp = temp->link;
}
cout<<endl;
}
}
这是阅读功能:
void LinkList::Readfromfile()
{
fstream File;
File.open("Lab_15.txt",ios::in);
File.seekg(40);
while(File)
{
Node* newnode = new Node();
newnode->info.Read(File);
newnode->link = NULL;
if(head == NULL)
{
head = newnode;
}
else
{
Node* temp = head;
while(temp->link != NULL)
{
temp = temp->link;
}
temp->link = newnode;
}
}
}
这里是文本文件的样子:
Serial_No Roll_No Name F.Sc Entry_Test
1 19I-0777 Jame#s moriarty777 70
2 19I-0789 Sherlock 734 80
3 19I-0860 Holmes 843 88
4 19I-0884 Dave Bautista 732 54
6 20I-1003 Barry Allen# 712 32
7 20I-1004 Clark kent 632 15
8 20I-1015 Adam 658 67
9 20I-1034 Ahmad hussain 734 55
10 20I-1041 Bill ga#tes 811 98
11 20I-1054 Trump 888 45
13 20I-1057 Donald duck 576 67
14 20I-1903 Faiza#n Shahid 789 34
15 20I-1904 Umair Shahid 567 55
16 20I-1909 Abdullah 123 67
17 20I-1915 Ali 300 45
在原始文本文件中,我有大约 20 个条目,但我的代码只读取了大约 13 个。我在这里做错了什么?
解决方法
除了您没有提供析构函数等导致内存泄漏的事实,并且您没有使用可以节省您一些时间并且可能自己工作的 STL,我认为算法中没有明显的错误.
这里是我会搜索以发现错误的地方:
- 为什么要跳过文件开头的 40 个字符 (
File.seekg(40);
)? - 您将运算符
>>
与get
函数混合使用。我因此产生了错误。 - 检查文件是否确实正确,并且您没有输入错误。
另外,正如其他人所指出的那样,当您插入新节点而不是再次遍历列表时,重新分配头部可能会更快。
,问题在于您的 LinkList
构造函数的名称。
您将(假定的)构造函数命名为 Linklist
而不是 LinkList
,这使得它不是构造函数,从而导致 head
指针未初始化。
除此之外,您可能仍然无法正确读取文件。完成后不要忘记关闭 File
。
编辑 1:回答您的first comment
确保您遵循有关 fstream
的一些参考,例如:
-
istream::get
方法(fstream
继承istream
)读取直到达到n - 1
个字符,或者直到找到分隔符(其中不包括分隔符本身)在输出参数中)。如果您不提供分隔符(例如仅使用 2 个参数调用方法:char*
和要读取的字符数,就像您为Name
所做的那样),则它默认为换行('\n'
)。这意味着当您调用infile.get(Name,15);
时,它实际上读取 14 个字符(并且我们不希望名称中有任何新行,因此这意味着它将始终从文本文件中读取 14 个字符),而不是 15 个字符想。因此,您需要将Name
声明为 16 个字符并调用infile.get(Name,16);
。这样,您将读取 15 个字符而不是 14 个。空字符会自动附加到输入序列的末尾(即在 index 15 处,因为我们知道 15 个字符将是阅读),因此您无需担心。因此,您自己从名称中删除'#'
字符意味着您会自动使每个名称长度为 14 个字符,而不是 15 个字符,这就解释了为什么infile.get(Name,15);
在这种情况下会成功。 - 另一件需要注意的事情是,您可能应该忽略列
Roll_no
和Name
之间的列分隔符。此字符可能是文本文件中的空格或制表符 ('\t'
)。使用istream::ignore
方法(就在读取Name
之前)忽略单个字符,如下调用:infile.ignore();
。 - 注意您的
skipg
调用和文件编码。你确定是 40 个字符?对我来说是 39,这真的取决于你的文件的内容。您可以尝试使用istream::getline
、getline
或ignore
作为忽略第一行的替代方法。
总结编辑 1:
- 将每个
Student
的私有属性更改为:
private:
char Name[16]; //Changed to 16 characters long,instead of 15.
char Roll_no[9]; //Changed to 9 characters long,instead of 8.
int Serial_no,FSC_marks,Entry_test_marks;
- 将您对文件中每个
Student
的阅读更改为:
void Read(fstream& infile)
{
infile >> Serial_no;
infile >> Roll_no; //'\n' is automatically appended.
infile.ignore(); //Added this line to ignore the column separator between the number Roll_no and the Name.
infile.get(Name,16); //Changed to read 15 characters instead of 14. '\n' is automatically appended.
infile >> FSC_marks >> Entry_test_marks;
}
- 尝试使用
skipg
的参数(或自己计算字符数)。