std::cin function not acting as expected? [duplicate] - c++

This question already has answers here:
c++ change function's variable argument
(2 answers)
Closed 2 years ago.
I created a function which takes a string for a message and an input value (primarily an integer, at least in this case) so I can print a message and take an input in a single function instead of two lines of code. Here is the snippet:
main.h
void input(std::string msg, int choice) {
std::cout << msg;
std::cin >> choice;
}
However, when passing the function in my main function, it doesn't perform the same way this would:
main.cpp (working code with expected result)
int initial_choice;
std::cout << "Invalid input provided. Please try again: ";
std::cin >> initial_choice;
main.cpp (working code with unexpected result)
int initial_choice;
input("Invalid input provided. Please try again: ", initial_choice);
When it comes to the snippet with the expected result, my switch case function properly detects the input (in this case it is initial_choice) as a valid integer. For example, entering 1, 2, or 3 will work with case 1:, case 2:, and case 3:. However, the snippet with the unexpected result doesn't detect any of the three valid numbers in my switch case function, instead they all run the code under the default case.

This has nothing to do with cin, cout, switch statements, etc.
As user202729 has pointed out, it is a simple matter of function parameter-passing.
C++ is not Fortran III; by default, parameters to functions are passed by value, not by reference. This means that if within a function you change the value of one of its parameters, this change will only be in effect within the function; the change will not be reflected to the caller.
So, your std::cin >> choice; statement works perfectly well, and it stores the value entered by the user in your choice variable. However, this value forever ceases to exist once the function ends, and it is never reflected back to the caller, which in this case is the initial_choice variable of your main() method.
To fix this, you have two options:
Pass the variable by reference, so that the function can modify it.
Do not pass the variable at all; instead, have the function return the value; that's generally what functions are for.

Related

Why do we use functions that return a data structure in C++? [duplicate]

This question already has answers here:
Which is more efficient: Return a value vs. Pass by reference?
(7 answers)
Closed 2 years ago.
I have been learning C++ and came across a function, but the return type was a vector.
Here is the code:
vector<Name> inputNames() {
ifstream fin("names.txt");
string word;
vector<Name> namelist;
while (!fin.eof()) {
Name name;
fin >> name.first_name;
fin >> name.last_name;
namelist.push_back(name);
}
return namelist;
}
name is part of a struct defined as:
struct Name {
string first_name;
string last_name;
bool operator<(const Name& d) const {
return last_name > d.last_name;
}
void display() {
cout << first_name << " " << last_name << endl;
}
};
What is the purpose of using vector< Name>inputName()? What is it doing?
And why can I just not create a void function and pass a vector through it?
I.e.:
void input(vector<Name>&v){
ifstream fin("names.txt");
string word;
while (!fin.eof()) {
Name name;
fin >> name.first_name;
fin >> name.last_name;
v.push_back(name);
}
}
Your question is basically: Do I return by value or do I use an output argument?
The general consensus in the community is to return by value, especially from C++17 on with guaranteed copy elision. Although, I also recommend it C++11 onwards. If you use an older version, please upgrade.
We consider the first snippet more readable and understandable and even more performant.
From a callers perspective:
std::vector<Name> names = inputNames();
It's clear that inputNames returns you some values without changing the existing state of the program, assuming you don't use global variables (which you actually do with cin).
The second code would be called the following way:
std::vector<Name> names;
// Other code
inputNames(names);
This raises a lot of questions:
does inputNames use the names as input or does it extend it?
if there are values in names, what does the function do with it?
does the function have a return value to indicate success?
It used to be good practice when computers were slow and compilers had troubles optimizing, though, at this point, don't use it for output arguments.
When do you use the last style: if you want an in-out argument. In this case, if you intend to append, the vector already had data, and that actually makes sense.
This basically mirrors the mathematical definition of a function as...
...a relation that associates an input to a single output.
While you could write void functions that modify their parameters, this has disadvantages:
Expression of intent. Consider a function taking multiple parameters. Which ones are input, which ones are output?
Clarity of purpose. A function modifying multiple values at once is usually (not always) attempting to do too many things at once. Focussing on one return value per function helps with keeping your program logic under control.
RAII. You can't use a void function to initialize a variable, meaning you would have to declare that variable first (initialized to some "default" value), then initialize it to the desired value.
There are languages that work without return values, using "out parameters" instead. You can do it this way in C++ as well. But all in all, using return values as the one output of a function helps the structure of your program.
vector<Name> is the return value of the method. It will create a new object with a vector of the structs.
Your implementation is called "call by reference". It will pass the pointer to an existing vector. As a example, with the call by the reference implementation, you could call input(vector<Name>&v) multiple times and your preexisting vector will have multiple times the content. If you would to it with the vector return value, it would always create a new object with only one iteration of data.

