Entering data from .txt into struct array - c++

For my c++ homework, I have an .txt document containing building information ordered like:
Building name
year built
lat coordinate
lon coordinate
ex.
Parking Deck
1993
34.2252
37.5563
Admin Building
1985
34.2356
37.5734
I have to read this into an array of my created struct:
struct list
{
char name[50];
int yearBuilt;
double latCoord;
double lonCoord;
} building;
now I've created a for loop to read in the data to my created array of type list:
list buildingnumber[SIZE]; //array for buildings
But when I try to print out the "k" earliest buildings made, it shows no data in the array
Here's my current code:
#include <iostream>
#include <fstream>
#include <istream>
#include <cstdlib>
#include <string>
using namespace std;
const int SIZE = 5000;
//struct for building type
struct list
{
char name[50];
int yearBuilt;
double latCoord;
double lonCoord;
}building;
list buildingnumber[SIZE]; //array for buildings
void InsertionSort(list buildingnumber[], int buildingsloaded)
{
int key = 0, i = 0;
for(int j = 1; j < buildingsloaded; j++)
{
key=buildingnumber[j].yearBuilt;
i=j-1;
while(buildingnumber[i].yearBuilt > key && i >= 0)
{
buildingnumber[i+1] = buildingnumber[i];
i--;
}
buildingnumber[i+1].yearBuilt = key;
}
}
int main()
{
char filePath[50];
ifstream openFile;
cout << "Enter the path of the building file: ";
cin.getline(filePath, 50);
openFile.open(filePath);
//verify if file is opened + report buildings loaded
int buildingsloaded = 0;
if(!openFile.fail())
{
while(openFile >> building.name >> building.yearBuilt >> building.latCoord >> building.lonCoord)
{
buildingsloaded++;
}
cout << buildingsloaded << " buildings have been loaded." << endl;
}
// get how many buildings user wants
int k = 0;
cout << "How many buildings are you interested in?: ";
cin >> k;
//create array
// loadKbuildings(building, buildingsloaded);
for(int i = 0; i < k; i++)
{
openFile >> buildingnumber[i].name >> buildingnumber[i].yearBuilt >> buildingnumber[i].latCoord >> buildingnumber[i].lonCoord;
}
// insertion sort
InsertionSort(buildingnumber, buildingsloaded);
// display earliest k buildings
cout << "The " << k << " oldest buildings are: " << endl;
int i = 0;
while ( i < k )
{
cout << buildingnumber[i].name << endl;
cout << "Year Built: " << buildingnumber[i].yearBuilt << endl;
cout << "Coordinates: (" << buildingnumber[i].latCoord << "," << buildingnumber[i].lonCoord << ")" << endl;
cout << endl;
i++;
}
}

The problem is here:
if(!openFile.fail())
{
while(openFile >> building.name >> building.yearBuilt >> building.latCoord >> building.lonCoord)
{
buildingsloaded++;
}
cout << buildingsloaded << " buildings have been loaded." << endl;
}
You've read all of the data already (to count the number of buildings); the next time you try to grab the data, it's gone.
You can resolve this issue by storing the buildings in an array the first scan through.
int c = 0;
if(!openFile.fail())
{
// *
while(openFile >> buildingnumber[c].name >> buildingnumber[c].yearBuilt >> buildingnumber[c].latCoord >> buildingnumber[c].lonCoord)
{
buildingsloaded++;
c++;
}
cout << buildingsloaded << " buildings have been loaded." << endl;
}
As per WhozCraig's comment, the line under the star only reads in one word for the building's name; you should use cin.getline() instead and change around the loop condition.
You should obviously also take out the data reading section below:
//create array
// loadKbuildings(building, buildingsloaded);
for(int i = 0; i < k; i++)
{
openFile >> buildingnumber[i].name >> buildingnumber[i].yearBuilt >> buildingnumber[i].latCoord >> buildingnumber[i].lonCoord;
}

Related

Adding conditions to a conditional statement

