How do I access an object out of its block scope? - c++

Hey I am trying to figure out how to access an a object out of the scope of the block. I defined Person personData in the For loop which writes data to the file. And after the loop I wanted to access the object again to update the values on the file but its giving me the error - personData is undefined identifier.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdlib>
#include "Person.h"
using namespace std;
int main() {
string lastName;
string firstName;
int age;
//file output and creation
ofstream outPerson("nameage.dat", ios::out | ios::binary);
Person randPerson;
randPerson.setLastName("unassigned");
randPerson.setFirstName("");
randPerson.setAge(0);
randPerson.setId(0);
//for loop to initialize the file with 100 records that store values lastName and firstName
for (int i = 0; i < 100; i++) {
outPerson.write(reinterpret_cast<const char*>(&randPerson), sizeof(Person)); //use write to output to file
}
cout << "File Created" << endl;
//file input and termination
ifstream inPerson("nameage.dat", ios::in | ios::out | ios::binary);
//loops through 10 times to input 10 values (RECORD VALUES)
for (int j = 0; j < 2; j++) {
int id = 0;
do {
cout << "Enter a valid id number: (1-100)" << endl;
cin >> id;
} while ((id<1)||(id>100)); //breaks do-while after it receives a valid input
Person personData;
inPerson.seekg((id - 1) * sizeof(Person));
inPerson.read(reinterpret_cast<char*>(&personData), sizeof(Person));
//checks to see if there is already data in that area, if not then proceed to record data onto file
if (personData.getId() == 0) {
cout << "Enter lastname: ";
cin >> lastName;
cout << "Enter firstname: ";
cin >> firstName;
cout << "Enter age: ";
cin >> age;
//sets data for the particular object
personData.setLastName(lastName);
personData.setFirstName(firstName);
personData.setAge(age);
personData.setId(id);
//seek position in file of user-specified record
outPerson.seekp((personData.getId() - 1) * sizeof(Person));
//write user-specified information in file
outPerson.write(reinterpret_cast<const char*>(&personData), sizeof(Person));
cout << "Record inserted" << endl;
}
else {
cout << "There is already data there. Try another ID number" << endl;
}//end if
}//end for loop
int idSearch;
do {
cout << "Enter a ID number: " << endl;
cin >> idSearch;
} while ((idSearch < 1) || (idSearch > 100));
if (personData.getId() != 0) {
cout << "Enter new Last name";
cin >> lastName;
cout << "Enter new first name";
cin >> firstName;
cout << "Enter age";
cin >> age;
//sets data for the particular object
personData.setLastName(lastName);
personData.setFirstName(firstName);
personData.setAge(age);
personData.setId(idSearch);
//seek position in file of user-specified record
outPerson.seekp((personData.getId() - 1) * sizeof(Person));
//write user-specified information in file
outPerson.write(reinterpret_cast<const char*>(&personData), sizeof(Person));
cout << "Record updated" << endl;
}
inPerson.read(reinterpret_cast<char*>(&personData), sizeof(Person));
system("pause");
return 0;
}
I'm assuming the problem is because the object cant be accessed when out of scope. So how would I go about accessing the object from the statement below the for loop. Thank you.

It's one of the core ideas of C++ data model: data is deleted as soon, as it leaves the scope.
For this to work, you'd need to change the scope of personData (for example, move variable definition outside of the loop).
But be cautious using something like that. In the very best case personData would store data left by the last iteration of the loop.

Related

Reading from a file and into a dynamically allocated array of type Student in C++