Returning input in C++

I'm very new to C++ and was wondering if there was a way to return integer input from a function directly without storing it in a variable.
To be more clear:
#include <iostream>
int function()
{
std::cin >> (return function here???)
}
int main()
{
int number = function()
std::cout << number
return 0;
}
Thanks for any help.
if there was a way to return integer input from a function directly without storing it in a variable.
There is not. All standard input interfaces take an object argument which they modify rather than return the resulting value1.
A possible reason for this design is that it is very typical for input to be bad. Only way to avoid returning an int from a function declared to return int is to throw (or terminate the process, but that would be silly). And input error is perhaps considered so non-exceptional that using exceptions for control flow of input handling may be considered inappropriate. This is just my reasoning, not an authoritative explanation for the design choice.
If you fix your function to be correct, with the variable that is necessary and checking for errors, then you can use that function to do exactly that:
return function();
1 With the exception of std::istream::get() and the corresponding C style std::getc and std::fgetc which you can use to extract a single character that they return directly.

Why can't I read a value from the user and make it a constant?

After inputting the following code, I would get an error.
const int quantity;
cout << "How much spacing do you want in-between the frames? " ;
cin >> quantity;
error: uninitialised const 'quantity'[-fpermissive]
error: ambiguous overload for 'operator>>'
This does not happen if I just use the type int
int quantity;
cout << "How much spacing do you want in-between the frames? " ;
cin >> quantity;
Which compiles without a problem. I'm new to C++ so I'd just like to know why this is.
If you define the variable as
const int quantity;
you're saying "I'd like an int called quantity, and under no circumstances do I want its value to ever change." As a result, if you then write
cin >> quantity;
the compiler says something to the effect of "wait - you want me to change the value of quantity by replacing it with whatever the user entered, but earlier you said that you never wanted me to change it!"
My sense is that you wanted to make it so that after you give an initial value to quantity that value never changes, but with const variables that initial value needs to be set when the variable is created. You could therefore try something like this:
const int quantity = readValue();
for some function readValue() that reads and returns an int value. That way, the compiler sees that quantity is given a fixed value, it knows that the value never changes, and you never try to directly cin into the value of quantity.
For a more technical perspective on the errors you got: when the compiler read
const int quantity;
without any value assigned to it, it reported an error because it's unusual to create a constant without giving it a value. (I can see from your code that you meant to give it a value, but the way you did it wasn't legal and the compiler didn't piece the two things together). The second error about operator >> resulted because none of the different ways that you can read something from cin (read a string, read an int, read a char, etc.) applied, since each of them assumed that they can get a mutable (modifiable) view of the value in question. Again, both of these issues stem from the fact that the compiler saw your code as two separate independent errors rather than one large "oops, that's not how const works" error.
You can initialize a const local variable only once, at the moment it's declared. Your example looks like it couldn't possibly work, but it's simple if you add a level of indirection.
int ReadAnInt()
{
int temp;
cin >> temp;
return temp;
}
const int quantity = ReadAnInt();
The const qualifier means that the variable is immutable and you cannot change its value. The first error is telling you that the variable is uninitialize.
cin allows you to assign a value to a variable, which immediately contradicts your const qualifier.
You must initialise quantity the moment you declare it. Furthermore, you can't assign a value to it later on; after all, it is constant.
First you put the same code in both of the boxes.
I admit you put the const symbol in the first source.
Second a const must be initialized at declaration in C++.
Thus you should put the code as following
int value;
cin >> value;
const int my_num = value;

