Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Page 1 of 2 12 LastLast
Results 1 to 15 of 22
  1. #1
    New Coder
    Join Date
    Nov 2011
    Posts
    30
    Thanks
    10
    Thanked 0 Times in 0 Posts

    Understanding C++: What am I doing wrong?

    I have been struggling for quite some time to understand C and C++. I have a feeling that quite a bit of that struggling is due to pointers, and not understanding how or where to use them. Following that, reading other peoples' code, I have issues all the time with understanding why sometimes the pointer reference is in the front of the word, and sometimes it's attached to the end (ex: "*char" and "char*").

    I attempted building a sample program, an "interactive fiction" which only consisted of moving between rooms.

    Code:
    #include <iostream>
    
    using namespace std;
    
    bool isPlaying = true;
    int playerx = 0;
    int playery = 0;
    char input[50];
    int roomnum = 1;
    
    void parsemov(char*);
    int roomfind(int, int);
    void roomdesc(int);
    void updateGame();
    
    int main()
    {
    	if (isPlaying != true){
    		return 0;
    	}
    	else{
    		updateGame();
    	}
    }
    
    void updateGame()
    {
    	roomfind(playerx, playery);
    	roomdesc(roomnum);
    	cin>> input;
    	parsemov(input);
    }
    
    void parsemov(char*)
    {
    	if (input != "exit"){
    		if (input == "n" || input == "north"){
    			if (playery < 1){	
    				playery += 1;
    			}
    		}
    		if (input == "s" || input == "south"){
    			if (playery > -1){
    				playery -= 1;
    			}
    		}
    		if (input == "e" || input == "east"){
    			if (playerx < 1){
    				playerx += 1;
    			}
    		}
    		if (input == "w" || input == "west"){
    			if (playerx > -1){
    				playerx -= 1;
    			}
    		}
    		else
    		{
    			cout<<"You cannot go that way.";
    		}
    	}
    	else
    	{
    		isPlaying = false;
    	}
    }
    
    int roomfind(int, int)
    {
    	if (playerx == 0 && playery == 0)
    	{
    		roomnum = 1;
    	}
    	if (playerx == 1 && playery == 0)
    	{
    		roomnum = 2;
    	}
    	if (playerx == -1 && playery == 0)
    	{
    		roomnum = 3;
    	}
    	if (playerx == 0 && playery == 1)
    	{
    		roomnum = 4;
    	}
    	if (playerx == 0 && playery == -1)
    	{
    		roomnum = 5;
    	}
    	else
    	{
            cout<<"Where are you?!";
        }
    }
    
    void roomdesc(int)
    {
    	if (roomnum == 1)
    	{
    		cout<<"You are in the middle of a dungeon.";
    	}
    	if (roomnum == 2)
    	{
    		cout<<"You are in the right wing of a dungeon.";
    	}
    	if (roomnum == 3)
    	{
    		cout<<"You are in the left wing of a dungeon.";
    	}
    	if (roomnum == 4)
    	{
    		cout<<"You are in the upper wing of a dungeon.";
    	}
    	if (roomnum == 5)
    	{
    		cout<<"You are in the lower wing of a dungeon.";
    	}
    	else
    	{
            cout<<"Where are you?!";
    	}
    }
    It doesn't work. In fact, when it does compile (through G++, there are a few linker errors when building in Dev-C++), it outputs "Where are you?!!You are in the middle of a dungeon.Where are you?!!" Any sort of input at all will exit the program.

    I'm not asking for someone to fix the code. I'm asking, based on that code there, what I'm not understanding about C++ that is hindering my progress with it. I already know I need a good explanation of pointers. I've read several tutorials regarding pointers (on cprogramming.com, cplusplus.com and a college's website), and for some reason I just can't grasp when I should use them (this includes -> pointers). I also haven't grasped the use of headers. I understand that a header is used to define functions that are used between code files, but WHEN I should use them and HOW WELL I should define said functions, I'm not sure of.

    Anything else, I'm just not sure what I'm missing about it.

    Thanks in advance!

  • #2
    Rockstar Coder
    Join Date
    Jun 2002
    Location
    USA
    Posts
    9,074
    Thanks
    1
    Thanked 328 Times in 324 Posts
    Well for starters you are defining the parameter types for your functions but you never give those parameters names. You need to give them names if you expect to access them.

    Secondly, you can't compare a char* with a string literal. Well you can but it isn't doing what you think, all it is doing is comparing the pointer addresses. It is a common beginner mistake. You need to use the strcmp or stricmp functions to compare two c-strings (char* strings).

    Thirdly the reason it exits after one input is that you are only calling your updateGame function once and it never loops. You need to do something like:
    Code:
    int main()
    {
    	while (isPlaying)
            {
    		updateGame();
    	}
    
            return 0;
    }
    OracleGuy

  • Users who have thanked oracleguy for this post:

    johnki (12-12-2011)

  • #3
    Rockstar Coder
    Join Date
    Jun 2002
    Location
    USA
    Posts
    9,074
    Thanks
    1
    Thanked 328 Times in 324 Posts
    Your roomfind function needs to be one if ... else if ... else construct not a bunch of seperate if statements. The reason for this is that even if one of those previous if statements is true it will still execute the last one and if it is false trigger your else condition that prints "where are you".
    OracleGuy

  • Users who have thanked oracleguy for this post:

    johnki (12-12-2011)

  • #4
    New Coder
    Join Date
    Nov 2011
    Posts
    30
    Thanks
    10
    Thanked 0 Times in 0 Posts
    Ah, so it's just a bunch of beginner mistakes compounded into one?

    Yeah, most of my programming experience right now comes from GML and PHP, so what it sounds like is I'm taking that and putting it into a different context and falling flat on my face.

    But again, for understanding, I do want to ask:

    1. When do you use pointers? I've read answers like "only when you have to", but what situations warrant their usage?

    2. What is the difference between front pointer (*var) and back pointer (var*)? (I'd find a code example from something but I don't feel like sifting through the dozens of open source codebases I have on the comp atm)

    3. I was able to read and understand that the "::" operator is pretty much just "class::function" for referencing functions defined inside a class that's inside a header. Does the "->" operator do the same thing except for structs? Or does it work a bit differently?

    Thanks again. I've had issues finding people who are receptive to such simple questions.
    Last edited by johnki; 12-12-2011 at 01:11 AM.

  • #5
    New Coder
    Join Date
    Nov 2011
    Posts
    30
    Thanks
    10
    Thanked 0 Times in 0 Posts
    Adding on, I changed the code to the below:

    Code:
    #include <iostream>
    #include <string.h>
    
    using namespace std;
    
    bool isPlaying = true;
    int playerx = 0;
    int playery = 0;
    char input[50];
    int roomnum = 1;
    
    void parsemov();
    int roomfind(int, int);
    void roomdesc(int);
    void updateGame();
    
    int main()
    {
    	while (isPlaying == true){
    		updateGame();
    	}
    	
    	return 0;
    }
    
    void updateGame()
    {
    	roomfind(playerx, playery);
    	roomdesc(roomnum);
    	cin>> input;
    	parsemov();
    }
    
    void parsemov()
    {
    	if (strcmp(input, "exit") == 0){
    		if (strcmp(input,"north") == 0 || strcmp(input,"n") == 0){
    			if (playery < 1){	
    				playery += 1;
    			}
    		}
    		else if (strcmp(input,"south") == 0 || strcmp(input,"s") == 0){
    			if (playery > -1){
    				playery -= 1;
    			}
    		}
    		else if (strcmp(input,"east") == 0 || strcmp(input,"e") == 0){
    			if (playerx < 1){
    				playerx += 1;
    			}
    		}
    		else if (strcmp(input,"west") == 0 || strcmp(input,"w") == 0){
    			if (playerx > -1){
    				playerx -= 1;
    			}
    		}
    		else
    		{
    			cout<<"You cannot go that way. \n";
    		}
    	}
    	else
    	{
    		isPlaying = false;
    	}
    }
    
    int roomfind(int, int)
    {
    	if (playerx == 0 && playery == 0)
    	{
    		roomnum = 1;
    	}
    	else if (playerx == 1 && playery == 0)
    	{
    		roomnum = 2;
    	}
    	else if (playerx == -1 && playery == 0)
    	{
    		roomnum = 3;
    	}
    	else if (playerx == 0 && playery == 1)
    	{
    		roomnum = 4;
    	}
    	else if (playerx == 0 && playery == -1)
    	{
    		roomnum = 5;
    	}
    	else
    	{
            cout<<"Where are you?! \n";
        }
    }
    
    void roomdesc(int)
    {
    	if (roomnum == 1)
    	{
    		cout<<"You are in the middle of a dungeon. \n";
    	}
    	else if (roomnum == 2)
    	{
    		cout<<"You are in the right wing of a dungeon. \n";
    	}
    	else if (roomnum == 3)
    	{
    		cout<<"You are in the left wing of a dungeon. \n";
    	}
    	else if (roomnum == 4)
    	{
    		cout<<"You are in the upper wing of a dungeon. \n";
    	}
    	else if (roomnum == 5)
    	{
    		cout<<"You are in the lower wing of a dungeon. \n";
    	}
    	else
    	{
            cout<<"Where are you?! \n";
    	}
    }
    Still has linker errors in Dev-C++, compiles in G++ but states "You are in the middle of a dungeon.", takes a single input and exits before output.
    Last edited by johnki; 12-12-2011 at 02:04 AM.

  • #6
    Senior Coder
    Join Date
    Aug 2006
    Posts
    1,139
    Thanks
    7
    Thanked 257 Times in 256 Posts
    I enjoyed reading your note, because I learned C some 30 years ago by writing a similar adventure-type game where you could walk around rooms, pick up and drop stuff, etc. The whole purpose was to get the hang of pointers. So it's fun to see someone working on the same situation, years later.

    Oracleguy mentioned something about parameters to functions, which you don't seem to have implemented. If you're going to call:
    Code:
    	roomfind(playerx, playery);
    and pass the x-y coordinates of where the player is, then the function roomfind ought to be declared as:
    Code:
    int roomfind(int x, int y)
    That's how your pass the parameters (the names "x" and "y" could be anything). As it stands, you've declared global variables for playerx and playery, which are being used and could work, but doing such things with globals (as opposed to parameters) is usually discouraged. So I'd declare them as local within the updateGame fuction, which you'd do as:

    Code:
    void updateGame()
    {
    int playerx,playery;
    
    	do {
    	roomfind(&playerx, &playery);
    	roomdesc(roomnum);
    	cin>> input;
    	}
    	while (parsemov());
    }
    You also want to move your other globals to be local variables, once you get the knack of it. Then let's get rolling on the pointers. You see I've passed roomfind its coordinated by reference, right? So the function declaration should look like:
    Code:
    int roomfind(int *x, int *y)
    i.e. "x and y are pointers to integers". Then your manipulations of them would look something like:
    Code:
    *x -= 1;  /* Subtract one from the integer x is pointing at */
    You will also want parsemov to return an integer 1/0 or true/false, as it's being used (in my code here) to decide whether the user has typed "exit" or not. And also, double-check your logic here:
    Code:
    	if (strcmp(input, "exit") == 0){
    		if (strcmp(input,"north") == 0 || strcmp(input,"n") == 0){
    That first test is backwards, you don't want "if the user types 'exit' then go on and check if he typed 'north'". You want 'if the user did NOT type 'exit'... right?

    There are a lot of ways to write this code, I'm just suggesting a way to start using pointers, which was your goal.

    Dave

  • Users who have thanked tracknut for this post:

    johnki (12-12-2011)

  • #7
    New Coder
    Join Date
    Nov 2011
    Posts
    30
    Thanks
    10
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by tracknut View Post
    There are a lot of ways to write this code, I'm just suggesting a way to start using pointers, which was your goal.

    Dave
    Yeah, getting the hang of pointers, as well as moving myself into the C++ mindset with something relatively simple that I could enjoy writing was the goal.

    Again, I really do appreciate the help, and definitely appreciate not getting the typical "go read a book" answer.

    Okay, now for the content of the post...

    First off, if playerx and playery are initialized that way, aren't they set to NULL, meaning for those local variables, I should actually declare them like...

    Code:
    int playerx = 0;
    int playery = 0;
    ...so that the center room (room 0) will show on startup instead of getting a null point error, or whatever you'd call it?

    Second, if I'm making the roomfind function structured like that, can I leave all the if (playerx == anumber) (except changed to match the &playerx dereferencing form) as they are or should I change them to match the function declaration's format (if (x == anumber))?

    Third, I'm starting to get a better grasp of pointers the more I get help with it, but again, I still don't understand why sometimes it's "*char" and sometimes it's "char*" (not necessarily with char but the same concept applies).

    Fourth, I'm still not sure when I'd want to use pointers versus when I wouldn't want to use pointers.

    Fifth, "->" is a pointer for structs, right? If I were to create a struct...

    Code:
    struct myStruct {
      int int1;
      char char1;
      int int2;
    }
    
    //and an object...
    myStruct myObject;
    ...would "->" be used to point to (dereference, in this case) a member of myStruct? For example, myObject->int1;? In essence, would this be the same as the & dereferencing...except for structs? Or am I getting this entirely wrong?

  • #8
    Senior Coder
    Join Date
    Aug 2006
    Posts
    1,139
    Thanks
    7
    Thanked 257 Times in 256 Posts
    Quote Originally Posted by johnki View Post
    First off, if playerx and playery are initialized that way, aren't they set to NULL, meaning for those local variables, I should actually declare them like...

    Code:
    int playerx = 0;
    int playery = 0;
    ...so that the center room (room 0) will show on startup instead of getting a null point error, or whatever you'd call it?
    Yep, good point. But not because you'll get a segment fault for an invalid address, but simply because you'd like to make sure you start the person in "room 0".

    Second, if I'm making the roomfind function structured like that, can I leave all the if (playerx == anumber) (except changed to match the &playerx dereferencing form) as they are or should I change them to match the function declaration's format (if (x == anumber))?
    You'd need to change them all to x rather than playerx. You can certainly use playerx, I was just trying to get you away from the idea that playerx and playery were globals and you had to use those names. The instance of playerx where you declare it is a completely different instance to the one as the parameter to the function, it would be complete coincidence to use the same names.

    Third, I'm starting to get a better grasp of pointers the more I get help with it, but again, I still don't understand why sometimes it's "*char" and sometimes it's "char*" (not necessarily with char but the same concept applies).
    You declare a pointer as "char * p;" meaning "this is a pointer to a char". When you dereference that pointer to use it, you might have "c = *p;" meaning "put the first character that p is pointing at into c".
    Fourth, I'm still not sure when I'd want to use pointers versus when I wouldn't want to use pointers.
    Certainly not "when all else fails" or whatever your first comment was at the beginning of the thread. There are tons of reasons to use them, and once you get familiar with them, ideas will pop up naturally. Let me describe one or two. Say you have some enormous memory structure (array, struct, whatever) that you need to pass to a function. It's far better to pass a pointer to that structure (ie, a 4 or 8 byte address) than to copy the entire data object onto the stack to send it to the function. Huge performance advantage. Another idea... You might have a list of common structures (ie, like a database of employee records) that you need to sort. It's going to be far better (performance and memory-wise) to sort a list of pointers to those records than it is to actually sort the records themselves.

    Fifth, "->" is a pointer for structs, right? If I were to create a struct...

    Code:
    struct myStruct {
      int int1;
      char char1;
      int int2;
    }
    
    //and an object...
    myStruct myObject;
    ...would "->" be used to point to (dereference, in this case) a member of myStruct? For example, myObject->int1;? In essence, would this be the same as the & dereferencing...except for structs? Or am I getting this entirely wrong?
    You got that one right. Dereferencing "c = *p;" is for a simple data type of character pointer. "c = p->int1;" is for the structure as you've described. (whoops, my answer is slightly off. I just read the one below from oracleguy, use his answer instead of mine for this struct pointer -> thing)

    Dave
    Last edited by tracknut; 12-12-2011 at 04:27 AM.

  • Users who have thanked tracknut for this post:

    johnki (12-12-2011)

  • #9
    Rockstar Coder
    Join Date
    Jun 2002
    Location
    USA
    Posts
    9,074
    Thanks
    1
    Thanked 328 Times in 324 Posts
    The -> (arrow) operator is just like the dot operator but it is used only with pointers (mostly). It combines a dereference call with accessing a member of the object. It can be used with structs and classes.

    So lets say we have this structure:
    Code:
    struct Vector3
    {
    int x;
    int y;
    int z;
    }
    If you had a pointer to that struct:
    Code:
    Vector3* point = new Vector3;
    Both of these lines of code do the same thing:
    Code:
    point->x = 0;
    (*point).x = 0;
    But as you can see in this case the arrow operator results in a bit cleaner code code and is easier to write.
    OracleGuy

  • Users who have thanked oracleguy for this post:

    johnki (12-12-2011)

  • #10
    New Coder
    Join Date
    Nov 2011
    Posts
    30
    Thanks
    10
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by oracleguy View Post
    The -> (arrow) operator is just like the dot operator but it is used only with pointers (mostly). It combines a dereference call with accessing a member of the object. It can be used with structs and classes.
    Okay, I think I've got it, but just to be clear, when used with classes, I would want to do it like this...

    Code:
    class myClass {
      int x, y, z;
      public:
        void voidFunc(int z);
        int intFunc(int x, int y);
      private:
        void privateFunc();
    }
    
    //and an instance of that class...
    myClass Class1;
    
    //I'd dereference it like this...
    Class1->voidFunc(int);
    ...the same way I did the structs, only with classes, right? And private functions can't be referenced because they're only available within the scope of the class? So, in that case, private functions should be fully defined within the scope of the class, more like...

    Code:
    class myClass {
      int x, y, z;
      public:
        void voidFunc(int z);
        int intFunc(int x, int y);
      private:
        void privateFunc(){
          //do something
        }
    }
    ...right?

    Man, this is going far beyond the scope of the original post, but I realized I should probably make sure I'm understanding all of this correctly.

    EDIT: Updated my code with the suggestions. Now, I'm getting a "playerx (or y) was not declared in this scope" error for updateGame() and parsemov().

    EDIT2: Removed the pointer references (meaning int roomfind(int x, int y) and int roomfind(playerx, playery)) and now it...sort of works. It takes input, but something broke and it will always output "You are in the middle of a dungeon."
    Last edited by johnki; 12-12-2011 at 04:55 AM.

  • #11
    Rockstar Coder
    Join Date
    Jun 2002
    Location
    USA
    Posts
    9,074
    Thanks
    1
    Thanked 328 Times in 324 Posts
    Quote Originally Posted by johnki View Post
    Okay, I think I've got it, but just to be clear, when used with classes, I would want to do it like this...

    Code:
    class myClass {
      int x, y, z;
      public:
        void voidFunc(int z);
        int intFunc(int x, int y);
      private:
        void privateFunc();
    }
    
    //and an instance of that class...
    myClass Class1;
    
    //I'd dereference it like this...
    Class1->voidFunc(int);
    ...the same way I did the structs, only with classes, right?
    No in that case you would just write Class1.voidFunc(0); because the way you declared the Class1 variable it isn't a pointer.

    Quote Originally Posted by johnki View Post
    And private functions can't be referenced because they're only available within the scope of the class? So, in that case, private functions should be fully defined within the scope of the class, more like...

    Code:
    class myClass {
      int x, y, z;
      public:
        void voidFunc(int z);
        int intFunc(int x, int y);
      private:
        void privateFunc(){
          //do something
        }
    }
    ...right?
    Sort of. Yes private and protected members cannot be called from outside of the class. However you don't have to define the functions in the same place you define the class. This is where header files start to come into play.

    You can define the class in a header file and then the function implementation in the class in a separate cpp file. The advantage over putting it in the header file is that then the code doesn't need to be recompiled in each place the header file is used. (Among many other reasons).

    So if you had that class:
    Code:
    class myClass {
      int x, y, z;
      public:
        void voidFunc(int z);
        int intFunc(int x, int y);
      private:
        void privateFunc();
    }
    You can define the implementation of the functions like so:

    Code:
    void myClass::privateFunc()
    {
    
    }
    OracleGuy

  • Users who have thanked oracleguy for this post:

    johnki (12-12-2011)

  • #12
    New Coder
    Join Date
    Nov 2011
    Posts
    30
    Thanks
    10
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by oracleguy View Post
    No in that case you would just write Class1.voidFunc(0); because the way you declared the Class1 variable it isn't a pointer.
    Ah, so in that case, it would have had to be "myClass * Class1;" to warrant using a "->" dereferencing?

    And understood with the class structure. And I'm starting to get headers now. Define the minimum that will be used in multiple places, then expand as needed. If that means fully defining a function, then fully define it. If that means simply declaring a function, then declare it. To be clear though, headers use #IFDEF and #ENDIF statements, as opposed to simply writing out the code, correct?

  • #13
    Rockstar Coder
    Join Date
    Jun 2002
    Location
    USA
    Posts
    9,074
    Thanks
    1
    Thanked 328 Times in 324 Posts
    Quote Originally Posted by johnki View Post
    Ah, so in that case, it would have had to be "myClass * Class1;" to warrant using a "->" dereferencing?
    Correct.

    Quote Originally Posted by johnki View Post
    And understood with the class structure. And I'm starting to get headers now. Define the minimum that will be used in multiple places, then expand as needed. If that means fully defining a function, then fully define it. If that means simply declaring a function, then declare it. To be clear though, headers use #IFDEF and #ENDIF statements, as opposed to simply writing out the code, correct?
    Yes those are called pre-processor directives. The pre-processor is the first stage of code compilation; those are used so that the code in a header file is only included once.

    Without them you can get errors about defining something multiple times.
    OracleGuy

  • Users who have thanked oracleguy for this post:

    johnki (12-12-2011)

  • #14
    New Coder
    Join Date
    Nov 2011
    Posts
    30
    Thanks
    10
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by oracleguy View Post
    Correct.
    So in that case, what does Class1 point to? Does it just point to myClass, essentially meaning it's uninitialized? Or would it be more like...

    Code:
    myClass Class1;
    
    myClass * ClassPtr = Class1;
    ...to be initialized correctly?

    Or would it just be like the below?

    Code:
    myClass * ClassPtr = new myClass;
    Last edited by johnki; 12-12-2011 at 04:40 PM.

  • #15
    New Coder
    Join Date
    Nov 2011
    Posts
    30
    Thanks
    10
    Thanked 0 Times in 0 Posts
    Changed the main loop to...

    Code:
    void updateGame()
    {
    	do{
    		parsemov();
    		roomfind(playerx, playery);
    		roomdesc(roomnum);
    		cin>> input;
    	}
    	while (isPlaying == true);
    }
    ...and changed the one function to...

    Code:
    if (strcmp(input, "exit") == 0)
    ...but it's crashing on first input again.

    I did notice that maybe I should change the roomdesc function to...

    Code:
    void roomdesc(int x)
    {
    	if (x == 1)
    	{
    		cout<<"You are in the middle of a dungeon. \n";
    	}
    //else if...else...
    }
    ...to go in line with the changes to roomfind.

    I also think I need to restructure parsemov, but I haven't totally figured out a way to streamline it just yet.

    Also, are there any ways that are "beginner friendly" that would make functions like roomdesc a lot...smaller? It seems kinda clunky to do the "if x = 1, print statement 1. if x = 2, blah blah..." method.

    EDIT: Changed them to...

    Code:
    void roomdesc(int * x)
    ...and...
    Code:
    roomdesc(&roomnum);
    ...to try and fit pointers in...but G++ gives me errors about converting an int to an int pointer.
    Last edited by johnki; 12-13-2011 at 12:39 AM.


  •  
    Page 1 of 2 12 LastLast

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •