I want to use a helper method to perform an operation on a string. I would like the method to have two parameters: input and output. I think there is a scoping problem with how I want to solve the problem because when I try to display the output, it is blank. I've minimized my code so you can see the approach I am taking.
#include <iostream>
#include <string>
using namespace std;
void example_method(string in, string out);
int main(){
string input;
string output;
cin >> input;
example_method(input, output);
cout << "The result is: " << output << endl;
return 0;
}
void example_method(string in, string out){
out = in;
}
This minimization compiles and runs, but no matter what string I enter, the result is always blank.
What would be a better way to approach this problem?
You're passing the output variable to the function, which means a copy of it is being pushed onto the stack, and then the stack variable is being altered and never returned back to the original variable. What you want to do is pass a reference to the variable, Like so:
#include <iostream>
#include <string>
using namespace std;
void example_method(string in, string &out);
int main() {
string input = "";
string output = "";
cin >> input;
example_method(input, output);
cout << "The result is: " << output << endl;
return 0;
}
void example_method(string in, string &out) {
out = in;
}
Solution One: The string output will always be blank, with your code in its present form. This is because output is only being copied to another string instance when it is passed as an argument to example_method. out is the other string instance which takes the value of output. In other words what this means is that string out=output and nothing else. The code line out = in; only copies the value of in to out.
So, actually the value of output is not being acted upon at all.
In order to effect the value of output you have to pass its value by reference or in other words, you have to pass the address of output to example_method and that address is to be taken by a pointer. This way what ever changes are made via the pointer also effect the value of the output string outside the scope of the example_method.
The following code segment illustrates my point:
#include <iostream>
#include <string>
using namespace std;
void example_method(string another_string, string *pointer_to_output);
int main()
{
string input="I am a test string";
string output="";
//cout<<"Enter input string"<<endl;
//cin>>input;
example_method(input,&output);
cout<<"The result is: "<<output<<endl;
return 0;
}
void example_method(string another_string, string *pointer_to_output)
{
*pointer_to_output=another_string;
}
Solution two:
Why not simply change the return type of the example_method from void to std::string? By this approach void example_method(string in, string out); changes to string example_method(string in, string out); in the declaration above the main.
And the returned output string is put out on the screen using cout<<example_method(input, output);
This way you can simply return your output to the screen using cout.
This way your code works, it achieves what you are trying to do and there is no real need of using pointers.
THE MODIFIED CODE:
#include <string>
using namespace std;
string example_method(string in, string out);
int main(){
string input;
string output;
cin >> input;
cout<<example_method(input, output);
// cout << "The result is: " << output << endl;
return 0;
}
string example_method(string in, string out){
out = in;
return out;
}
Hope this helps!
When you pass a argument to a function, the value is copied into the parameter.
In your case, the function will operate on the copied value, and leave the original value untouched (in this case: empty).
This can be changed by declaring the parameter as a 'reference parameter'. This is done by adding a & to the type, like this: string& out. Then no local copy will be made, so the original value will be updated.
Full example:
#include <iostream>
#include <string>
void example_method(std::string in, std::string& out); // note the additional &
int main(){
std::string input;
std::string output;
std::cin >> input;
example_method(input, output);
std::cout << "The result is: " << output << std::endl;
return 0;
}
void example_method(std::string in, std::string& out){ // Note the additional &
out = in;
}
A different approach is to specify a return value for the function.
Your function is returning nothing (void), so you could return the resulting string instead. In that case, the output parameter is no longer required, but you'll have to assign the returned value to the output variable at the calling site.
A complete example:
#include <iostream>
#include <string>
std::string example_method(std::string in); // note that 'output' is gone
int main(){
std::string input;
std::cin >> input;
std::string output = example_method(input);
std::cout << "The result is: " << output << std::endl;
return 0;
}
std::string example_method(std::string in){
return in; // use 'return' to return a value.
}
Related
I am pretty new to c++ and I am trying to make a program that prints out the number based on user input. But when you add a , it breaks the code since it is not part of integers. What should I do?
I made a simplified code because I want to do more with the integers:
#include <iostream>
using namespace std;
int main(){
int player_input;
cout << "Insert the number" << endl;
cin >> player_input;
cout << player_input;
return 0; //the code doesn't work if you add a comma in cin when you run such as "3,500"
}
Read the input in as a string:
std::string input;
std::cin >> input;
Remove the commas, using the erase-remove idiom:
input.erase(std::remove(input.begin(), input.end(), ','), input.end());
which from C++20 you can write like this:
std::erase(input, ','); // C++20
Convert the string to an int:
int player_input = std::stoi(input);
With <locale>, you might do:
#include <locale>
template<typename T> class ThousandsSeparator : public std::numpunct<T> {
public:
ThousandsSeparator(T Separator) : m_Separator(Separator) {}
protected:
T do_thousands_sep() const override { return m_Separator; }
std::string do_grouping() const override { return "\03"; }
private:
T m_Separator;
};
int main() {
ThousandsSeparator<char> facet(',');
std::cin.imbue(std::locale(std::cin.getloc(), &facet));
int n;
std::cin >> n;
// ...
}
Demo
I think #Jarod42 is on the right general track, but I don't think there's usually a good reason to define your own locale for this task. In most cases you're doing to have a pre-defined locale you can use to do the job. For example, this code:
#include <locale>
#include <iostream>
int main() {
std::cin.imbue(std::locale("en-US"));
int i;
std::cin >> i;
std::cout << i << "\n";
}
...let's me enter a number like 3,400, and it'll print it back out as 3400, to show that it read all of that as a single number.
In a typical case, you'd probably want to simplify things even a bit further by using a nameless locale (std::cin.imbue(std::locale(""));, as this will normally at least try to use a locale matching the what the operating system is configured for, so it would support an American entering 3,400, and (for example) a German entering 3.400 instead.
I have a computer science assignment which requires me to have a separate function just to open the file, and then another function which will then process the data in that file and then some others to do some operations with that data. Anyways, I'm having trouble in how to be able to let other functions use that opened file. References with '&' or'*' are confusing me and I'm unsure if I have to use one or not, of course, though I'm pretty sure I'll have to pass at least something to the next function. The main intent when dealing with the file is to open it(openFile) and then have another function(getData) to sort the data into two different arrays. One for the names, and one for the amounts next to them. The file would be written as:
Johnson 6000
Brown 5000
Miller 4000
Duffy 2500
Robson 1800
My code is as follows:
'''
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;
void openFile();
void getData();
void computePercentages();
void sortVotes();
void display();
void displayWinner();
int main() {
openFile();
getData();
return 0;
}
void openFile(){
string fileName;
cout << "Enter the name of the file to open: ";
cin >> fileName;
ifstream file;
file.open(fileName.c_str());
}
void getData(){
int count = 0;
while(!file.eof()){
string names[count];
int votes[count];
cin >> names[count];
cin >> votes[count];
count ++;
}
}
'''
One way is to have openFile return the file stream object, then pass it to getData.
ifstream openFile()
{
string fileName;
cout << "Enter the name of the file to open: ";
cin >> fileName;
ifstream file(fileName);
return file;
}
void getData(ifstream &file)
{
int count = 0;
while(file){
string names[count];
int votes[count];
cin >> names[count];
cin >> votes[count];
count ++;
}
}
int main()
{
ifstream file = openFile();
if (file)
{
getData(file);
}
}
Note that this answer does not fix other issues in your code. For example, in getData you're using variable-length arrays which are non-standard and won't work on all compilers, and those arrays are constructed and destroyed each time through the while loop.
There are many ways to do it..
Here is a simple way.. using global variables.
I made ifstream file; as global..
This is not good way.. but simple..
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;
void openFile();
void getData();
void computePercentages();
void sortVotes();
void display();
void displayWinner();
ifstream file;
int main() {
openFile();
getData();
return 0;
}
void openFile(){
string fileName;
cout << "Enter the name of the file to open: ";
cin >> fileName;
file.open(fileName.c_str());
}
void getData(){
int count = 0;
while(!file.eof()){
string names[count];
int votes[count];
cin >> names[count];
cin >> votes[count];
count ++;
}
}
Your getData() function has some problems:
void getData(){
int count = 0;
while(!file.eof()){ // this is almost never the correct check
string names[count]; // you declare new VLA:s (non-standard) every iteration
int votes[count]; // -"-
cin >> names[count]; // and you put a value in it out of bounds.
cin >> votes[count]; // -"-
count ++;
} // both arrays are destroyed here
}
file.eof() does not return true until you've tried to read beyond the end of the file. If you've read the last value, it will not be set. Only when you try next time will it be set.
The arrays you declare inside the while loop will be destroyed at the end of the loop. After the loop is finished, you have no arrays.
When you declare an array of count elements, you can access those elements using 0 to count-1 inclusive. You access element count which is out of bounds so your program has undefined behaviour.
VLA:s (variable length arrays) does not exist in standard C++ (but does as an extension in some compilers). If you know exactly how many elements you need to store, you can use std::array instead, but in this case, use a std::vector.
It uses a global file variable (that doesn't even exist). Try to stay away from global variables if you can.
The records in your data file should be kept together instead of putting each column in a separate array. A simple placeholder for each record in your file could look like this:
struct record {
std::string name{};
int vote{};
};
With that, you only need one array (or std::vector).
std::vector<record> records;
It'd also be good if one could extract one complete record from a stream using the same >> operator as you used for int and std::string. Like this:
record temp; // declare a variable using your own type, "record"
while(file >> temp) { // read records until no more can be read
records.push_back(temp) // add one record to records
}
A function to read one record from an istream, like an ifstream:
std::istream& operator>>(std::istream& is, record& r) {
// You may want to use getline here instead in case the names contain spaces.
return is >> r.name >> r.vote; // extract name and vote from is and return is
}
The function takes both parameters (is and r) by reference. That means that whatever is done to the parameters inside the function affects the variables that were used to call the function. file >> temp results in a call to the above function where is is a reference to file and r is a reference to temp.
For openFile() I'd suggest:
std::ifstream openFile(const std::string& fileName) { // return the ifstream by value
return std::ifstream{fileName};
}
Getting the filename from the user doesn't have anything to do with opening the file, so get the filename before calling the function. The above function lets you call openFile() and get an ifstream in return:
std::ifstream file = openFile(fileName);
You can now call getData() using file, but it needs to be able to receive it. Standard stream objects can't be copied (passed by value), but we don't need to. Just make getData() receive a reference to the stream. I'd make it an istream instead of an ifstream to be able to read from any istream decendant:
std::vector<record> getData(std::istream& is) {
// create a vector, read data from "is" and put it in vector and return vector when done
}
When all is pieced together, you could have a main() looking something like this:
int main() {
std::vector<record> records;
std::cout << "Enter the name of the file to open: ";
// use getline since a filename may contain spaces
if(std::string fileName; std::getline(std::cin, fileName)) {
// if "file" is in a good state after openFile(), call getData()
if(std::ifstream file = openFile(fileName)) {
records = getData(file);
} // "file" is automatically closed when it goes out of scope
}
// print what you collected
for(const record& r : records) {
std::cout << r.name << "\t" << r.vote << "\n";
}
}
The above uses If Statements with Initializer which is a C++17 feature to help create a narrow scope for variables.
I am new to C++ and I am trying to create a program that gets an unknown data type input from a user and stores it in a variable. I am programming using visual studios and the code keeps producing error messages: E0304, LNK2019 and LNK1120.
#include "stdafx.h"
#include <iostream>
template <typename T>
T dataEntered() {
T data;
std::cout << "Enter Data" << std::endl;
std::cin >> data;
return data;
}
int main()
{
auto data = dataEntered();
std::cout << sizeof(data) << std::endl;
return 0;
}`
Template is not the solution unless you will use it in this way:
auto data1 = dataEntered<char>();
auto data2 = dataEntered<int>();
std::cout << sizeof(data1) << std::endl;
std::cout << sizeof(data2) << std::endl;
You should pass the type parameter so its known at compile time.
If you do not know the data until run-time I recommend that you read the data as string then write a function to parse it as you need.
Templates and autos are deduced at compile time, where autos are basically changed into the type deduced from the initialization value, and a version of the templated version is generated for every type used in the template parameter.
If you need to perform operations on the input, figure out what type the input is before reading it. You can also input it into a string and parse it later.
If you don't need to parse the input, just input into a string.
For example, if the first character of the input is a digit, it's probably a number.
My code:
#include <iostream>
#include <string>
#include <cctype>
int main()
{
if(std::isdigit(static_cast<unsigned char>(std::cin.peek())))
{
//the input is a number
int num;
std::cin >> num;
//do stuff with num
}
else
{
//input is something else
std::string str;
std::cin >> str;
//do stuff with str;
}
}
I am trying to get the first character of a string written to a variable of type char. With std::cin (commented out) it works fine, but with scanf() I get runtime error. It crushes when I enter "LLUUUR". Why is it so? Using MinGW.
#include <cstdio>
#include <string>
#include <iostream>
int main() {
std::string s;
scanf("%s", &s);
//std::cin >> s;
char c = s[0];
}
scanf knows nothing about std::string. If you want to read into the underlying character array you must write scanf("%s", s.data());. But do make sure that the string's underlying buffer is large enough by using std::string::resize(number)!
Generally: don't use scanf with std::string.
Another alternative if you want to use scanf and std::string
int main()
{
char myText[64];
scanf("%s", myText);
std::string newString(myText);
std::cout << newString << '\n';
return 0;
}
Construct the string after reading.
Now for the way directly on the string:
int main()
{
std::string newString;
newString.resize(100); // Or whatever size
scanf("%s", newString.data());
std::cout << newString << '\n';
return 0;
}
Although this will of course only read until the next space. So if you want to read a whole line, you would be better off with:
std::string s;
std::getline(std::cin, s);
I need to convert a std::string to a const char*.
To do so, I used the c_str() method on the string, as in the following code :
#include <iostream>
#include <string>
using namespace std;
int main(void) {
string testStr;
cin >> testStr;
const char* testStrConst = testStr.c_str();
cout << testStrConst << endl;
return 0;
}
If I type "Hey hello" in the terminal, when this code is running, the output is only "Hey".
Why is the second word ignored?
Because it was never a part of the std::string in the first place.
The >> operator reads only a single, whitespace delimited word.
Use std::getline() instead of >> to read the entire line of text entered on standard input.
string testStr;
getline(cin, testStr);