Error "request for member 'nombreIntr' in 'jugadorActual'" - c++

I'm trying to make a class for the player, then the object and the idea is to make the bottom cin save what he writes in the variable "name", but when executing it says that the variable "intr" has not been declared.
class jugador{
public:
string nombreIntr(string intr);
private:
string nombre;
};
string jugador::nombreIntr(string intr){
nombre = intr;
return nombre;
}
main(){
jugador jugadorActual();
//G
cout << "G: Bienvenido Jugador!\n\nG: Me dirias tu nombre?\n\n";
//Introducir Nombre
cin >> jugadorActual.nombreIntr(intr);
}

cin >> jugadorActual.nombreIntr(intr);
This says to take data from cin and put it into whatever nombreIntr returns. Since nombreIntr returns a temporary object (a copy of the nombre member), this is rather ineffective (even if it had compiled).
The simplest approach to what you want to do is probably to break this statement into its two conceptual parts: get a value from cin and store that value in jugadorActual.
cout << "G: Bienvenido Jugador!\n\nG: Me dirias tu nombre?\n\n";
std::string nombre;
cin >> nombre; // Get the value.
jugadorActual.nombreIntr(nombre); // Store the value.
There are ways to combine this into one step, but the ways I'm thinking of would require expanding the jugador interface, so not as simple as the above.

Related

Difficulty adding an enumerated variable into a structure variable with the dot operator in C++?

Essentially, I have a structure of VideoGame statistics
like the following in my C++ program:
struct Game
{
string title;
genre this_genre;
int this_rank;
float time;
};
I also have defined the enumerated type genre as this:
enum genre {FPS, MOBA, ROLEPLAY};
I have declared an abstract structure variable called NewGame
Game NewGame
My goal is the have the user define the members of the structure variable NewGame from standard input. I have no problem doing that for the other members of the structure, but I cannot seem to figure out how to get the user to store an enumerator in the enumerated member of the structure.
cout << "Enter the title for your game: ";
getline(cin, NewGame.title);
cout << "Enter the rank of your game: ";
cin >> NewGame.this_rank;
// The genre currently breaks the code:
cout << "Enter the genre of the game: ";
cin >> NewGame.this_genre;
cout << "Enter the time (days) spent playing your game: ";
cin >> NewGame.time;
I tried static casting it as an integer, but then I overloaded the insertion operator.
cin >> static_cast<int>(NewGame.this_genre); // doesn't work.
I want for the user to be able to provide values 0, 1, or 2, and have those respectively be assigned to FPS (0), MOBA (1), or ROLEPLAY (2).
What am I doing wrong? What am I not understanding?
You have to read into a temporary int and then use static_cast<genre> to get the enumeration value.
int value;
cin >> value;
NewGame.this_genre = static_cast<genre>(value);
You can "make your code work" with this:
cin >> reinterpret_cast<int&>(NewGame.this_genre); // bad
but don't do that, because it's undefined behavior to assign a value through such a type-punned reference.
Have the user input an integer, validate it, and then cast. The way you tried fails because you pass an rvalue to the insertion operator. static_cast<int> returns an integer, it doesn't transmogrify NewGame.this_genre into an integer for the type system.
int gen;
cin >> gen;
if(/*gen is valid*/)
NewGame.this_genre = static_cast<genre>(gen);

Memory management issue in c++

