New desperate programmer here

Hello c++ members. I am Zac and this is my first post here. I am brand new to c++ and have taken only 1 course in it. I am trying my hand at creating my own calculator type of program, but I cannot move on because I cannot figure this out. To keep it brief, I want to create a switch inside of an object that stores a char (y or n) inside of a variable and then after the object runs my main.cpp looks to see which char the person chose. I have tried this many ways, but I cannot figure it out. Thank you all in advance and I hope to learn a lot here so I can contribute as well.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>

using namespace std;

class welcome {
    public:
        char newHere (char makeAcc) {
            cin >> makeAcc;
            switch (makeAcc) {
                case 'y':
                    cout << "I am new here" << endl;
                    break;
                case 'n':
                    cout << "I am not new here" << endl;
                    break;
                default:
                    cout << "Oops! Please type y or n." << endl;
            }
        }
};

int main () {
    cout << "Hello Human" << endl;
    cout << "Are you new here? (y/n)" << endl;
    char newUser;
    welcome obj1;
    obj1.newHere(newUser);
    if (newUser == 'y') {
        cout << "Great, welcome!" << endl;
    }
}
Lets start with the warnings (you should always listen to them because they will give critical clues to many problems).
If you don't see warnings, try to google how to set it to the maximum level in your specific compiler.

 In member function 'char welcome::newHere(char)': 
19:9: warning: no return statement in function returning non-void [-Wreturn-type] 

I think this is simple enough for you to understand, you should always call a return /*insert value here*/; inside your function because you defined your function to return something, if you don't want it to return anything, return replace the char in the function definition with a void.

In function 'int main()': 
25:10: warning: 'newUser' is used uninitialized in this function [-Wuninitialized]

This is a critical clue to you, why is newUser uninitialized?
C++'s compiler is very smart, no matter how many hoops you go through, if a variable is not used, then the compiler will tell you, I should note it not something you should depend on since if you made newUser initialized with a value no warning would happen in the first place, but you should never ignore it them when you do see them, and if you don't understand something you should google it even if it seems unlikely to get help from that.

I should also point out that the class you created has absolutely no purpose. Perhaps in the future you could throw some variables that would've been in the global scope which is good, but for this context, it is best to be clear cut with with your intentions, because your function is no different than a global function.

As a solution there are 2 possibilities, I feel like you accidentally tried to do both at the same time, but you seem to not get it. Way #1 is to make your (char makeAcc) to (char& makeAcc), Way #2 is to return the value.

I assume you are have habits from another language like Java, js, lua, and probably many others. In C++ a value put in a parameter is ALWAYS copied. All the way down to the core where even pointers or references are copied, and you have to learn that copying an integer or double is cheaper than copying & de-referencing a pointer since a pointer is no different than a number, internally. While also understanding what data is expensive or cheap to copy (because beginners commonly make the mistake of copying things in the parameters).

I'm going off at a tangent here, but when you make it to the point of trying to learn C-Strings (AKA: char* magic = "how can this be a pointer and a string at the same time? MAGIC";), it may confuse you that changing a single pointer does not change other pointers (like in other languages), so if you put a C-String into a function parameter and you want to dynamically change it's size (which requires pesky manual memory management work), you to have a pointer to a pointer in that case, because every pointer you create also has it's own pointer in memory which like any integer or primitive would have.

I personally believe people fall for this since people write code like:
1
2
char *c = "abc";
c = "defg";

but that falls apart when you try to do:
1
2
3
4
void change_str(char *c)
{
  c = "defg";
}

Mainly because the value "defg" is immediately deleted when the function ends, since it is created on the stack, which if you don't know, stack memory looks like a directory tree, when you go in a directory you can access all the files from the directory and the directories that leads up to the path (that's not how directories work, but this is an analogy), but you cannot access or keep ownership of any other files outside the directories that are open, and all these files have a fixed or maximum size, unless you hold that memory in the heap like how std::list, vector, etc work. Also remember that heap vs stack memory is hard to compare, since a value may look like it is on the stack, like in a class, but it sometimes it's not (depending on how you allocate the class).

Meanwhile in C++ you have things like std::string which will be completely copied (expensive) if you don't make the parameter have the reference operator (for strings in particular use const std::string & because it allows more flexible ways of entering values).

Thus, connecting this to your problem, your function newHere has a parameter makeAcc, but it is a copy which does not change the orginal newUser, which causes the warning of newUser being uninitialized.

But I should remind you, it is kinda weird to get a value from a reference of a function, it makes more sense (in my opinion) to return the char, or return a boolean.

If you want to retry after entering an invalid answer, you will require probably a while(true) loop inside your function, and calling return when you want to exit out, and continuing the loop when default happens.

It also makes more sense to move the print "Are you new here? (y/n)" to be inside the function (in my opinion), since if you wanted to change "y/n" to "yes/no" the code is decoupled to easily change the question with the input. And you could perhaps explain what the function does with a comment.

I covered more than what I needed to give, but these are the pillars that most beginners need to understand.
I think this is more what you wanted:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// ConsoleApplication10.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "pch.h"
#include <iostream>

using namespace std;

class welcome {
public:
	void newHere(char &makeAcc) {
		cin >> makeAcc;
		switch (makeAcc) {
		case 'y':
			cout << "I am new here" << endl;
			makeAcc = 't';
			break;
		case 'n':
			cout << "I am not new here" << endl;
			makeAcc = 'f';
			break;
		default:
			cout << "Oops! Please type y or n." << endl;
			makeAcc = 'r';
		}

	}
	
};

int main() 
{
	char newUser{};
	welcome obj1;
	do
	{
		cout << "Hello Human" << endl;
		cout << "Are you new here? (y/n)" << endl;
		obj1.newHere(newUser);
		cout << '\n';
		if (newUser != 't' || newUser != 'f')
		{
			//error handling:
			cin.clear(); // If input was numerical - This will keep program from breaking
			std::cin.ignore(32767, '\n'); // If there were multiple inputs, this well keep the rest from being counted.
		}
	} while (newUser == 'r');

	if (newUser == 'y') {
		cout << "Great, welcome!" << endl;
	}
}


newUser needs to be initialized - which can be done by adding '()' or '{}' after declaration - it will set the value to nothing in this case. Moreover, the "newHere" function didn't return anything - so it should be a void function - a function that wont return a value. I made makeAcc pass to the function through reference, so when makeAcc's value changes, the newUser value will also change - this will help with creating the loop for incorrect answers as shown.
Last edited on
Well thank you a lot for this information. I am going to take my time and study what you both sent. Thank you for taking the time to reply.
zapshe's sample is OK in terms of execution, it is very close to working, but there is a very obvious bug that goes with it, I wonder if you can figure it out.

But the error handling is something that is very important that I have forgotten and solves an ugly bug if someone enters garbage input.

The more I think about it, the more weird std::cin looks to me, because it seems like the only way to make cin have clean input is to clean up cin after every time you use it, because in this example, even if you get the correct input, there could still be garbage left. It seems like getline should be the only answer to user input, since cin seems to be a hack to make file input and user input the same thing, which is cool to some degree, but it doesn't seem to make much sense...
Last edited on
Topic archived. No new replies allowed.