I thought I had a decent understanding of fstreams and struct's, but for some reason I can't figure out what's wrong with my code. The file I'm reading from starts with an integer 'n' that represents the amount of students in the file, it's then used as the size of the dynamically allocated array of Students.
I go on to read each name, major, and grade from the file into the array of type Student. But for whatever reason, it's only reading the first "line" in the file (as in it reads the first name, major, and grade), and does that n times. I messed around with the code and I believe I've narrowed the problem down to the array not actually being of size n. It correctly reads the first int in the file, as I've printed it out to make sure that's working, and I've tried manually reading in each Student for the array from the file with the same issues.
This is an assignment, so I'm not looking for any straight forward answer, but a nudge in the right direction would be incredibly helpful.
Here's my code:
using namespace std;
struct Student {
string name, major;
double grade;
void display(Student);
void filterByMajor(Student[], int, string);
void filterByGrade(Student[], int, double);
};
int main() {
ifstream inputFile;
Student* students = nullptr;
string filename;
int n;
cout << “Enter an input file to read from: “;
cin >> filename;
inputFile.open(filename);
if (inputFile.fail()) {
cout << “ERROR: Could not open the file.” << endl;
}
else {
inputFile >> n;
students = new Student[n];
for (int i = 0; i < n; i++) {
inputFile >> students[i].name;
inputFile >> students[i].major;
inputFile >> students[i].grade;
}
cout << “ Student info” << endl;
students->display(students[0]);
cout << endl;
students->display(students[3]);
}
delete[] students;
inputFile.close();
return 0;
}
void Student::display(Student s) {
cout << “Name: “ << name << endl;
cout << “Major: “ << major << endl;
cout << “Grade: “ << grade << endl;
}
And the input file I'm reading from:
7
John CS 3.0
Joe Math 2.5
Jane Math 3.7
Mike CS 2.2
Carol CS 3.3
James Math 2.8
Mary CS 3.6
The problem is not with your reading code. That is actually reading the file data just fine. The real problem is in the display code. You are calling display() on the 1st entry in the array each time, and display() is ignoring the Student that is passed to it, instead displaying the data of the Student it is called on, so you see only the data of the 1st entry being printed each time.
Try this instead:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct Student {
string name, major;
double grade;
void display() const;
};
int main() {
ifstream inputFile;
Student* students = nullptr;
string filename;
int n;
cout << “Enter an input file to read from: “;
cin >> filename;
inputFile.open(filename);
if (inputFile.fail()) {
cout << “ERROR: Could not open the file.” << endl;
}
else {
inputFile >> n;
students = new Student[n];
for (int i = 0; i < n; i++) {
inputFile >> students[i].name;
inputFile >> students[i].major;
inputFile >> students[i].grade;
}
cout << “ Student info” << endl;
students[0].display();
cout << endl;
students[3].display();
}
delete[] students;
inputFile.close();
return 0;
}
void Student::display() const {
cout << “Name: “ << name << endl;
cout << “Major: “ << major << endl;
cout << “Grade: “ << grade << endl;
}

How can I read a document and write to it at the same time