C++ (Type error in Switch statement) [duplicate]

This question already has answers here:
Why can't the switch statement be applied to strings?
(22 answers)
Closed 6 years ago.
Ok, so I got an error when I tried to print something based on the user's input. Pretty standard stuff, right? So, if the program would have worked correctly, the user would have entered six words or phrases that would be stored in the string named PhrasesAndWords. Then, each part of the array would have been tested, by creating a while-loop, using the counter as the index in the switch statement. Well, apparently, this didn't work, because it wasn't a constant expression, or a constexpr. The variable can't be a constant expression, though, since that would result in an infinite loop. By the way, here is the error:
C:\Users\henry\Desktop\NotTheActualPathForThisProject\main.cpp|34|error: switch quantity not an integer|
Aaand here's the code I wrote (I have gotten rid of irrelevant variables and such, though):
int main() {
string phrasesAndWords[6];
cin >> phrasesAndWords[0] >> phrasesAndWords[1] >> phrasesAndWords[2] >> phrasesAndWords[3] >> phrasesAndWords[4] >> phrasesAndWords[5]; // Recieve input
int counter = 0;
while (counter < 6) {
switch(phrasesAndWords[counter]) {
case "RandomString":
print("That sure was quite random. \n")
default:
print("I don't understaahnd... \n")
};
counter++;
};
};
Switch in C++ doesn`t work with strings. Cosider mapping the expected cases with integers.
The expression used in a switch statement must have an integral or enumerated type, or be of a class type in which the class has a single conversion function to an integral or enumerated type.

Very basic C++ program issue - Invalid operands to binary expression

I just started teaching myself C++ on the Mac, and I have run into some issues.
I have written some code that allows the user to enter a number and when they hit enter, the number will be returned to the user.
Xcode will absolutely not have it though. Every time I try to run my code, it says that there is an issue with the cin>> thisisanumber; code.
The error comes up and says
Invalid operands to binary expression. Error is on line 10.
What am I doing wrong?
#include <iostream>
using namespace std;
int main()
{
int thisisanumber();
cout << "Please enter a number: ";
cin >> thisisanumber;
cin.ignore();
cout << "You entered"<< thisisanumber <<"\n";
cin.get();
}
You've fallen victim to the most vexing parse, which means thisisanumber is being treated as a function. Take out the parentheses and you should be fine:
int thisisanumber;
Also consider making it a bit more readable, such as thisIsANumber. If you ever need to know it, thisIsANumber uses the camel-case naming convention.
Declare your variable without brackets, like
int thisisanumber;
With brackets, it is interpreted as a function, and a function can't be passed as a parameter to the >> operator.
Your problem is the so called most vexing parse. Basically everything, which could be parsed as a function declaration will be parsed as such. Therefore the compiler will interpret int thisisanumber(); as a declaration of a function thisisanumber taking zero arguments and returning an int. If you consider this behaviour the problems with cin>>thisisanumber; should be somewhat selfevident.
If you remove the parantheses, changing the variable declaration to int thisisanumber;, your program should behave like you'd expect it to with thisisanumber being a variable of type int.
You might however reconsider your naming conventions, thisisanumber isn't exactly readable. I would suggest going with this_is_a_number, thisIsANumber or ThisIsANumber.
int thisIsANumber;
try making it variable declaration because what you wrote has been interpreted as function.
delete () after thisisanumber, because () after thisisanumber means that it's a function, when it's not.