I am messing around with dynamic arrays for a user defined amount of inputs for an and gate.
The issue I am running into is that I don't know how many inputs the user is going to test and I need to be able to have an if-else statement that tests each input.
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class logic_gate {
public:
int x = 0;
};
int main() {
int userInput = 0;
cout << "How many inputs do you want on your and gate?: ";
cin >> userInput;
cout << endl;
logic_gate *and_gate = new logic_gate[userInput];
cout << endl << "Please enter the values of each bit below . . ." << endl <<
endl;
int userTest1 = 0;
for (int i = 0; i < userInput; i++) {
cout << "#" << i + 1 << ": ";
cin >> userTest1;
and_gate[i].x = userTest1;
}
return 0;
}
Here is the code that I am currently trying to find a solution for.
To implement an AND gate with n inputs you can simply do:
int output = 1;
for (int i = 0; i < n; ++i)
{
if (!and_gate [i])
{
output = 0;
break;
}
}
// ...
Use Vector data structure, you don't need to tell its size while declaring, unlike array, and it can grow automatically.
To read input till it's arriving, put cin inside while loop condition. I used getline to read whole line and work with it, so that whenever user presses enter button at empty line, program will think that no more input is coming anymore, and will start calculating 'And' of inputs.
//don't forget to import vector
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class logic_gate {
public:
int x = 0;
logic_gate(){ //default constructor
}
logic_gate(int k){ //another constructor needed
x = k;
}
};
int main(){
cout << endl << "Please enter the values of each bit below . . ." << endl;
vector<logic_gate> and_gate; //no need to tell size while declaration
string b;
while(getline(cin, b)){ //read whole line from standard input
if (b == "\0") //input is NULL
break;
and_gate.push_back(logic_gate(stoi(b))); //to convert string to integer
}
if (!and_gate.empty()){
int output = and_gate[0].x;
for (int i = 1; i < and_gate.size(); i++){
output = output & and_gate[i].x;
}
cout << "And of inputs is: " << output << endl;
}
else{
cout << "No input was given!\n";
}
return 0;
}
Feel free to ask if some doubts linger
I figured out what I wanted to do. Thanks to everyone who helped and especially Paul Sanders. Below is my final code.
#include <iostream>
using namespace std;
class logic_gate {
public:
int x = 0;
};
int main() {
int userInput;
int output = 1;
cout << "How many inputs do you want on your and gate?: ";
cin >> userInput;
cout << endl;
logic_gate *and_gate = new logic_gate[userInput];
cout << endl << "Please enter the values of each bit below . . ." << endl <<
endl;
int userTest1;
for (int i = 0; i < userInput; i++) {
cout << "#" << i + 1 << ": ";
cin >> userTest1;
and_gate[i].x = userTest1;
}
if (userInput == 1) {
output = userTest1;
cout << "The test of " << userTest1 << " is " << output << endl << endl;
}
else if (userInput > 1) {
for (int i = 0; i < userInput; i++) {
if (!and_gate[i].x)
{
output = 0;
break;
}
}
cout << "The test of ";
for (int i = 0; i < userInput; i++) {
cout << and_gate[i].x;
}
cout << " is " << output << endl << endl;
}
return 0;
}

Multiple errors with function header, and overloaded functions