struct employee
{
string empid;
string lastn;
string firstn;
float hours;
float payrate;
float taxrate;
};
const int SIZE = 100;
int main()
{
employee eCount[SIZE];
string empF;
int count, option1;
fstream inFile;
inFile.open("personnel1.dat", ios::in | ios::out);
count = 0;
cout << "Enter an Employee ID to Change Values (i.e Cv299): ";
cin >> empF;
cin.ignore();
while (!inFile.eof())
{
count += 1;
inFile >> eCount[count].empid >> eCount[count].lastn >> eCount[count].firstn >> eCount[count].hours >> eCount[count].payrate >> eCount[count].taxrate;
if (empF == eCount[count].empid)
{
do
{
cout << "1. Change Employee's ID (" << eCount[count].empid << ")\n";
cout << "2. Change Employee's Last Name (" << eCount[count].lastn << ")\n";
cout << "3. Change Employee's First Name (" << eCount[count].firstn << ")\n";
cout << "4. Change Employee's Hours Worked (" << eCount[count].hours << ")\n";
cout << "5. Change Employee's Pay Rate (" << eCount[count].payrate << ")\n";
cout << "6. Change Employee's Tax Rate (" << eCount[count].taxrate << ")\n";
cout << "7. Quit!\n\n";
cout << "Enter 1 - 7: ";
cin >> option1;
cin.ignore();
switch (option1)
{
case 1:
{
cout << "What would you like to change the Employee ID to?: ";
getline(cin, eCount[count].empid);
break;
}
case 2:
{
cout << "What would you like to change the Employee's Last Name to?: ";
getline(cin, eCount[count].lastn);
break;
}
case 3:
{
cout << "What would you like to change the Employee's First Name to?: ";
getline(cin, eCount[count].firstn);
break;
}
case 4:
{
cout << "What would you like to change the Employee's Hours Worked to?: ";
cin >> eCount[count].hours;
cin.ignore();
break;
}
case 5:
{
cout << "What would you like to change the Employee's Pay Rate to?: ";
cin >> eCount[count].payrate;
cin.ignore();
break;
}
case 6:
{
cout << "What would you like to change the Employee's Tax Rate to?: ";
cin >> eCount[count].taxrate;
cin.ignore();
break;
}
default:
break;
}
} while (option1 != 7);
}
}
inFile << eCount[count].empid << eCount[count].lastn << eCount[count].firstn << eCount[count].hours << eCount[count].payrate << eCount[count].taxrate;
inFile.close();
}
The program is supposed to read the file and also allow the user to write to it. After inputting a valid employee ID it pops up the menu allowing the user to enter what they want to change. After inputting those changes and closing the file, it doesn't update the file. It still shows the same values from before.
You can do some thing like,
This code copies Line by line from old file to a tempfile. When you find the line which you want to update, change it with your line and copy it to the tempfile. Then finally copy all data from tempfile to file and delete tempfile
#include<iostream>
#include<fstream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
using std::ios;
class Employee
{
public:
std::string empname;
std::string empid;
};
int main()
{
std::fstream file("emp"),tempfile("tempemp");
Employee emp;
std::string id;
if(!file.is_open()||!tempfile.is_open())
{
file.open("emp",ios::out); //create a file
tempfile.open("tempemp",ios::out); //create a file
if(!file.is_open()||!tempfile.is_open())
{
cout<<"File Error";
exit(1);
}
else
{
file.close();
tempfile.close();
file.open("emp"); // open file for both read and write
tempfile.open("emp"); // open file for both read and write
if(!file.is_open()||!tempfile.is_open())
{
cout<<"File Error";
exit(1);
}
}
}
for(int i=0;i<3;i++) // taking 3 employee name and id
{
cout<<"Enter Name and id:"<<endl;
cin>>emp.empname;
cin>>emp.empid;
file.write((char*)&emp,sizeof emp);
}
cout<<"Contents:"<<endl; //printing contents
file.seekg(0,ios::beg); //move get pointer to beginning
while(file.peek()!=EOF)
{
file.read((char*)&emp,sizeof emp);
cout<<emp.empname<<endl;
cout<<emp.empid<<endl;
}
file.clear(); //reset file
cout<<"Enter Id to Modify:"<<endl;
cin>>id; // which id to modify
file.seekg(0,ios::beg); //move get pointer to beg
tempfile.seekp(0,ios::beg); //move get pointer to beg
while(file.peek()!=EOF)
{
file.read((char*)&emp,sizeof emp);
if(emp.empid==id) //if emp id in file equal to id then
{ //save to tempfile the name and id of user entered
cout<<"Enter New name and id:"<<endl;
cin>>emp.empname;
cin>>emp.empid;
tempfile.write((char*)&emp,sizeof emp);
}
else // if not equal save the content in file to tempfile
{
tempfile.write((char*)&emp,sizeof emp);
}
}
file.clear(); //reset file
tempfile.seekg(0,ios::beg); //move get pointer pos to beg
file.seekp(0,ios::beg); //move put pointer pos to beg
while(tempfile.peek()!=EOF)
{
tempfile.read((char*)&emp,sizeof emp); //copy contents of tempfile to file
file.write((char*)&emp,sizeof emp);
}
file.clear(); //reset file
tempfile.close(); //close file
remove("tempemp"); //remove tempemp pointed by tempfile
cout<<"Modified Contents:"<<endl; //print modified contents
file.seekg(0,ios::beg); //move get pointer pos to beg
while(file.peek()!=EOF)
{
file.read((char*)&emp,sizeof emp);
cout<<emp.empname<<endl;
cout<<emp.empid<<endl;
}
file.close(); //close file
return 0;
}
i am used name and id only for simplicity
(OR)
you can use like this also,But this code did not use tempfile. it replaces the new content directly in the file.
#include<iostream>
#include<fstream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
using std::ios;
class Employee
{
public:
std::string empname;
std::string empid;
};
int main()
{
std::fstream file("emp");
Employee emp;
std::string id;
std::fstream::pos_type pos=0; //for position
if(!file.is_open())
{
file.open("emp",ios::out);
if(!file.is_open())
{
cout<<"File Error";
exit(1);
}
else
{
file.close();
file.open("emp");
if(!file.is_open())
{
cout<<"File Error";
exit(1);
}
}
}
for(int i=0;i<3;i++)
{
cout<<"Enter Name and id:"<<endl;
cin>>emp.empname;
cin>>emp.empid;
file.write((char*)&emp,sizeof emp);
}
cout<<"Contents:"<<endl;
file.seekg(0,ios::beg);
while(file.peek()!=EOF)
{
file.read((char*)&emp,sizeof emp);
cout<<emp.empname<<endl;
cout<<emp.empid<<endl;
}
file.clear();
cout<<"Enter Id to Modify:"<<endl;
cin>>id;
file.seekg(0,ios::beg);
file.seekp(0,ios::beg);
pos=file.tellp(); //get init pos
while(file.peek()!=EOF)
{
pos=file.tellp(); //update pos
file.read((char*)&emp,sizeof emp);
if(emp.empid==id)
{
cout<<"Enter New name and id:"<<endl;
cin>>emp.empname;
cin>>emp.empid;
file.seekp(pos); // change pos
file.write((char*)&emp,sizeof emp); //save modified content
}
}
file.clear();
cout<<"Modified Contents:"<<endl;
file.seekg(0,ios::beg);
while(file.peek()!=EOF)
{
file.read((char*)&emp,sizeof emp);
cout<<emp.empname<<endl;
cout<<emp.empid<<endl;
}
file.close();
return 0;
}
In file streams only tellg changes tellp but it not for other streams for more info see this
are "seekp" & "seekg" interchangeable?