A very simple code with a weird issue. The code goes through fine but I can't seem to get the desired output. My getStock() and getQuantity() functions don't seem to work. When I debug the code, it says 'error reading the memory'. When the execution reaches s.dispP() the code crashes unexpectedly. Can't seem to find a solution for it. Kindly help. Thank you.
#include<iostream>
#include<conio.h>
using namespace std;
class Sale
{
class SaleItem
{
int stock, quantity;
public:
SaleItem(int pstock, int pquantity) : stock(pstock), quantity(pquantity)
{
}
int getStock()
{
return stock;
}
int getQuantity()
{
return quantity;
}
};
int sstock, squantity;
public:
SaleItem *si;
void addP()
{
cout << "Enter Stock: ";
cin >> sstock;
cout << "Enter Quantity: ";
cin >> squantity;
SaleItem *si = new SaleItem(sstock, squantity);
}
void dispP()
{
cout << si->getStock() << endl << si->getQuantity();
}
};
void main()
{
Sale s;
s.addP();
s.dispP();
_getch();
}
The error comes from the following method:
void addP() {
cout << "Enter Stock: ";
cin >> sstock;
cout << "Enter Quantity: ";
cin >> squantity;
SaleItem *si = new SaleItem(sstock, squantity);
}
Here the si is just a local variable and not the member variable you are thinking it is. To fix the issue, just prepend the si with a this-> or just use it without the this pointer.
void addP() {
cout << "Enter Stock: ";
cin >> sstock;
cout << "Enter Quantity: ";
cin >> squantity;
this->si = new SaleItem(sstock, squantity);
}
Alternative is to use a naming convention for member variables, e.g. prefix m_, _ or suffix _.
Although the correct modern C++ approach here is to not use raw pointers at all. Any memory you allocate with new must have delete called on it. And you have not called delete to deallocate the memory you allocated, and this causes a memory leak.
The modern C++ solution is to use std::unique_ptrs instead to automate memory management.
public:
std::unique_ptr<SaleItem> si;
void addP()
{
cout << "Enter Stock: ";
cin >> sstock;
cout << "Enter Quantity: ";
cin >> squantity;
this->si = std::make_unique<SaleItem>(sstock, squantity);
}
void dispP()
{
cout << si->getStock() << endl << si->getQuantity();
}
Note that you might not need to use smart pointers here at all. Simple objects might do. Have the knowledge of the options available at your disposal and use the best one :)
Here
SaleItem *si = new SaleItem(sstock, squantity);
you are not assigning the result of the new expression to the si field; instead, you created a local variable si (that shadows the field that has the same name) and initialized it with the result of the new expression.
The si field is remains uninitialized, and thus when you later try to use it you get a crash (actually, you are lucky, an uninitialized pointer may silently appear to work and overwrite unrelated memory).
To fix this, you have to change the new variable definition in an assignment; so, that line simply becomes
si = new SaleItem(sstock, squantity);
Notice that your class is leaking memory, as it calls new without a corresponding delete; the immediate fix here would be to use a smart pointer such as unique_ptr, but, unless you need a pointer for some other reason, here you should just have SaleItem as a "regular" (non-pointer) field inside Sale and forget about all memory management issues.
The line
SaleItem *si = new SaleItem(sstock, squantity);
introduces a local variable named si. It does not set the value of the member variable of the class. As a consequence, the member variable si remains uninitialized. Accessing such a variable causes undefined behavior.
You can use
si = new SaleItem(sstock, squantity);
to remove the particular problem you are facing but realize that your class is very fragile.
The member variables sstock and squantity seem to be intended for SaleItem but they are declared outside of that class. It's not clear whether that was from an error in copying and pasting code from you computer to the post, or the error exists on your computer too.
It's always a good idea to initialize all member variables of a class in the constructor. si can be initialized to nullptr in the constructor of the class.
You haven't shown why you need to use a pointer. If your class needs one object, use an object. If it needs a list of objects, use a std::vector of objects.
If, for some reason, you need to store a pointer in your class, you need to be aware of The Rule of Three and make sure to update your class accordingly.
You declared a local variable si in the addP() method which shadows the member variable si of the class Sale. Thereby the member variable si is not initialized and your subsequent reference to it causes a crash.
SaleItem *si;
void addP()
{
cout << "Enter Stock: ";
cin >> sstock;
cout << "Enter Quantity: ";
cin >> squantity;
SaleItem *si = new SaleItem(sstock, squantity);
}
At the last SaleItem *si = new SaleItem(sstock, squantity); you are creating another, function local SaleItem* si which holds the newly created object's address, and then it immediately goes out of scope.
Instead, you want your member si to be assigned with it, so another function can use it.
So, instead of declaring another si, just refer the member si.
SaleItem *si;
void addP()
{
cout << "Enter Stock: ";
cin >> sstock;
cout << "Enter Quantity: ";
cin >> squantity;
this->si = new SaleItem(sstock, squantity);
}
P.S.
If you are initializing the member si from within a function, and accessing it from yet another function, you can't be sure about the order of calls.
To save yourself from later headache because of initial garbage address in pointer si causing segfaults, I would suggest to have it initialized to nullptr :)
I am not very sure why you want to use si as a pointer to SaleItem?
Maybe I am missing something, but it doesn't seem to me necessary, unless you are trying to create a list of SaleItems (then I don't think you are implementing the class correctly, see below).
In any case, with that structure I would just go for
public:
SaleItem si(0,0);
void addP()
{
cout << "Enter Stock: ";
cin >> sstock;
si.stock=sstock
cout << "Enter Quantity: ";
cin >> squantity;
si.quantity=squantity;
}
void dispP()
{
cout << si.getStock() << endl << si.getQuantity();
}
However, if what you are trying to create is a class Sale that is a list of SaleItems then you need to approach things differently. In that case yes, you would have a pointer to an object SaleItem. I would understand that si is an array of elements of the type SaleItem. You then need to allocate memory for the array when you create it, which implies that you know beforehand the maximun number of elements this array will have. Then you can have an index and each time you add a new SaleItem to the array you do it according to this index, being careful not to go beyond the allocated maximum number of items.
If what you are looking to implement is a dynamic data structure that grows as you add elements, then depending on what particular one you choose to implement you will need to make use of pointers. For a example, you could have a pointer to the next SaleItem and a pointer to the previous one. Or alternatively, the pointer to the next SaleItem could be within the SaleItem definition. The point is that you will have to link them somewhere, somehow. If this is the case then I recommend you do some reading on data structures. You can try
http://www.cprogramming.com/algorithms-and-data-structures.html
https://www.tutorialspoint.com/cplusplus/cpp_data_structures.htm
https://www.tutorialspoint.com/data_structures_algorithms/data_structures_basics.htm
If that is what you are after, I hope that helps :)