it's my first time working with classes and headers in C++ and I ran into these errors after putting together my code
function does not take 1 arguments // For all 4 functions
overloaded member function not found in 'Animals' // Also for all 4 fncs
syntax error: identifier 'fstream' // header file error
The program is designed to read and write to a file, while also doing searches and being able to manipulate the binary file. I'm pretty sure the error is in my declarations somewhere but I can't figure it out myself; any help is appreciated.
main.cpp
#include <iostream>
#include<iomanip>
#include <fstream>
#include"animals.h"
using namespace std;
int main()
{
Animals nA;
fstream animalFile;
int choice;
cout << setprecision(2) << fixed;
do
{
// Display the menu.
cout << "\n1. Add a new animal\n";
cout << "2. Remove an animal\n";
cout << "3. Search and display a animal\n";
cout << "4. Display all animals\n";
cout << "5. Exit\n";
do
{
cout << "Enter your choice (1-5): ";
cin >> choice;
} while (choice < 1 || choice > 5);
// Process the selection.
switch (choice)
{
// Choice 1 is to add an animal
case 1:
nA.addAnimal(animalFile);
break;
// Choice 2 is to remove an animal
case 2:
nA.removeAnimal(animalFile);
break;
// Choice 3 is to search and display 1 animal
case 3:
nA.searchAnimal(animalFile);
break;
// Choice 4 is to display all animals
case 4:
nA.displayAnimal(animalFile);
}
} while (choice != 5);
system("pause");
return 0;
}
Animals.h
#ifndef ANIMALS_H
#define ANIMALS_H
#include <string>
#include <iostream>
#include <fstream>
class Animals
{
private :
std::string name;
int age;
public :
//Default constructor
Animals();
//Create an animal object
Animals(std::string name, int age);
//Add a new animal record
void addAnimal(fstream &d);
//Remove an animal record
void removeAnimal(fstream &d);
//Displays an animal through a search
void searchAnimal(fstream &d);
//Display ALL animals
void displayAnimal(fstream &d);
};
#endif
Animals.cpp
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
#include "Animals.h"
using namespace std;
Animals::Animals()
{
name = "NULL";
age = 0;
}
Animals::Animals(std::string name, int age)
{
Animals *newAnimal = new Animals;
}
void Animals::addAnimal(fstream &d)
{
string userName;
int userAge = 0;
int stringRemainder;
int record;
const int RECORD_SIZE = 40;
//Collecting user input
do
{
std::cout << "Please enter your animal name: ";
std::cin >> userName;
std::cout << "\n";
} while (sizeof(userName) > 30);
do
{
std::cout << "Please enter your animal age: ";
std::cin >> userAge;
std::cout << "\n";
} while (userAge <= 0 || !isdigit(userAge));
//Fixing length of string
stringRemainder = 30 - sizeof(userName);
//Finds record number based on position
record = (d.tellg() % RECORD_SIZE) + 1;
//Writing to file
d.close();
d.open("animals.txt", std::ios_base::app | ios::binary);
d << record << "";
d << userName;
for (int i = 0; i < stringRemainder; i++)
{
d << "";
}
d << userAge << "\n";
d.close();
}
void Animals::removeAnimal(fstream &d)
{
int recordNumber = 0;
const int RECORD_SIZE = 40;
char recordBuffer[RECORD_SIZE];
d.open("animals.txt", ios::out| ios::in |ios::binary);
//Collecting user input
do
{
cout << "Enter the record of the animal to be removed: ";
cin >> recordNumber;
} while (recordNumber <= 0 || !isdigit(recordNumber));
// move pointer to desired position, and overwrite!
d.seekp((recordNumber-1) * RECORD_SIZE);
d.write(recordBuffer, RECORD_SIZE);
d.close();
}
void Animals::searchAnimal(fstream &d)
{
int userRecord = 0;
char displayRecord[2];
const int RECORD_SIZE = 40;
char fileOutput[RECORD_SIZE];
string displayInfo;
char displayName[RECORD_SIZE];
char displayAge[2];
int i,k;
int j = 0;
d.open("animals.txt", ios::out | ios::binary);
//Getting user input
do
{
cout << "Enter the record of the animal to be diplayed: ";
cin >> userRecord;
} while (userRecord <= 0 || !isdigit(userRecord));
//Moving pointer position to searched value
d.seekp((userRecord - 1) * RECORD_SIZE);
//Gets data from file, stores into displayInfo
getline(d, displayInfo);
d.close();
//Entering file data into diplay variables,
//value 'i' increments through entire displayInfo array
for (i = 0; isdigit(displayInfo[i]); i++)
{
displayRecord[i] = displayInfo[i];
}
//New sentinel for ONLY string cap including buffer
k = i + 30;
for (i; i < k; i++)
{
displayName[j] = displayInfo[i];
j++;
}
//Finishes off last of the displayInfo array
for (i; i < sizeof(displayInfo); i++) {
displayAge[i] = displayInfo[i];
}
//Prints the data for user
cout << "For record number: " << userRecord << "\n";
cout << "Animal: ";
for (int i = 0; i < strlen(displayName); i++)
{
cout << displayName[i];
}
cout << "\n";
cout << "Age: ";
for (int i = 0; i < strlen(displayAge); i++)
{
cout << displayAge[i];
}
cout << "\n";
}
//Mostly copied from above function, displays ALL animals
void Animals::displayAnimal(fstream &d)
{
int userRecord = 0;
char displayRecord[2];
const int RECORD_SIZE = 40;
char fileOutput[RECORD_SIZE];
string displayInfo;
char displayName[RECORD_SIZE];
char displayAge[2];
int numberOfRecords;
int i, k;
int j = 0;
int q = 0;
d.open("animals.txt", ios::out | ios::in | ios::binary);
d.seekg(0, d.end);
numberOfRecords = d.tellg() % RECORD_SIZE;
d.seekg(0, d.beg);
for (int q; q < numberOfRecords; q++) {
d.seekp(q * RECORD_SIZE);
//Gets data from file, stores into displayInfo
getline(d, displayInfo);
//Entering file data into diplay variables,
//value 'i' increments through entire displayInfo array
for (i = 0; isdigit(displayInfo[i]); i++)
{
displayRecord[i] = displayInfo[i];
}
//New sentinel for ONLY string cap including buffer
k = i + 30;
for (i; i < k; i++)
{
displayName[j] = displayInfo[i];
j++;
}
//Finishes off last of the displayInfo array
for (i; i < sizeof(displayInfo); i++) {
displayAge[i] = displayInfo[i];
}
//Prints the data for user
cout << "For record number: " << userRecord << "\n";
cout << "Animal: ";
for (int i = 0; i < strlen(displayName); i++)
{
cout << displayName[i];
}
cout << "\n";
cout << "Age: ";
for (int i = 0; i < strlen(displayAge); i++)
{
cout << displayAge[i];
}
cout << "\n\n";
}
d.close();
}
The headers <iostream> and <fstream> bring their symbols into the std namespace, so any reference to these symbols in the header need to be fully qualified; e.g. std::fstream. Also, you might want to include <iosfwd> in your headers instead - this minimizes the compiler time cost of importing the header, assuming that the header only uses reference to the symbols mentioned in the iostream header.
You should use ifstream for read files and ofstream for write files.
And in header file, you should use std::ifstream & d or std::ofstream & d in argument of 4 functions.