File program won't stop displaying garbage values

I am trying to insert object in file and then read the object to display the student data but when It goes to display program just goes in infinite loop and starts displaying 0 which I have initialized in constructor.I am simply not getting what is happening. I am using visual studio 17 just in case anyones wondering. I even tried to create a new file named Student.txt in same directory as the program but it won't work. Can somone explain me what I am doing wrong?
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
//class to handle individual record
class Student
{
public:
char name[20];
int year;
char division;
char address[50];
int rollno;
Student()
{
strcpy_s(name," ");
strcpy_s(address, " ");
rollno = 0;
year = 0;
division = 0;
}
};
class operations
{
public:
void insertdata();
void printg();
};
void operations::insertdata()
{
int n;
cout << "\nEnter how many student data you want to insert:";
cin >> n;
fstream fin;
Student obj;
fin.open("Student.txt", ios::in | ios::out | ios::binary| ios::trunc);
if (!fin)
{
cout<<"\nFILE NOT Opened!";
}
for (int v = 0; v < n; v++)
{
cout << "\nEnter Roll no:";
cin >> obj.rollno;
cout << "\nEnter Name:";
cin.ignore();
cin >> obj.name;
cout << "\nEnter year:";
cin >> obj.year;
cout << "\nEnter division:";
cin >> obj.division;
cout << "\nEnter Address:";
cin.ignore();
cin >> obj.address;
fin.seekp(0, ios::end);
fin.write((char*)&obj, sizeof(obj));
}
fin.close();
}
void operations::printg()
{
Student obj;
fstream fin("Student.txt", ios::in | ios::out | ios::binary);
fin.seekg(0, ios::beg);
fin.read((char*)&obj, sizeof(obj));
if (!fin)
{
cout << "\n FIle doenst exist";
}
while (!fin.eof())
{
cout << "\n" << obj.name;
cout << "\n" << obj.year;
cout << "\n" << obj.division;
}
fin.close();
}
int main() {
operations obj;
obj.insertdata();
obj.printg();
system("pause");
return 0;
}
A few wrong things:
Writing objects like fin.write((char*)&obj, sizeof(obj)); is a bad idea. A compiler may decide to have different padding between members at any moment for your Student objects, so your file format is like a quantum particle: you don't really know how the file was laid out.
strcpy_s takes 3 parameters, not 2. Anyway, do not use them, they are not really portable (even if they are in the C standard).
Your paths are wrong, so the file will not open (as Sam explains in the comment).
Even if you succeeded in opening a file, in operations::printg() you are not reading the file, so you will not get any data.
Why do you have an operations class? I guess it is intended to be expanded in the future, but seems weird. If you do not intend to have state, use a namespace instead.

