I'm working on this project and I'm fairly new to C++. Its kind of hard to explain what I'm trying to do but I shall try. So I'm working with a file called flix.txt and in it looks like the following:
1 A 5
1 B 4
1 D 3
1 F 5
2 A 1
3 E 3
3 F 1
4 A 2
The first column are people(my objects), second columns are movies, and the third are the ratings given by the objects.
I'm trying to first extract the first int from every line and create an object using an 'operator new'. Then I'm taking a movie and turning it into an int so I can plug the rating into an array. Sorry if it sounds confusing. Heres the code I have now:
//flix program
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#define NUMBER_OF_MOVIES 6
using namespace std;
int tokenize(string line);
int getMovieNum(char movie);
void resetPos(istream& flix);
class Matrix{
public:
int movieRate[NUMBER_OF_MOVIES];
};
int main(){
int distinctCount = 0;
int checker = -1;
int check = 0;
string line;
int personNum;
char movie;
int rating;
int movieNum;
ifstream flix("flix.txt");
ofstream flick("flix1.txt");
//identify distinct account numbers in file
while(getline(flix, line)){
check = tokenize(line);
if(check != checker)
distinctCount++;
checker = check;
check = 0;
}
//reset position in file
resetPos(flix);
//create objects in accordance with distinct numbers
Matrix* person = new Matrix[distinctCount];
for(int i = 0; i < distinctCount; i++){
for(int j = 0; j < NUMBER_OF_MOVIES; j++){
person[i].movieRate[j] = 0;
cout << i + 1 << ' ' << person[i].movieRate[j] << endl;
}
cout << "\n";
}
//reset position in file
resetPos(flix);
//get data from file and put into respective variables
while(getline(flix, line)){
flix >> personNum >> movie >> rating;
cout << personNum << ' ' << movie << ' ' << rating << endl;
//changes the char into an int
movieNum = getMovieNum(movie);
person[personNum].movieRate[movieNum] = rating;
}
//reset position in file
resetPos(flix);
//input ratings into movie array
for(int i = 0; i < distinctCount; i++){
for(int j = 0; j < NUMBER_OF_MOVIES; j++){
cout << i + 1 << ' ' << person[i].movieRate[j] << endl;
flick << i + 1 << ' ' << person[i].movieRate[j] << endl;
}
}
//write data to text file
//??
flick.close();
//free memory
delete[] person;
system("pause");
return 0;
}
int tokenize(string line){
string myText(line);
istringstream iss(myText);
string token;
getline(iss, token, ' ');
int strInt = atoi(token.c_str());
return strInt;
}
int getMovieNum(char movie){
int movieNum = 0;
switch(movie){
case 'A':
movieNum = 1;
break;
case 'B':
movieNum = 2;
break;
case 'C':
movieNum = 3;
break;
case 'D':
movieNum = 4;
break;
case 'E':
movieNum = 5;
break;
case 'F':
movieNum = 6;
break;
default:
movieNum = 0;
break;
}
return movieNum;
}
void resetPos(istream& flix){
flix.clear();
flix.seekg(0);
}
I also apologize in advance if there are noobish mistakes here.
I think the problem is somewhere in the while loop, that's where it keeps locking up. I spent hours on this and I can't figure out why it doesn't work. In the while loop, I'm trying to access every line of the file, snag the data from the line, take the movie char and turn it into an int, and then plug the data into the array within the object. When I did have it working, all the data was wrong too. Any input is highly appreciated. Thanks in advance.
You need to change a little in your program and i'l paste only the changed part.
Somewhere after you reset the person[].movieRate[] to zero,you have written this while loop
resetPos(flix);
int k = NUMBER_OF_MOVIES + 2; //this is the variable that i have declared
//get data from file and put into respective variables
while(k){ //do you see that instead of getline() i have used the variable k. i'l tell you why later
flix >> personNum >> movie >> rating;
//personNum = tokenize(line,1);
cout << personNum << ' ' << movie << ' ' << rating << endl;
//changes the char into an int
movieNum = getMovieNum(movie);
person[personNum - 1].movieRate[movieNum] = rating; //this is personNum-1 and NOT personNum the most common mistake while indexing array.
k--;
}
this code seems to work as your criteria.
the reason that i removed getline() is, if u call getline then the get pointer position will be incremented. so after this you call flix >> something... , this reads the data from the second line. your first line 1 A 5 is lost. this was the cause of the trouble. change it n let me know.
Okay, let me try to give at least some idea of a simple starting point:
#include <iostream>
#include <iterator>
#include <vector>
#include <fstream>
struct rater {
std::vector<int> ratings;
rater() : ratings(6) {}
friend std::istream &operator>>(std::istream &is, rater &r) {
char movie;
is >> movie;
return is >> r.ratings[movie-'A'];
}
friend std::ostream &operator<<(std::ostream &os, rater const &r) {
for (int i=0; i<r.ratings.size(); i++) {
os << char(i + 'A') << ":" << r.ratings[i] << "\t";
}
return os;
}
};
int main() {
std::ifstream in("flix.txt");
std::vector<rater> ratings(5);
int i;
while (in >> i)
in >> ratings[i-1];
i=1;
for (auto r : ratings)
std::cout << i++ << "-> " << r << "\n";
}
Here's a bit of a clean up. It uses std::map to keep track of the Person and Movie keys, which is more flexible as textual strings of any kind (sans whitespace) can be used. You've added a comment saying you specifically want to list movies people didn't rate in their outputs - that can be done by using a std::set and ensuring each movie name encountered is inserted, then using an iteration over the set to guide lookups in each person's ratings: left as an exercise.
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <map>
using namespace std;
typedef std::map<std::string, int> Movie_Ratings;
typedef std::map<std::string, Movie_Ratings> Persons_Movie_ratings;
int main()
{
if (!ifstream flix("flix.txt"))
{
std::cerr << "error opening input\n";
exit(1);
}
if (!ofstream flick("flix1.txt"))
{
std::cerr << "error opening output\n";
exit(1);
}
Persons_Movie_Ratings ratings;
std::string line;
while (getline(flix, line))
{
istringstream iss(line);
string person, movie;
int rating;
if (line >> person >> movie >> rating)
ratings[person][movie] = rating;
}
// input ratings into movie array
for (Persons_Movie_Ratings::const_iterator i = ratings.begin();
i != ratings.end(); ++i)
{
for (Movie_Ratings::const_iterator j = i->second.begin();
j != i->second.end(); ++j)
{
cout << i->first << ' ' << j->second << endl;
flick << i->first << ' ' << j->second << endl;
}
}
system("pause");
}
Related
I'm trying to complete a program that reads from a file and calculates the GPA. Basically there are 16 sets of data with 3 types in every set - name, grades, and extra points.
Example text:
Bugs Bunny
A B+ B A- B B C+ A B A-
100
The problem I am getting is at the middle part of the string, when taking in the grades. I am trying to read the entire line of grades, then read each grade itself, like "A" then "B+". Basically read "A", the value is 3, add it to an accumulator, then move to the next letter grade until the newline character is reached.
I thought of using .get but that's for taking in values. I don't really understand how to process the grades from the string. I know a loop is used, however.
struct infoTaker
{
string theirName;
string theirGrade;
double theirDonation;
int totalValue;
};
int main( )
{
double donation;
char letter;
ifstream file;
string fullName, actualGrade, substring;
file.open("F://Yes/thing.txt");
for ( int i = 0; i < 16; i ++){
getline( file, fullName ); // getting the names
infoTaker person;
person.theirName = fullName;
cout << person.theirName << endl; // end of names section
getline(file, actualGrade); // gettting the entire line
person.theirGrade = actualGrade; // the string of grades
cout << letter << endl; // Don't know what to do here
file >> donation;
file.ignore( 3 , '\n');
person.theirDonation = donation;
cout << person.theirGrade << endl;
cout << person.theirDonation << endl;
double convertDoodahs = person.theirDonation / 2.0;
}
}
This is one way to do it by adding the contents you read in a file, or you can also just read that certain line of grades. Im guessing this will be more useful because you can then later retrieve the name and other info.
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
int main(){
std::vector<std::string> vec;
std::string temp;
std::string grades;
std::ifstream input("test.txt");
//add them to vector, and access them later
while(getline(input, temp)) vec.push_back(temp);
//read the grades and seperate them
std::stringstream ss(vec[1]);
while(ss >> grades){
std::cout << grades << "\n";
}
}
sample txt file
Bugs Bunny
A B C D+
100
output
A
B
C
D+
#include<iostream>
#include<string>
using namespace std;
int convert(char a,char b='\0')
{
int result = 0;
if(b == '\0')
{
switch(a)
{
case 'A':
result = 9;
break;
case 'B':
result = 9;
break;
case 'C':
result = 9;
break;
}
}else
{
switch(a)
{
case 'A':
if(b=='+')
result = 10;
else
{
result = 8;
}
break;
case 'B':
if(b=='+')
result = 10;
else
{
result = 8;
}
break;
case 'C':
if(b=='+')
result = 10;
else
{
result = 8;
}
break;
}
}
return result;
}
int getSum(string g)
{
int ans = 0;
int l = g.length();
for(int i=0;i<l;)
{
char a = g[i++],b='\0';
if(g[i]=='+'||g[i]=='-')
{
b = g[i++];
}
ans+=convert(a,b);
i++;
}
return ans;
}
int main()
{
string g = "A B+ B A- B B C+ A B A-";
int sum = getSum(g);
}
try this...
I want to write a program that finds a word that the user entered I think my solution is right but when I Run it, the program shows nothing in the console
anybody can fix it?
int main()
{
char sen[200],del[200],maybedel[200];
cout<<"enter sentence :"<<endl;
cin.getline(sen,200);
cout<<"which word do you want to delete ?";
cin.getline(del,200);
int len = strlen(sen);
for(int i=0;i<=len;i++)
{
if(sen[i]==' ')
{
for(int j=i;j<=len;j++)
if(sen[j]==' ' || sen[j]=='\0')
for(int k=i+1,t=0;k<j;k++,t++)
maybedel[t]=sen[k];
if(maybedel==del)
cout<<maybedel;
}
}
return 0;
}
The line if(sen[i]==' '), line 12 of your code , prevents code from entering the block unless the sentence begins with (' ')!
I changed the code a bit and now it works fine.
char sen[200], del[200], maybedel[200];
cout << "enter sentence :" << endl;
cin.getline(sen, 200);
cout << "which word do you want to delete ?" << endl;
cin.getline(del, 200);
int len = strlen(sen);
int t = 0;
for(int i = 0; i <= len; i++) {
if(sen[i] == ' ' || sen[i] == '\0') {
maybedel[t] = '\0';
t = 0;
if(strcmp(del,maybedel)==0) {
cout << maybedel << endl;
}
}
else
{
maybedel[t] = sen[i];
t++;
}
}
The major reason for no output is
if (maybedel == del) // <<< this will *never* be true
cout << maybedel; // will never run
Since comparing "strings" in arrays needs help from std::strcmp(maybedel,del) == 0 would be better.
UPDATE:
Another attack method is to avoid raw loops and utilize the STL to your favor. Here's a more robust solution:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
using namespace std;
int main() {
cout << "enter sentence :\n";
string sen;
if (!getline(cin, sen)) throw std::runtime_error("Unable to read sentence");
cout << "which word do you want to delete ? ";
string del;
if (!(cin >> del)) throw std::runtime_error("Unable to read delete word");
istringstream stream_sen(sen);
vector<string> arrayofkeptwords;
remove_copy_if(istream_iterator<string>(stream_sen), istream_iterator<string>(),
back_inserter(arrayofkeptwords),
[&del](auto const &maybedel) { return maybedel == del; });
copy(begin(arrayofkeptwords), end(arrayofkeptwords),
ostream_iterator<string>(cout, " "));
cout << '\n';
}
players.txt
2
Zlatan
Ibrahimovic
1981
4
20130110
20130117
20130122
20130208
Yohan
Cabaye
1986
1
20130301
Main.cpp
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
ifstream pFile("players.txt");
int numberOfPlayers;
string firstName;
string lastName;
int birthYear;
int numberOfMatches = 0;
string *matchDates = NULL;
matchDates = new string[];
while (pFile >> numberOfPlayers >> firstName >> lastName >> birthYear >> numberOfMatches >> matchDates)
{
for(int i = 0; i < numberOfPlayers; i++)
{
cout << firstName << endl;
cout << lastName << endl;
cout << birthYear << endl;
for(int i = 0; i < numberOfMatches; i++)
{
cout << matchDates[i] << endl;
}
}
}
delete[] matchDates;
getchar();
return 0;
}
So I want to import data from a textfile, e.g. soccer players as above or anything else, like hockey players etc. The point is to be able to use this code for all kind of sports aka it's not set to like 12 players max, amount of players should be dynamic. Well I'm already stuck here with what I thought was a dynamic array (matchDates) but I've been told that it's not and is still a static array.
matchDates should also be dynamic because some players could've 20 mathcdates, another could have five, another three and so on. In my example zlatan has four and youhan one.
Well my problem appear on line 20, posted below:
while (pFile >> numberOfPlayers >> firstName >> lastName >> birthYear >> numberOfMatches >> matchDates)
Error message when I hover over the bolded ">>" (which is underlined with red in VS)
Error no operator ">>" matches these operands
operand types are: std::basic_istream> >> std::string *
I want to print out all matchdates but it doesn't work and I'm very sure it's something to do with matchDates.
Thanks in advance and regards Adam
Use C++ class for player, stop using new and override stream operator.
See the code in action here
#include <iostream>
#include <string>
#include <deque>
#include <fstream>
#include <algorithm>
#include <iterator>
using namespace std;
class Player
{
public:
Player() : firstName(""), lastName(""), birthYear(0){}
~Player() {}
//copy ctor by default
// Operator Overloaders
friend ostream &operator <<(ostream &output, const Player p);
friend istream &operator >>(istream &input, Player &p);
private:
string firstName;
string lastName;
int birthYear;
deque<string> matchDates;
};
ostream& operator <<( ostream& output, const Player p )
{
output << p.firstName << " " << p.lastName << " etc ...";
return output;
}
istream& operator >>( istream& input, Player &p )
{
input >> p.firstName;
input >> p.lastName;
input >> p.birthYear;
int nbMatch = 0; input >> nbMatch;
for(int i = 0 ; i < nbMatch ; ++i) {
string match_date; input >> match_date;
p.matchDates.push_back(match_date);
}
return input;
}//*/
int main()
{
//ifstream pFile("players.txt");
int numberOfPlayers;
deque<Player> players;
cin >> numberOfPlayers; int i = 0;
while( i < numberOfPlayers)
{
Player p;
cin >> p;
players.push_back(p);
i++;
}
std::ostream_iterator< Player > output( cout, "\n" );
cout << "What we pushed into our deque: ";
copy( players.begin(), players.end(), output );
getchar();
return 0;
}
The Problem
This is the error Clang gives me:
error: invalid operands to binary expression ('istream' and 'string *')
Then it goes on to list the various overloads of operator>>() and why a right-hand operand of type std::string* cannot convert to respective right-hand types. This is expected because there are no overloads of operator>>() that take a pointer or array of that type.
Solution
When reading into an array, you normally read into "temporary" objects and copy that to the array. For example:
#include <iostream>
int main()
{
int array[5];
for (int i = 0, temp; i < 5 && std::cin >> temp; ++i)
{
array[i] = temp;
}
}
But in your case, you initialized your array with the following line which I assume to be an attempt to create an indefinitely-sized array:
matchDates = new string[];
I don't know about Visual Studio, but on Clang I got the following error:
Error(s):
error: expected expression
int* j = new int[];
^
1 error generated
Dynamically-sized arrays are not possible in C++. If you need an array that will grow in size, consider using a std::vector. You would need to call push_back() to insert elements.
You can put things at one line to ease the code for your eye but don't over do it. Take a 'record' as a one record, so you can say.
An array doesn't have the >> operator.
Would go for user 0x499602D2 his answer but I may not upvote nor comment yet, so I put it here as I already answered. ;)
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
ifstream pFile( "players.txt" );
int numberOfPlayers;
string firstName;
string lastName;
int birthYear;
int numberOfMatches = 0;
while( pFile >> numberOfPlayers )
{
for( int i = 0; i < numberOfPlayers; i++ )
{
pFile >> firstName >> lastName >> birthYear >> numberOfMatches;
cout << firstName << endl;
cout << lastName << endl;
cout << birthYear << endl;
for( int i = 0; i < numberOfMatches; i++ )
{
string date;
pFile >> date;
cout << date << endl;
}
}
}
getchar();
return 0;
}
To maintain the data you can createa a struct (or class). The second while loop is just to print out while the first gets the data.
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct Player
{
string firstName;
string lastName;
int birthYear;
std::vector<string> matchDates;
};
int main()
{
ifstream pFile( "players.txt" );
int numberOfPlayers;
int numberOfMatches = 0;
std::vector<Player> players;
// fill the vector players
while( pFile >> numberOfPlayers )
{
for( int i = 0; i < numberOfPlayers; i++ )
{
// create player struct and fill it
Player player;
pFile >> player.firstName >> player.lastName >> player.birthYear >> numberOfMatches;
for( int i = 0; i < numberOfMatches; i++ )
{
string date;
pFile >> date;
player.matchDates.push_back( date );
}
// add it to the vector
players.push_back( player );
}
}
// print out the values
std::vector<Player>::iterator iterPlayer = players.begin(),
endPlayer = players.end;
while( iterPlayer != endPlayer )
{
Player player = *iterPlayer;
cout << player.firstName << endl;
cout << player.lastName << endl;
cout << player.birthYear << endl;
std::vector<string>::iterator iterDates = player.matchDates.begin(),
endDates = player.matchDates.end;
while( iterDates != endDates )
{
string date = *iterDates;
cout << date << endl;
}
}
getchar();
return 0;
}
I am trying to read the two words "kelly 1000" in the text file "players", into vectors players and balances respectively. Don't know why it's not working?
string name = "kelly";
int main()
{
int num =0;
vector<string> players;
vector<int> balances;
ifstream input_file("players.txt");
while(!input_file.eof())
{
input_file >> players[num];
input_file >> balances[num];
num++;
}
for(size_t i = 0; i=players.size(); i++)
{
if(name==players[i])
cout << "Welcome " << name << ", your current balance is " << balances[i] << "$." << endl;
else
break;
}
With operator[] you can only access existing elements. Going out of bounds invokes undefined behaviour. Your vectors are empty and you need to use push_back method to add elements to them.
Second problem is while (!file.eof()) anti-pattern. It'll typicaly loop one to many times because the read of last record doesn't neccesarily trigger eof. When reading from streams, always check whether input succeeded before you make use of values read. That's typicaly done by using operator>> inside loop condition.
string temp_s;
int temp_i;
while (input_file >> temp_s >> temp_i) {
players.push_back(temp_s);
balances.push_back(temp_i);
}
This way the loop stops if operator>> fails.
//Hope this is something you want dear.Enjoy
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
string name = "kelly";
int main()
{
int num =0;
string tempname;
int tempbalance;
vector<string> players;
vector<int> balances;
ifstream input_file("players.txt");
while(!input_file.eof())
{ input_file>>tempname;
input_file>>tempbalance;
players.push_back(tempname);
balances.push_back(tempbalance);
}
for(size_t i = 0; i<players.size(); i++)
{
if(name==players.at(i))
cout<< "Welcome " << name << ", your current balance is " << balances.at(i)<< "$." << endl;
}
return 0;
}
I tried earlier to use a for loop to put data in but became too problematic. So I tried to use a while loop, it works but when I tried to debug it it continued to put -858993460 into every slot. The .dat file is in the right spot and opens.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct record
{
int item_id;
string item_type;
float item_price;
int num_stock;
string item_title;
string item_author;
int year_published;
};
void read_all_records(record records[], int &valid_entries);
int num_inventory_of_type(record records[], string type, int &valid_entries);
const int max_array = 100;
int main()
{
int valid_entries = 0;
record records[max_array];
read_all_records(records, valid_entries);
cout << "Stock Report" << endl;
cout << "------------" << endl;
int book = num_inventory_of_type(records, "book", valid_entries);
cout << "Book's In Stock: " << book << endl;
int cd = num_inventory_of_type(records, "cd", valid_entries);
cout << "CD's In Stock: " << cd << endl;
int dvd = num_inventory_of_type(records, "dvd", valid_entries);
cout << "DVD's In Stock: " << dvd << endl;
return 0;
}
void read_all_records(record records[], int &valid_entries)
{
ifstream invfile;
invfile.open("inventory.dat");
if (!invfile.is_open())
{
cout<<"file open failed";
exit(1);
}
while(invfile.good() && valid_entries < max_array)
{
invfile >> records[valid_entries].item_id >> records[valid_entries].item_type
>> records[valid_entries].item_price >> records[valid_entries].num_stock
>> records[valid_entries].item_title >> records[valid_entries].item_author
>> records[valid_entries].year_published;
if(!invfile.good())
break;
valid_entries++;
}
invfile.close();
}
int num_inventory_of_type(record records[], string type, int &valid_entries)
{
int count = 0;
int holder = 0;
for (int count = 0; count<valid_entries; count++);
{
if (records[count].item_type == type)
{
holder+=records[count].num_stock;
}
}
return holder;
}
the .dat file is
123456
book
69.99
16
Problem_Solving_With_C++
Walter_Savitch
2011
123457
cd
9.99
32
Sigh_No_More
Mumford_and_Sons
2010
123458
dvd
17.99
15
Red_State
Kevin_Smith
2011
123459
cd
9.99
16
The_Church_Of_Rock_And_Roll
Foxy_Shazam
2012
123460
dvd
59.99
10
The_Walking_Dead_Season_1
Robert_Kirkman
2011
all are on new lines, no spaces.
Basically it should start, run the read_all_records function and put the .dat data into the array. However, I put the cout << records[count].item_id; in the while loop just to see if the data was actually going in, and I get -858993460 each time. After that it should run the next function 3 times and return how many of each books there are.
You used the integer type int on item_price. invfile >> records[count].item_price will then only extract 69 instead of 69.99, thus resulting in a error when you try to extract the year_published.
Use a float or double instead.
struct record
{
int item_id;
string item_type;
float item_price;
int num_stock;
string item_title;
string item_author;
int year_published;
};
/* skipped identical lines */
while(invfile.good() && count < max_array)
{
invfile >> records[count].item_id >> records[count].item_type
>> records[count].item_price >> records[count].num_stock
>> records[count].item_title >> records[count].item_author
>> records[count].year_published;
cout << records[count].item_price << endl;
if(!invfile.good())
break;
cout << records[count].item_id << endl;
count++;
}
invfile.close();
Note that you have an extra semicolon in for (int count = 0; count<max_array; count++);. I guess you didn't intend this, so remove it.
This isn't a direct answer to the problem, but perhaps it will go away after a refactoring:
std::istream& operator>>(std::istream& is, record& r) {
return is >> r.item_id >> r.item_type >> … >> r.year_published;
}
int main () {
if (std::ifstream invfile("inventory.dat")) {
std::vector<record> records((std::istream_iterator<record>(invfile)),
std::istream_iterator<record>());
num_inventory_of_type(records, "dvd");
num_inventory_of_type(records, "cd");
num_inventory_of_type(records, "book");
}
}
If you still want to print out each record as you read it, the code can be rearranged as follows:
std::vector<record> records;
for (std::istream_iterator<record> i(invfile);
i != std::istream_iterator<record>(); ++i)
{
records.push_back(*i);
std::cout << i->item_id << "\n";
}
You need to change int item_price; to a float so -> float item_price;
and as mentioned above you need to swap the count++; and cout << records[count].item_id line.
After these two changes it will work properly.
struct record
{
int item_id;
string item_type;
float item_price; // <--- Needs to be a float
int num_stock;
string item_title;
string item_author;
int year_published;
};
// This order is required because you are storing in the current 'count' record and then you need to print it. Then increment the count to store the next record
cout << records[count].item_id;
count++;