c++ array showing an error

Hello i am trying to create a program in which you enter your deals and after you're finished you should get a list of the deals . I want to get them displayed with an array but i keep getting an error must have a pointer to object.
#include <iostream>
using namespace std;
int main() {
int deal;
int date;
int type;
int quantity;
int quality;
int end;
int find;
for (deal = 0; deal < 5000; deal++) {
for (date = 0; date < 5000; date++) {
cout << " enter the year,month,day and hour of pruchase in this format YYYY/MM/DD/HH/MM" << endl;
cin >> date;
for (type = 0; type < 5000; type++) {
cout << " enter the mushroom type. 1 = манатарка, 2 = печурка, 3 = кладница 4 = пачи крак, 5 = съренла, 6 = друг вид гъба "<<endl;
cin >> type;
for (quantity = 0; quantity < 5000; quantity++) {
cout << " enter the mushroom quantity " << endl;
cin >> quantity;
for (quality = 0; quality < 5000; quality++) {
cout << "enter the mushroom quality from 1 to 3 " << endl;
cin >> quality;
cout << "Press 1 for a new deal , press 2 to exit" << endl;
cin >> end;
if (end = 2)
{
deal[date];
goto stop;
}
}
}
}
}
}
stop:
for (find = 0; find < 5000; find++) {
int find = 0;
cout << date[find] << ", " << type[find] << ", " << quantity[find] << ", " << quality[find];
//error must have a pointer to object
}
}
Your date, find, etc. variables are defined as scalars. You cannot refer to them date[find]. You should have declared them as arrays/vectors.
deal should be declared as array type of int.

Is there a way to link input from two different arrays?