visual studioc++ array size in struct is too long

I am currently doing an assignment for my beginner C++ course, the chapter is on structs. I am using visual studio so I am can't do anything fancy for dynamic array's (i.e. no vector's etc.).
The part of the homework I am having trouble with is reading a file with some spaces at the end of the file. Since I am using filename.eof() it is reading the blanks and recording that data. I tried doing cin.ignore(xxxxx, '\n'), however that did not work. The my current out put is the data I want but a row of garbage. How do I get rid of the garbage?
a) A function to read the data into the array. You can use the attached file named soccer-1.txt to test your code. It also goes without saying that your code must work with any input data file. Of course, for testing, use your file to avoid entering data while testing. The name of the data file must always be entered by the user (do not hard code a file name). Also, check to make sure that the given input data file exists. If the file does not exist, issue an error message to alert the user about the invalid file name. Make sure to ask the user again for the name of another file. However, terminate the program after the user has entered an incorrect file name for a total of 3 times. NOTE: the data file name can be input inside the function.
The text file looks like this:
"
Duckey E Donald forward 8 2 21
Goof B Goofy defense 12 0 82
Brave A Balto goalkeeper 0 0 5
Snow W White defense 1 2 3
Alice I Wonderful midfield 1 5 15
Samina S Akthar right_defense 1 2 7
Simba P Green left_back 7 3 28
**************WHITESPACE****************************
**************WHITESPACE****************************
Here is my code:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int subSize = 100;
//struct to store nameInfo
struct nameInfo
{
string fName;
char middleInitial;
string lName;
};
//struct to store playerInfo
struct playerInfo
{
nameInfo name;
string postion;
int goals;
int penalties;
int jersey;
};
int getData(playerInfo matrix[]);
void displayData(playerInfo matrix[], int arraySize);
int main()
{
playerInfo p;
playerInfo playerArray[subSize];
int arraySize;
int userSelection;
string searchTerm;
arraySize = getData(playerArray);
cout << arraySize << " records found." << endl << endl;
displayData(playerArray, arraySize); //call to display all data
cout << endl;
return 0;
}
//function to read the data into the array
int getData(playerInfo matrix[])
{
ifstream infile;
string fileName;
int i = 0; //counter to hold array row length
int k = 0; //counter for file input
int x = 0; //counter for user input
cout << "Enter the file name (e.g. soccer-1.txt): ";
getline(cin, fileName);
cout << endl;
infile.open(fileName.c_str());
//checks if file exists
//ask the user again for the name of another file
//loop returns -1 after 3 failed attempts to enter a file
while (!infile)
{
k++;
cout << "After attempt " << k
<< " input file not opened." << endl;
cout << "Attempt " << k + 1 << ", enter the file name (e.g. soccer.txt): ";
getline(cin, fileName);
cout << endl;
infile.open(fileName.c_str());
cout << endl;
if (k == 2) //terminate program at 2 because entered validation loop
{ //after first attempt
cout << "Terminating program.";
return -1;
}
}
while (!infile.eof())
{
infile >> matrix[i].name.fName >> matrix[i].name.middleInitial
>> matrix[i].name.lName >> matrix[i].postion
>> matrix[i].goals >> matrix[i].penalties
>> matrix[i].jersey;
i++; //holds size of array
}
infile.close();
return i;
}
void displayData(playerInfo matrix[], int arraySize)
{
for (int y = 0; y < arraySize; y++)
{
//display format:
//Duckey.(E)Donald:8 2 21 – forward
cout << matrix[y].name.fName
<< ".(" << matrix[y].name.middleInitial << ")"
<< matrix[y].name.lName << ":" << matrix[y].goals << " "
<< matrix[y].penalties << " " << matrix[y].jersey
<< " - " << matrix[y].postion << endl;
}
}
OK, this is where you can apply a change:
while (!infile.eof()) {
infile >> matrix[i].name.fName >> matrix[i].name.middleInitial >>
matrix[i].name.lName >> matrix[i].postion >> matrix[i].goals >>
matrix[i].penalties >> matrix[i].jersey;
i++; // holds size of array
}
Read to a string, or a set of strings, instead of straight to the container. That way you can check they're valid (i.e. not blank) before copying to the matrix container.