Search through a 2D array and return the entire row

I am new to C++ and I am having a hard time figuring out how 2D arrays work.
I am making a program that takes a .txt file filled with "driver's license records" and reads them in, and then lets the user search through the "database" for for last name, age, or whether the driver is registered to vote (y/n).
A sample .txt file would look like this:
4
Chris Jones 19 Y 374122
Pat Smith 23 N 863901
Kyle Howard 31 Y 673911
Samantha Pratter 27 Y 874309
My main method is simply
int main(int argc, char* argv[])
{
Executive exec(argv[1]);
exec.run();
return (0);
}
Here is the code for my Executive class:
#include <iostream>
#include <fstream>
#include "Executive.h"
#include "DriversLicenseRecord.h"
using namespace std;
Executive::Executive(char* filename){
int n;
ifstream inp(filename);
inp >> n;
num_records=n;
DriversLicenseRecord** record = new DriversLicenseRecord*[n];
for(int i=0; i<n; i++){
record[i] = new DriversLicenseRecord(inp);
}
}
//here is where I am pretty much guessing
void Executive::run(){
int x=0;
do{
cout << "1: Query last name" << endl << "2: Query age range" << endl << "3: Query registered voters" << endl << "4: Quit" << endl;
cin >> x;
if(x==1){
string name;
cout << "Enter last name: ";
cin >> name;
/**for(int i=0; i<num_records; i++){
if(name==record[i]){
cout << record[i];
}
}*/
}
else if(x==2){
int max;
int min;
cout << "Enter age range: " << endl << "min: ";
cin >> min;
cout << "max: ";
cin >> max;
}
else if(x==3){
}
}while(x!=4);
}
And here is my DriversLicenseRecord class:
#include "DriversLicenseRecord.h"
using namespace std;
DriversLicenseRecord::DriversLicenseRecord(ifstream& inp){
inp >> first_name;
inp >> last_name;
inp >> age;
inp >> vote;
inp >> license;
}
Firstly I want to know if I'm reading in the values correctly, it is my understanding that it skips reading in white space, so the DriversLicenseRecord should be getting the correct values.
Secondly I have no idea how to search through this, and return the whole row.
Below is an example of output with a given .txt file:
1. Query last name
2. Query age range
3. Query registered voters
4. Quit
3 // user input
Chris Jones 19 Y 374122
Kyle Howard 31 Y 673911
Samantha Pratter 27 Y 874309
Just a small push in the right direction would be very helpful, I've been struggling with this problem all week and haven't made much progress.
Thank you!
There are a couple errors in your code, but first I'd like to say that there is (1) no need for a 2D array here and (2) you don't create a 2D array in Executive::Executive(). For (1): all you need in this task is an one-dimensional array (or container) of DriversLicenseRecord objects. Then, you can query the fields of individual objects and compare their values to the query to search for specific records. For (2), what you have created is simply an one-dimensional array of pointers to DriversLicenseRecord objects.
Here is where the errors appear.
Firstly, the variable records is local to the constructor. Once the c'tor returns, records will be destroyed. You won't be able to access it outside the constructor. Also, the memory you allocated will be lost, creating a memory leak.
Secondly, while creating the array is correct, iteration is not. Here's how you can iterate over the array and query the fields:
for(int i=0; i < num_records; i++){
// note the -> : because we're using a pointer, not the object itself
if(name == m_records[i]->first_name){
cout << m_records[i]->first_name;
// or, if you define operator<<(istream&, const DriversLicenseRecord&):
cout << *(m_records[i]);
}
Finally, why you had to use a dynamic array. Thing is, you don't know the number of entries until you read the file, and you can't create a variable length array other than with new, except inside a function as a local variable, but then see #1: it's lost on function exit. However, you could create a dynamic array of records, not pointers to records. For that, you need to supply a default constructor to DriversLicenseRecord, and then simply fill in the fields on the fly from the file. (Not the syntax you used with DriversLicenseRecord::DriversLIcenseRecord(istream&), that's not the default c'tor.)
Next, this is how I would go about this problem, using STL containers and algorithms.
1. Switch to std::vector, which has the benefit of being safer and more convenient to use.
2. I honestly disliked the idea of creating the D.L.R. class with an istream parameter. What you can do, if you want to use streams, is to define istream& operator>>(istream&, DriverLicenseRecord&) and then use the beautiful STL syntax like so:
std::istream& operator>>(std::istream& str, DriversLicenseRecord& rec)
{
std::string str;
str >> rec.first_name >> rec.last_name >> rec.age >> temp >> rec.license;
rec.can_vote = (temp == "Y");
return str;
}
Then some STL beauty:
class Executive {
typedef std::istream_iterator<DriversLicenseRecord> in_driver_it;
std::vector<DriversLicenseRecord> records;
public:
Executive(const std::string& file)
{
std::ifstream inp(file);
int n; inp >> n;
std::copy(in_driver_it(inp), in_driver_it(), std::back_inserter(records));
}
};
Same fot the output.
Long story short: here is the complete sample code using the standard library, which is not the shortest but simple on the other hand. Running out of space!
You can avoid using the 2D array.
Approach 1
Use a vector<string> instead. Makes things much simpler to handle.
Read from the text file and store each line as a string in the vector.
Then when you are searching for a particular query string all you need to do is process each string in the vector.
So for reading from the input text file you would do something like this:
ifstream inpFile(myfile.txt);
string line;
vector<string> myInpFile;
while(getline(inpFile,line))
{
myInpFile.push_back(line);
}
I'll leave the implementation of the string search as an exercise for you. Take a look at how to process strings here
Approach 2
Alternatively you can just read off what you need straight off the file into a string and then search the string. You wouldn't need DriversLicenseRecord in memory at all. But that's not what your TA appears to be looking for.

C++ cin input stored directly to pass by reference variable - dangerous?

Is it dangerous to have cin input directly assigned to a double variable that is passed by reference? If so, what measures can I take to defend against dangerous input - aside from not passing by reference.
Example below:
void samplefunction(double &var1, double &var2)
{
cout << "Enter something: ";
cin >> var1;
cout << endl;
cout << "Enter something: ";
cin >> var2;
}
The short answer, is no, as the cin >> operator will only read as much data as it requires to fill the type. The rest is discarded until the next whitespace. You may not get correct values, for example if someone feeds in "ABCDEF" instead of "1.0," but you won't have to worry about a buffer overflow.

Combining Two Strings into One Variable in C++

I am en process of writing a simple program that assigns given student names into groups of whatever interval requested. Currently, I am focusing on the function that reads the name of the students.
Here is the code:
class student
{
public:
string nameFirst;
string nameLast;
};
student typeName()
{
student foo;
cout << "Type in a student's first name: ";
cin >> foo.nameFirst;
cout << "Type in that student's last name: ";
cin >> foo.nameLast;
cout << "\n";
return foo;
}
Since I cannot use getline(), I am forced to create two strings, one for each section of the student's full name. How can I rewrite this code to allow for it to take the full name without creating two variables and without using getline()? Or, if such isn't possible, how can I use a method within the class to combine the two strings into one?
You can just use
cin >> foo.nameFirst >> foo.nameLast;
cin >> will parse stops at white spaces, so you can just input the full name in one line split by space like James Bond.
To combine two strings into one:
string fullName = foo.nameFirst + " " + foo.nameLast;