I'm having an issue with some school work where I need to create two arrays one for names and one for scores which allows the user to input into both arrays (i.e. Enter the players name:; Enter the players score:). Then I need to print the arrays in descending score and then ascending alphabetical. As a hint we were told: Using the string sort function combine the two arrays into one then sort.
However I can't figure out how to link the two values to one another so that if I enter Nathan with a score of 87 the two values can't be split apart.
This is what I have so far (with some things I was trying to get to work but couldn't):
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string names[10];
int scores[10];
string combine[20];
int count = 0;
while (count < 10){
cout << "Please enter a player's name: ";
cin >> names[count];
cout << "Now enter that player's score: ";
cin >> scores[count];
count++;
}
/*sort(begin(names), end(names));
sort(begin(scores), end(scores));*/
for (int i = 0; i < 10; i++){
cout << names[i] << ": " << scores[i] << "\n";
}
system("pause");
}
You want to "link" them from the very beginning:
struct Student {
string name;
int score;
bool operator<(const Student& rhs) const {
return score > rhs.score || (score == rhs.score && name < rhs.name);
}
};
That way, the sort is easy:
sort(begin(students), end(students));
Otherwise, you'd have to make an array of indices:
int indices[10];
std::iota(begin(indices), end(indices), 0);
And sort that:
std::sort(begin(indices), end(indices), [&](int a, int b){
return scores[a] > scores[b] ||
scores[a] == scores[b] && names[a] < names[b];
});
And then print according to indices:
for (int idx : indices) {
std::cout << names[idx] << " with score " << scores[idx] << '\n';
}
As far as combining the two arrays into one you can do something like this:
// create a struct that of type "result"
// that combines both name and score
struct result
{
string name;
int score;
};
int main()
{
string names[10];
int scores[10];
// array of your struct - same number of elements (10 not 20)
result combine[10];
int count = 0;
while (count < 10){
cout << "Please enter a player's name: ";
cin >> names[count];
cout << "Now enter that player's score: ";
cin >> scores[count];
count++;
}
/*sort(begin(names), end(names));
sort(begin(scores), end(scores));*/
for (int i = 0; i < 10; i++){
cout << names[i] << ": " << scores[i] << "\n";
}
// combine into one array
for(int i = 0; i < 10; ++i)
{
combine[i].name = names[i];
combine[i].score = scores[i];
}
// Now sort the combined array
system("pause");
}

Dynamically Allocated Structures

So i am having troubles here. The program works perfectly fine when i enter in 1 for numStudents but get a segmentation fault: 11 when i enter anymore that 1 for numstudents. Am i doing something wrong with the dynamic allocation? I am just lost have done everything i can think of.
#include <iostream>
#include <string>
#include <cstdlib>
#include <iomanip>
using namespace std;
//Structure Declaration
struct Student
{
string name;
long long ID;
double *score;
};
//Function prototypes
void calcAvg (int loc, Student test[], double average[], int tests);
int main()
{
int numStudents, numTests; //Get from user
double *averages; //For Dynamic allocation of averages
Student *info; //For Dynamic Allocation
cout << "Enter the number of students you will enter ";
cin >> numStudents;
info = new Student[numStudents];
averages = new double[numStudents];
cout << "\nEnter the number of tests that were taken by the students ";
cin >> numTests;
info->score = new double[numTests];
for(int s = 0; s < numStudents; s++)
{
cout << "Enter student #" << (s+1) << "'s name ";
cin.ignore();
getline(cin, info[s].name);
cout << "Enter " << info[s].name << "'s ID number ";
cin >> info[s].ID;
cout << endl;
for(int t = 0; t < numTests; t++)
{
cout << "\nEnter " << info[s].name << "'s score for test #" <<(t+1) << " ";
cin >> info[s].score[t];
while(info[s].score[t] > 100 || info[s].score[t] < 0)
{
cout << "The score you entered is invalid, try again. ";
cin >> info[s].score[t];
}
}
calcAvg(s, info, averages, numTests);
}
return 0;
}
void calcAvg (int loc, Student test[], double average[], int tests)
{
double total = 0;
for(int i = 0; i < tests; i++)
{
total += test[loc].score[i];
}
average[loc] = total/tests;
cout << average[loc] << endl;
}
You need to repeat this for each student
info->score = new double[numTests];
So you could move it into the loop:
for(int s = 0; s < numStudents; s++)
{
info[s].score = new double[numTests];
...
}
But all this is very error prone - I suggest you look into structures that can handle all this for you like std::vector.