Dec 22, 2019 at 1:03pm UTC
I have a problem which I just can't figure it out. It happens in case 2 "Check info about a student". When the program is launched and first a group of students is created and then check info is selected everything is fine. The information is shown. But if I exit the program and then launch it again. When trying straight up checking info it throws the error.
Line 153: std::length_error at memory location
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
#include <iostream>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <conio.h>
#include <fstream>
const int N=30; //max students
const char students[]="students.dat" ;
struct student
{
std::string fnom;
std::string name;
char sex;
int age;
int ocenki[4];
double srusp;
};
int n;
std::fstream fp;
void menu();
void crstudent(struct student stud[]);
void chkinfo(struct student stud[]);
void addstudent();
void back();
int main()
{
menu();
}
void menu()
{
struct student stud[N];
int choice;
do
{
do
{
std::cout << "---------------//MENU//---------------\n\n" ;
std::cout << "Choose one of the following options: \n\n" ;
std::cout<<"1.Add a new student.\n"
<<"2.Check info about a student.\n"
<<"3..\n"
<<"4..\n"
<<"5.Exit program.\n\n" ;
std::cout << "Input: " ;
std::cin>>choice;
system("CLS" );
}
while (choice<1||choice>5);
switch (choice)
{
case 1:
{
int ch1;
do
{
std::cout<<"1. Create a group of students.\n"
<<"2. Add a new student.\n"
<<"3. Back.\n" ;
std::cin>>ch1;
system("CLS" );
}
while (ch1<1||ch1>3);
switch (ch1)
{
case 1:
crstudent(stud);
break ;
case 2:
addstudent();
break ;
case 3:
continue ;
break ;
}
break ;
}
case 2:
chkinfo(stud);
break ;
case 3:
break ;
case 4:
break ;
case 5:
exit(0);
break ;
default :
std::cout<<"Wrong input.\n" <<"Try again.\n" ;
}
}
while (choice !=5);
}
void crstudent(struct student stud[])
{
fp.open("students.dat" ,std::ios::out|std::ios::binary);
if (!fp)
{
std::cout<<std::endl<<"Error creating the file!" ;
exit(1);
}
std::cout<<"Input the number of students you wish to add: " ;
std::cin>>n;
for (int i=0; i<n; i++)
{
fflush(stdin);
std::cout<<"Input student " <<i+1<<" faculty number: " ;
std::cin.ignore();
std::getline(std::cin,stud[i].fnom);
std::cout<<"Input student's name: " ;
std::getline(std::cin,stud[i].name);
fp << stud[i].name;
std::cout<<"Input student's age: " ;
std::cin>>stud[i].age;
std::cout<<"Input student's sex - M or F: " ;
std::cin >> stud[i].sex;
stud[i].sex=std::toupper(stud[i].sex);//Converting lowercase to uppercase
stud[i].srusp=0;
std::cout<<"Input student's marks: \n" ;
for (int k=0; k<4; k++)
{
std::cout<<"Input mark number " <<k+1<<": " ;
std::cin>>stud[i].ocenki[k];
stud[i].srusp+=stud[i].ocenki[k];
}
stud[i].srusp=stud[i].srusp/4.00;
std::cout<<std::endl;
}
fp.write((char *)stud,n* static_cast <int64_t>(sizeof (student)));
fp.close();
system("CLS" );
}
void chkinfo(struct student stud[])
{
std::streamoff pos;
student s;
fp.open("students.dat" , std::ios::in | std::ios::binary);
if (!fp)
{
std::cout << std::endl << "File does not exist!" ;
exit(1);
}
fp.seekg(0L, std::ios::end);
pos = fp.tellg();//conversion from 'std::streamoff' to 'long', possible loss of data
fp.close();
fp.open("students.dat" , std::ios::in | std::ios::binary);
fp.seekg(0);
for (unsigned int i = 0; i < (pos / sizeof (student)); i++)
{
fp.read((char *)&s, sizeof (student));
stud[i] = s;
std::cout << std::endl << "Faculty number: " << stud[i].fnom;
std::cout << std::endl << "Name: " << stud[i].name;
std::cout << std::endl << "Age: " << stud[i].age;
std::cout << std::endl << "Sex: " << stud[i].sex;
std::cout << std::endl << "Average result is: " << stud[i].srusp;
std::cout << std::endl;
}
fp.close();
back();
Last edited on Dec 22, 2019 at 1:08pm UTC
Dec 22, 2019 at 1:49pm UTC
You can't fp.write() and fp.read() std::string objects in your student structure.
Each std::string has an internal pointer to somewhere else in memory where your actual string is stored.
Which is fine so long as you don't quit the program, or cause your array to go out of scope.
But as soon as you do, that string data is gone for good.
Just load your students.dat file into a hex editor, you will not see your strings.
So when you quit and reload, you're SoL, because the memory and the strings are gone.
Edit:
> fflush(stdin);
No - absolutely not.
If you're doing your cin.ignores properly, you don't need this abortion.
Last edited on Dec 22, 2019 at 1:50pm UTC
Dec 22, 2019 at 1:56pm UTC
I understand! It makes sense actually. So what are my alternative options? Can you recommend me something?
Dec 22, 2019 at 2:06pm UTC
Well the crude way out is to just use char arrays.
Proper robust serialisation of data structures is a minefield and a PITA in C++.
Dec 22, 2019 at 3:18pm UTC
Thank you! It is now working.