#include <iostream>
#include <stdio.h>
using namespace std;
struct Table{
char fullname [100];
int group;
int firstMarks[5];
int secondMarks[5];
};
void ReadTable (Table *&data, int N);
void ShowTable (Table *data, int N);
int main() {
int N = 5;
Table *data = new Table[N]{
{},
{},
{},
{},
{}
};
ReadTable(data, N);
ShowTable(data, N);
}
void ReadTable (Table *&data, int N){
FILE *fl = fopen("table.txt","r");
if (!fl) {
cout << "Помилка";
exit(1);
}
for (int i = 0; i < N; i ) {
for (int j = 0; j < N; j ) {
fscanf(fl, "%[^|] | %d | %d %d %d %d %d | %d %d %d %d %d ", &data[i].fullname, &data[i].group,
&data[i].firstMarks[j], &data[i].firstMarks[j], &data[i].firstMarks[j], &data[i].firstMarks[j], &data[i].firstMarks[j],
&data[i].secondMarks[j], &data[i].secondMarks[j], &data[i].secondMarks[j], &data[i].secondMarks[j], &data[i].secondMarks[j]);
}
fscanf(fl, "\n");
}
fclose(fl);
}
void ShowTable (Table *data, int N){
for (int i = 0; i < N; i ) {
cout << data[i].fullname << " ";
cout << " | ";
cout << data[i].group << " ";
cout << " | ";
for (int j = 0; j < N; j ) {
cout << data[i].firstMarks[j] << " ";
}
cout << " | ";
for (int j = 0; j < N; j ) {
cout << data[i].secondMarks[j] << " ";
}
cout << endl;
}
}
file table.txt:
Новикова Аделина Максимовна | 1151 | 5 2 3 1 2 | 1 2 1 3 2
Воронина Анна Леоновна | 2151 | 2 4 3 2 1 | 5 4 5 5 4
Медведева Елена Михайловна | 4452 | 4 2 1 3 4 | 2 4 5 2 1
Зайцев Пётр Миронович | 1148 | 2 3 4 5 1 | 5 2 1 5 5
Кочергин Алексей Семёнович | 3252 | 4 4 3 4 5 | 2 1 3 4 2
Console output:
Кочергин Алексей Семёнович | 3252 | 2 1 4 1 5 | 2 4 1 5 2
| 0 | 0 0 0 0 0 | 0 0 0 0 0
| 0 | 0 0 0 0 0 | 0 0 0 0 0
| 0 | 0 0 0 0 0 | 0 0 0 0 0
| 0 | 0 0 0 0 0 | 0 0 0 0 0
Hi all, there is a table, one row of the table corresponds to one student and contains the following information: student's name, group number, exam grades for the first semester, exam grades for the second semester.
How do I read the information from the file into my structure variables? My attempts are unsuccessful, hope for your help!
CodePudding user response:
C is an old, mutating language. Thus, it is hard for new users to discern, which language features belong to which state of mutation of the language.
First, you can do everything with <iostream>
. Mixing in <stdio>
just complicates matters, IMHO.
Second, you declare your Table
struct (naming! it is one RECORD in a table, only) in C style (very old mutation) and you could make good use of newer C features. Assuming, of course, you do not sit on an ancient tool chain like BorlandC 6.0 or something (which would be your first mistake).
Now, with <iostream>
, solving such tasks is always following the same pattern, repeatedly:
- For input from a stream to a type, write yourself an overloaded
operator>>
. - For output to a stream for a type, write yourself an overloaded
operator<<
.
A further complication of your task is, that you use kyrillic names (utf8 file encoding?!). This can be a pitfall, but sometimes, as long as you do not try to dissect the name string, you get away with ignoring this.
See below a modernized (in terms of C mutation progress) version of your code, which, at least worked on my machine after copy and pasting your data into emacs and saving it.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <array>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <cctype>
#include <locale>
using MarksArray = std::array<int,5>;
struct Data {
std::string fullname;
int group;
MarksArray firstMarks;
MarksArray secondMarks;
};
using DataVector = std::vector<Data>;
// trim functions taken from:
// https://stackoverflow.com/a/217605/2225104
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(),
s.end(),
[](unsigned char ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(),
s.rend(),
[](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
std::istream& operator>> (std::istream& stream, Data& data) {
bool success = true;
auto verify = [&success](const char* step) {
if (!success) {
std::cerr
<< "reading " << step << " failed!" << std::endl;
throw std::runtime_error(step);
}
};
success = success && std::getline(stream, data.fullname, '|');
verify("fullname");
trim(data.fullname);
std::string temp;
success = success && std::getline(stream, temp, '|');
verify("group");
data.group = std::stoi(temp);
success = success && std::getline(stream, temp, '|');
verify("firstMarks");
std::istringstream ss1(temp);
for (size_t i = 0; i < data.firstMarks.size(); i ) {
ss1 >> data.firstMarks[i];
}
success = success && std::getline(stream, temp);
verify("secondMarks");
std::istringstream ss2(temp);
for (size_t i = 0; i < data.secondMarks.size(); i ) {
ss2 >> data.secondMarks[i];
}
return stream;
}
std::ostream& operator<< (std::ostream& stream,
const MarksArray& data) {
bool first = true;
for (const auto& x : data) {
if (first) {
stream << x;
first = false;
} else
stream << " " << x;
}
return stream;
}
std::ostream& operator<< (std::ostream& stream, const Data& data) {
stream << data.fullname << " | "
<< data.group << " | "
<< data.firstMarks << " | "
<< data.secondMarks << std::endl;
return stream;
}
template <class T>
std::ostream& operator<< (std::ostream& stream,
const std::vector<T> & data) {
for (const auto &x : data) {
stream << x;
}
return stream;
}
DataVector ReadTable(const std::string& inPath) {
DataVector result;
std::ifstream stream(inPath);
size_t line = 1;
while (!std::ws(stream).eof()) {
try {
Data d;
stream >> d;
result.push_back(d);
line ;
}
catch (std::runtime_error& ex) {
std::cerr
<< "reading line " << line << " failed." << std::endl;
throw;
}
}
return result;
}
void WriteTable(std::ostream& stream, const DataVector& data) {
stream << data;
}
int main (int argc, const char* argv[]) {
std::string inputFilePath{"./data.txt"};
if (argc > 1) {
inputFilePath = argv[1];
}
std::cout << "reading "
<< inputFilePath << "..." << std::endl;
auto dv = ReadTable(inputFilePath);
std::cout << "... done" << std::endl
<< "number of records: " << dv.size() << std::endl;
//std::cout << dv << std::endl;
WriteTable(std::cout, dv);
return 0;
}