Segmentation fault when accessing a structure

The program works all the way up until it checks for the name the user enters. When you enter the name you wish to search for in the array of structures that have been imported from a file full of customer info) it comes back segmentation fault core dumped. This puzzles me.
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
using namespace std;
struct AccountsDataBase{
char name[50];
string email;
long int phone;
string address;
};
#define MAX 80
AccountsDataBase * account = new AccountsDataBase[MAX];
void readIn(ifstream& file){
int i=0;
while(!file.eof()){
file >> account[i].name >> account[i].email >> account[i].phone >> account[i].address;
}
}
void getAccount(){
char userPick[50];
char streamName[50];
cout << " What account will we be using? " << endl;
cin.getline(streamName, 50);
for(int i=0; strcmp(account[i].name, streamName)!=0; i++){
if( strcmp(account[i].name, streamName)==0){
cout << "\n\n FOUND IT!! \n\n";
cout << account[i].name << "\n" << account[i].email << "\n" << account[i].phone << "\n" << account[i].address << endl;
}
}
}
int main(){
ifstream file;
file.open("2.dat"); //opens data account records text
readIn(file);
getAccount();
delete account;
return 0;
}
Your loop keeps reading everything into the initial element of the array:
while(!file.eof()){
file >> account[i].name >> account[i].email >> account[i].phone >> account[i].address;
}
because the value of i is never incremented. You can convert this to a for loop, like this:
for (count = 0 ; count < MAX && !file.eof() ; count++) {
file >> account[count].name >> account[count].email >> account[count].phone >> account[count].address;
}
Note that I changed i to count:
AccountsDataBase * account = new AccountsDataBase[MAX];
int count = 0;
This will help you solve another problem - determining when the array ends in the getAccount function. Currently, you assume that the record is always there, so the outer loop keeps going on. Now that you have count, you could change the loop like this:
for(int i=0; i < count && strcmp(account[i].name, streamName)!=0; i++){
if( strcmp(account[i].name, streamName)==0){
cout << "\n\n FOUND IT!! \n\n";
cout << account[i].name << "\n" << account[i].email << "\n" << account[i].phone << "\n" << account[i].address << endl;
break;
}
}
if (i == count) {
cout << "Not found." << endl;
}