View Full Version : Simple Question...
xISOx
10-27-2005, 06:22 PM
I'm pretty new to programming, and for practice, I have chose to write a simple text based game with C++, just so I can get used to alot of the commands and structure. I have this so far...
/*
* This program source code and all associated executables and files that
* may or may not be packaged and distributed are registered under the
* general public licence(GPL) and are free to be copied, re-compiled, edited,
* or just about anything else that you want to do with it. It is not
* required, but the authors(Nik 'xISOx' Daniel and David 'brfngmnky' Brees)
* would like to be credited for their work on this project. Thank You.
*
* As this is intended to be a learning project, we will be trying to document
* and explain what we do, but if you have no idea what any of the code is,
* the explanations may not make much sense. Go buy yourself a programming
* book if you want to learn how to program.
*
* The website for this project has yet to be determined, as it has no name.
*/
/* These things are the things that should appear at the beginning of any
* source code files, they basicly hold the data for the functions that we
* use regularly. (cout, cin, int, char) They are used by the pre-processor
* of the compiler, meaning that they are only used by the compiler, not the
* actual program. The '<>' denote universal files, and a '""' would denote
* a local file, but I'm not sure we'll be using those for this project.
*/
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string.h>
/*
* This next little line means that we will be using standard functions and
* calls in the code. This prevents us from having to type std:: in front of
* alot of the code.
*/
using namespace std;
//Defining the strings to be used for logon and saving purposes...
char playername[20];
char playerpass[20];
// Prototyping the functions...
void login (char playername[20], char playerpass[20]);
// The main function, what starts the actual program.
int main()
{
login(playername, playerpass);
cout << "DEBUG: This is where the game would be, if we had one..." << endl;
cin.get();
return 0;
}
void login(char playername[20], char playerpass[20])
{
int playerexists(0);
char newpass[20];
char verifypass[20];
cout << "Welcome to <Game Name>, please enter your username:" << endl;
cin.getline (playername,20);
ifstream in(playername);
in >> playerexists;
if (playerexists == 1) {
existinguser:
cout << "DEBUG: Preloading data for existing user " << playername
<< "...";
ifstream in(playername);
in >> playerexists >> playername >> playerpass;
cout << "Success." << endl;
cout << "Welcome back, " << playername << ". Please enter your "
<< "password:" << endl;
cin.getline (verifypass,20);
if (strcmp (verifypass,playerpass) == 0) { }
else {
cout << "Incorrect login, please try again...\nUsername:" << endl;
cin.getline (playername,20);
ifstream in(playername);
in >> playerexists;
if (playerexists == 1) { goto existinguser; }
else { goto newuser; }
}
}
else {
newuser:
cout << "A new player! " << endl;
do {
cout << "Please pick a nice password for " << playername << ":"
<< endl;
cin.getline (newpass,20);
cout << "Please re-enter your password for verification:" << endl;
cin.getline (verifypass,20);
} while (strcmp (newpass,verifypass) != 0);
cout << "DEBUG: Creating new PlayerFile..." << endl;
playerexists = 1;
playerpass = verifypass;
ofstream out(playername);
out << playerexists << " " << playername << " " << playerpass;
cout << "DEBUG: Done." << endl;
}
cout << "DEBUG: End of login function." << endl;
}
I am wondering if there is a way for the program to prompt the player for a command without making something like:
char arg[20];
cin.getline(arg,20);
switch (arg) {
case save:
save function call
case north:
north movement call
case quit:
save and then exit call
default:
cout << "What?\n" << endl;
}
Does this make any sense at all? Is this the way I will have to do it, it just seems ugly to me.
Also, how can you check to make sure a string has no spaces in it?
IrishFarmer
10-27-2005, 07:40 PM
Well you could always use keyboard input, though code-wise it would look just as ugly.
Its kind of unwieldy if you don't know what you're doing with it, but there is the:
<conio.h>
header and the _getch() function. Of course, I'm guessing your text game isn't message based and thus just loops about as fast as the processor allows it, which can make for poor results with this function.
Otherwise the only real way I know to handle keys "well" so far (besides directx) is with the Windows API. In fact, if you're just starting in Game Design I would recommend you start there. Text based games are good and all, but the experience is very limited.
If you want, I have a 2D engine I can send you the source code for. Its designed with a backbuffer (no flickering), can handle bitmaps, midi music, and seperates the various logic of the game into functions that are 'reactions' to the different windows messages. Or, in other words, you'll know right where to put the code when the user hits a key or clicks the mouse, or its time to handle another frame cycle or the game needs to be redrawn.
Its not the final version, since I want to add a couple of more advanced features to it, but for your purposes it should work.
Anyway, hope that helps.
NomadRock
10-27-2005, 09:50 PM
Basically yes, you are going to need a big case statement. Though if you store your case values, and functions they do into arrays, you can write a loop that will step through them.
monjardin
10-28-2005, 06:14 AM
I think NomadRock means something like this:
// functions to handle user commands
void save();
void north();
void quit();
// function pointer type definition
typedef void (*func)();
// structure to hold a string and function pair
struct arg_func{
const char* arg;
func f;
};
// an array of string/function pairs
arg_func commands[] =
{
{ "start", start },
{ "north", north },
{ "quit", quit }
};
const int args = 3;
// after getting the user input
// loop through the stored commands
for( int i = 0; i < args; ++i )
{
// compare the input to the stored argument
if( !strcmp( arg, commands[i].arg ) )
{
commands[i].f(); // calls the function
break; // found the command, so we're done
}
}
This would be a lot cleaner using STL classes/algorithms. I did something similar recently for handling sections of an XML document.
I definitely think you should look at using a string class (e.g., std::string) instead of passing around char*'s. It will make your life much easier.
If you want to make sure a string has no whitespace, you will have to iterate over it and check each character. However, cin operator>> uses whitespace as a delimeter by default. So, if you did something like the following you would be guaranteed not to have any whitespace:
std::string arg;
std::cin >> arg;
-Judge
xISOx
10-28-2005, 10:42 AM
IrishFarmer: Thanks for the offer, but at this point in time, other people's code confuses me. This is my absolute first project working with anything remotely like this, so I don't think having graphics to handle would be such a great idea.
Nomadrock/Monjardin: Thanks guys, that'll keep me going for a little while longer. :lol:
But, wouldn't typdef'ing void as *func mean that I couldn't use void for it's normal purpose anymore?
I would advice you to code just the "engine" in a quite general way. The Rooms in your game could each be a textfile with some text to show when you enter, and a list of legal commands and other rooms you can reach from there (filenames).
Using a similar system, you can quite easily build a complete world, while you keep the code clean.
xISOx
10-28-2005, 11:15 AM
OK, I have split up my files, and tried to impliment your idea into themain function, but I get these errors...
52 invalid conversion from `void (*)(char*, char*)' to `void (*)()'
56 no match for 'operator>>' in 'std::operator>> [with _CharT = char, _Traits = std::char_traits<char>](((std::basic_istream<char, std::char_traits<char> >&)(&std::cin)), ((char*)(&arg))) >> std::endl'
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string.h>
#include "prototype.h"
#include "global.h"
#include "systemfunc.cpp"
#include "playerfunc.cpp"
/*
* This next little line means that we will be using standard functions and
* calls in the code. This prevents us from having to type std:: in front of
* alot of the code.
*/
using namespace std;
// The main function, what starts the actual program.
int main()
{
// login(playername, playerpass);
cout << "DEBUG: This is where the game would be, if we had one..." << endl;
typedef void (*func)();
struct arg_func{
const char* arg;
func f;
};
arg_func commands[] =
{
{ "lol", lol },
{ "login", login }
};
const int args = 3;
char arg[20];
cin >> arg >> endl;
for( int i = 0; i < args; ++i )
{
if( !strcmp(arg, commands[i].arg))
{
commands[i].f();
break;
}
}
cin.get();
return 0;
}
Reedbeta
10-28-2005, 11:24 AM
Check the definitions of your lol and login functions. One of them is declared as taking two strings, but you are calling them with no arguments.
For the second error, you can't use >> into a C-style string. Try using cin.getline(arg, 20).
xISOx
10-28-2005, 12:07 PM
Yuck, I can get the first command in the playerfunc.cpp command to work, but anything else crashes the game...
I have put in checks against invalid options, but I still can't get the second one to work... maybe if I prototype it... nah, that didn't do anything.
Interesting, I took out my checks, so there is nothing else in the for loop, and it works, it just kills the program after two commands are entered.
Any ideas?
eddie
10-28-2005, 12:48 PM
xISOx, to give you another option, that's more jive with C++, you might want to take a look at Functors.
Basically the idea is that you create a class with an overloaded operator(), that can then be called like a function. Something like:
class Save
{
public:
void operator()()
{
// Do your save operations.
}
}
int main(int argc, char *argv[])
{
Save saveFunctor;
/// logic here.
switch(argument)
{
case SAVE:
{
saveFunctor();
}
}
return(0);
}
I find Functor's preferable to function pointers for a variety of reasons:
- Functor's can maintain state, whereas function's cannot (without using global variables or static function variables, which all introduce re-entrance issues)
- Functor's (allegedly) can be procedurally integrated by the compiler, so it seems that it can optimized better by the compiler (admittedly, I got this from the parashift CPP Lite faq, I can't empirically verify this)
- Functor's are a lot more elegant than the normal typedefing that's required with function pointers.
If you still want to go with function pointers, I suggest looking at the tutorials at http://www.function-pointer.org/.
Hope that helps. :) I pray you try Functors. :)
roxtar
10-28-2005, 12:58 PM
But, wouldn't typdef'ing void as *func mean that I couldn't use void for it's normal purpose anymore?
I don't think you understood what he did. He has actually given a new name for a pointer to a function (http://www.newty.de/fpt/index.html)which takes no arguments and returns void. Also even if you do something like
typedef int blah;
you will be able to do both
blah x=60;
int y=70;
typedef is just a convenience.
eddie
10-28-2005, 01:53 PM
I don't think you understood what he did. He has actually given a new name for a pointer to a function (http://www.newty.de/fpt/index.html)which takes no arguments and returns void.
Exactly. I think the xISOx is getting confused by defines vs typedefs, as well as the weird way with which C/C++ do function pointers.
// function pointer type definition
typedef void (*func)();
I know this is weird, but what's actually happening there is we're declaring a function pointer of return type 'void', that takes no parameters, and labelling that 'type' as 'func'.
As roxtar explained, you're not really 'redefining' the meaning of 'void', you're simply saying that 'in place of the word "func", use this much uglier looking type' to the compiler.
Check the http://www.function-pointer.org/ site for more information.
It really shines in the case of function pointers, and generics (templates).
xISOx
10-28-2005, 07:03 PM
Hmm... I think I'll just use switch statements... this is a little advanced for me...
Ugh, I'm completely and utterly confused now.
Is there a way to have a user enter more than one word and it stores each word into a seperate variable?
Switch won't work with strings... I think I'm gonna cry...
eddie
10-29-2005, 02:09 AM
Don't feel bad about using switch. It's a great tool, and you can always optimize into using functors, function pointers, etc, later. :)
Don't be confused either, feel free to ask questions, or just go with what you know until you're more solid. :)
TO have a user enter more than one word and store each word into a separate variable... I'd probably do something inside of a loop with a push_back to a vector.
std::vector<std::string> vecString;
for(/* loop conditions */)
{
std::string myString;
cin >> myString;
vecString.push_back(myString);
}
Then you can access it using the indexing operator (vecString[0]), or better yet, STL iterators.
That said, what are you trying to do at this point? I assume it's still the same thing as before, the whole 'save', 'load', etc?
What you *could* do, is a bit of a change in your 'UI' design.
Why not have the user menu look like this:
User, what do you want to do?
1) Save
2) Load
....
Input:
Then your code simply has to take in an integer, and you can do a switch based on the integer (you can even use the fact that an integer and an enum silently cast to each other on most compilers, and still use an enum. :)).
Depending on what you want, this might be nicer. If I"m playing a game, I'm not sure I'd want to type in 'save' or 'load' all the time anyways: but that's totally up to you. :)
HTH
xISOx
10-29-2005, 06:49 PM
Well, the point of the program is to have something like a MUD, only with only one player, and obviously seriously limited in functionality by my horrible programming skills.
I am wanting to set up a user prompt for commands that they can do in the game. At any time they would be able to use the save function, or do a number of other things. That's why the numbered options wouldn't work too well.
Well, I'm having no luck with C++ style strings...
//Defines for player command input...
string commandline;
string userinput;
Gives me:
10 C:\Program Files\Apache Group\Apache2\htdocs\GT\global.h `string' does not name a type
?!?!?!?!?!?!?!?!?!
That's in my included file for all my global variables. I have compiled a program using strings before on this compiler, so I don't know what's up with it...
monjardin
10-29-2005, 08:46 PM
The STL string class is in the <string> header as opposed to the <string.h> header. So, adding "#include <string>" should fix your problem (given that you have the "using namespace std;" line as in your example).
Which compiler are you using?
eddie
10-30-2005, 01:28 AM
Well, you should preface your string with std::string, allowing you're using the STL string.
It's bad practice to use 'using' in a header, as it pollutes every compile unit you use that header in (read: every cpp, and other header that's included after that one).
Make sure you #include <string> before those declarations in that file! (#include <string.h> will automatically put your header file into the using std; namespace, which you should avoid!).
One last note about your game design: it sounds like you're going for a Sierra kings-quest/heros-questish type game (in terms of command processing, anyhow), and so you'll end up having to do string compares against things in a series of if's or some such (if you don't go the functor, loop route).
Just another option if you like: there are a large amount of keys on a keyboard. :) You can bind keys to 'save', 'load', etc. F1 to save, F2 to load, etc, and then you can do a switch statement based upon the scancode for the key (which then can map to a nicer architecture for re-mapping those keys, etc).
I only give that as an option, because you probably don't want to have to build a parser and interpreter for incoming text, and handling error items. Single keys representing items are a lot easier to handle.
Just my two cents. :)
xISOx
10-30-2005, 05:03 AM
I am getting alot of stuff to work now, I just keep having one recurring error that is bugging me. Alot of times, when I enter a line of input, then another line, the program will crash.
Any ideas?
Also, how do you use the switch function with a string?
std::vector<string> commandline;
for (int x(0); x<3; x++) {
cin >> userinput;
commandline.push_back(userinput);
}
Will loop through and get three different lines of input, this isn't really what I wanted. I want them to be able to enter something like "look sword" and i can grab the look and the sword part as two seperate variables...
Another approach could be something like this. Note I wrote it without testing.
So be careful about the syntax when using copy-paste. It should be correct but
I don't give a guaranty when I didn't compile and test :)
#include <string>
#include <map>
// define available commands
enum
{
SAVE=1,
LOAD,
QUIT
};
// a sample when it makes sense to use typedef's
typedef map<string, int> mapCommandID;
/*
now instead of writing "map<string, int>" all the time you
can simply write "mapCommandID". this makes your source easier to
read. "mapCommandID" gives a much better hint about what your map
actually does. The compiler will just replace the part
"mapCommandID" with "map<string, int>" wherever it shows up
in your source code.
*/
mapCommandID g_mapCommand; // the actual map
// function to assign your commands to a map
void FillCommandID()
{
g_mapCommand["save"] = SAVE;
g_mapCommand["load"] = LOAD;
g_mapCommand["quit"] = QUIT;
return;
};
int main()
{
// set up the commands in your map
FillCommandID();
// buffer to hold your command
char cmd[128];
// read a command
cin >> cmd;
// use the map to act on your command
switch ( g_mapCommand[cmd] )
{
case SAVE:
SafeToFile();
case LOAD:
LoadFromFile();
case QUIT:
CleanUpAndExit();
default:
NotifyInvalidCommand();
}
return 0;
}
///////////////////////////////////////////////////////////
///////// another approach for your main-function /////////
///////////////////////////////////////////////////////////
/*
if you still want to get rid of the switch then you
could use the functors as it was mentioned in earlier posts.
basically you would have an array of function pointers.
*/
int main()
{
int iNumberOfFunctions = 4; // number of avaiable funtions
void (*arrayFuncPointers[iNumberOfFunctions]) (); // the array with function pointers
// set the function pointers to the actual funtion
arrayFuncPointers[0] = NotifyInvalidCommand;
arrayFuncPointers[SAVE] = SafeToFile;
arrayFuncPointers[LOAD] = LoadFromFile;
arrayFuncPointers[QUIT] = CleanUpAndExit;
// set up the commands in your map
FillCommandID();
// buffer to hold your command
char cmd[128];
// read a command
cin >> cmd;
// call the function
arrayFuncPointers[ g_mapCommand[cmd] ]();
return 0;
}
Hope that made sense.
edited for lousy grammar...
About the crashes you mentioned.
(this should apply to vectors as well as to maps I stick to the sample I made in my previous post)
If you did properly assign a value to your map then you have:
g_mapCommand[„safe“] = SAFE;
here „SAFE“ stands for „1“
so you can do this:
int iSomeInteger = g_mapCommand[„safe“] ;
it will be the same as:
int iSomeInteger = 1;
If you did not assign a correct value to a map you get something like this:
int iSomeInteger = g_mapCommand[„nonsense“];
since this was not assigned to your map it is as if you wrote:
int iSomeInteger = NULL;
because the map did not contain the referred string. So the map returns NULL. But you can’t have an integer be NULL.
To avoid crashes you could do this:
if( NULL != g_mapCommand[cmd] )
{
arrayFuncPointers[ g_mapCommand[cmd] ]();
}
else
{
NotifyInvalidCommand();
}
Will loop through and get three different lines of input, this isn't really what I wanted. I want them to be able to enter something like "look sword" and i can grab the look and the sword part as two separate variables...
To do this you would need to parse your command line. Are you sure that’s what you want? Because then it gets more complicated. It would probably be best to write a class as a parser.
edit: Guess I should learn how to write properly…
A few more details:
In your code sample you have this
for (int x(0); x<3; x++)
{
...
}
Look at the part where you write x(0)
That’s as if you call a function x() with a parameter 0.
Try changing it to x=0.
On another note. NULL is basically a definition:
define NULL 0
Hence, technically you could have
int iSomeInteger = NULL;
But it’s bad practice. You should use the logical way and have “0” for assigning to an integer.
What I was trying to say earlier was that you might use your vector to assign it to a wrong place. So you are mixing different types. I should have been more thoughtful when giving you an explanation. But it’s Sunday and there is no code sample from you. So we can’t be certain about the problem in the first place.
Anyway I hope I did not confuse you but rather give you some constructive ideas. Let me know if I succeeded in that regard. If not I will try to make up for it :)
NomadRock
10-30-2005, 11:18 AM
That’s as if you call a function x() with a parameter 0.
Try changing it to x=0.
Actually, that is a correct way to initialize a variable. the ability to use the = operator at declaration is just shorthand for what he is already doing. in other words it doesn't use operator=().
There is a problem he is running into however, and that is he is taking input from 3 words at a time when he doesnt necessarily have that many variables. there is a function getline that will take the entire line and put it into a string, which can later be split into several strings based on some seperator (in this case a space).
NomadRock:
Thx for pointing this out! I totally forgot about that…
xISOx:
In order to avoid confusion about typedef’s and definitions some additional samples:
-definition
#define MAX_VALUE 256
Note the # in front of the definition. That’s because it is a pre-processor command. Here you are basically defining another way to write 256. You can use it wherever it is fitting:
int intValue = MAX_VALUE; // same as int intValue = 256
long longValue = MAX_VALUE; // same as long longValue = 256
char arrayChar[MAX_VALUE]; // same as char arrayChar[256]
As you see you can use it for different types. The compiler simply replaces MAX_VALUE with 256. This is useful when the same value (MAX_VALUE) appears in different places in your source code. If later you want to change your MAX_VALUE then you can only change your definition instead of adjusting it all over your source.
e.g. you set it to
#define MAX_VALUE 512
- typedef’s
These are used to give another name for a type.
typedef myInt int;
Now you have another way to identify a type. In this case an integer.
So this would work:
myInt anInteger = 10;
int anotherInteger = anInteger;
But this would give an error/warning:
myInt anInteger = 10;
long someLong = anInteger;
Here you would mix different types this should at least give a warning from the compiler.
These things are handy to keep your source code readable and make it less error prone. But it’s mostly used in larger sources. It doesn’t really show the benefit in a small source code.
xISOx
10-30-2005, 07:18 PM
Wonderful, thanks for all your help.
But NomadRock... You said that I can seperate the string retrieved by the getline command, but, you didn't really elaborate. This is what I am really needing to do right now :-)
The sourcecode and executable(probably very broken) can be found at the website http://coupdegrace.servegame.com/gt/. Still working on the actual website, but eventually it will have some of the storyline and update news and an actual download page. Right now it's just yucky though.
NomadRock
10-30-2005, 08:01 PM
There are a number of ways you can split a string. Here is a function I found with a quick google search http://www.codeproject.com/string/stringsplit.asp
xISOx
10-31-2005, 06:52 AM
Thanks a ton for all your help guys. I'll try to leave you alone now. I'm sure you're getting annoyed by all my newbish questions.
eddie
10-31-2005, 07:40 AM
I can't speak for the others, but I say don't worry.
Any quesiton sparks intelligent conversation, and everybody learns.
That said, be sure to do your homework, and at least Google search and try to find answers on your own. You're less likely to annoy a cranky person if you've at least done some preliminary research. :)
Yup, don’t worry about that. Everyone has to start at some point. Your initial post clearly shows that you were doing something _before_ asking. And the other posts show that you were using and trying to apply the new found knowledge. That’s the whole point.
If you feel like going a bit advanced, you can have a look at this:
http://www.gamedev.net/reference/articles/article2179.asp
It should give you some idea how you can parse your input in a flexible and solid way.
NomadRock
10-31-2005, 05:09 PM
I especially like that you have started small. All these, I just started programming yesterday, how do I make Quake or an MMORPG threads are what get on my nerves :)
I just reminded myself of something I used in my first code sample. It might not be obvious to someone who started coding. I figured it might be helpful to point that out. So here it comes.
You might have noticed that I used an enumeration (enum) witch is starting with the value “1”. I made this because if you were to have an input witch is not referred in your map then the map returns NULL. As this is a definition for 0 this would prevent to have two different meaning for the value 0. Therefore your switch would still work even if you input some nonsense instead of an actual command.
For the same reason I have the first value in the function pointer array as:
arrayFuncPointers[0] = NotifyInvalidCommand;
If the enum would start at “0” then each time you write something witch is not a command the first function (SafeToFile) would be called instead of NotifyInvalidCommand.
Hope it helps.
xISOx
11-01-2005, 08:46 PM
Alright guys, I have sucessfully implemented a thing to seperate the strings up.
I just now have no idea what to do next.
I have tried to use a switch, but it says that the variable has to be an integer, then I tried an if/else statement, but that didn't work right either.
Then I tried to use a function pointer and a function class, but I am completely lost there, and nothing on the internet I have found helps me have any clue what classes do, it always just shoots right over my head.
So, I am asking something, yet again. How should I handle the cycling through functions, which, surprisingly enough was the beginning topic of this thread. It kind of evolved, and I did some other things.
If you want to take a look at the code, head on over to www.coupdegrace.servegame.com/gt
eddie
11-01-2005, 10:34 PM
I couldn't get a look at your code (is best to just put a snippet up here anyways, so I don't have to glaze over all your code, and it's more perpetual than a hyperlink anyhow), but here's some advice.
Just do a simple if/else if/else set of conditionals. It'll not be pretty, it'll be expensive if you're doing string compares, etc. etc., but who cares. You want to get something running, so get it running, and you can fine tune things later.
i.e.
std::string userInput;
cin >> userInput;
if(userInput == "save")
{
// Do stuff.
}
else if(userInput == "load")
{
// Do other stuff.
}
else
{
// Etc.
}
Do I say the above code is the most performant? No. Do I say that it's most maintainable? Definitely not.
But it seems like you could just use something that works for now, and hone it later. Get something like that working first, and then come back and I'll show you how to do it using function pointers. You'll have a better grasp of it too, once you can get the above working.
Sound good?
xISOx
11-02-2005, 05:49 AM
When I get the if statement to compile correctly, the game crashes when I try to use it.
I have the entered commands and arguments stored in an array of strings, and i am trying to use...
if (strcmp(results[0].c_str(), "lol")) {
lol();
}
else { cout<<"What?"<<endl; }
The program will compile, but when I type lol, a box with a windows aplication error pops up.
if (results[0]=="lol") {
lol();
}
else { cout<<"What?"<<endl; }
Gives me the same error.
Is the error in something other than my if statement?
After debugging, I get the message "An access violation (segmentation fault) raised in your program."
Any idea what causes this?
The lol function only looks like this:
void lol()
{
cout << "You laugh at the success of your command system!" <<endl;
}
Well, it happens whenever I enter any command, so I'm not too sure what to make of it.
It seems to be trying to refrence memory at 0x0000000000, which isn't normal.
nothing on the internet I have found helps me have any clue what classes do
You can think of a class as a recipe for an object. The member variables are the attributes and the member functions of a class define its behaviour.
How should I handle the cycling through functions,
You mean something like this (not using compare strings for simplification):
class Dude
{
public:
int iPosX;
int iPosY;
public:
Dude() { iPosX=0; iPosY=0; };
int MoveNorth()
{
iPosY += 1;
std::cout << "Dude walks north to position x:" << iPosX << " y:" << iPosY << "\n";
return 0;
};
int MoveSouth()
{
iPosY -= 1;
std::cout << "Dude walks south to position x:" << iPosX << " y:" << iPosY << "\n";
return 0;
};
int MoveEast()
{
iPosX += 1;
std::cout << "Dude walks east to position x:" << iPosX << " y:" << iPosY << "\n";
return 0;
};
int MoveWest()
{
iPosX -= 1;
std::cout << "Dude walks west to position x:" << iPosX << " y:" << iPosY << "\n";
return 0;
};
};
int _tmain(int argc, _TCHAR* argv[])
{
// initialisation
Dude theDude;
bool bQuit = false;
while( !bQuit )
{
char c;
std::cout << "Enter command...\n";
std::cout << "1 to quit\n";
std::cout << "2 to move north\n";
std::cout << "3 to move south\n";
std::cout << "4 to move east\n";
std::cout << "5 to move west\n\n";
std::cin >> c;
if( '1' == c )
bQuit = true;
else if( '2' == c )
theDude.MoveNorth();
else if( '3' == c )
theDude.MoveSouth();
else if( '4' == c )
theDude.MoveEast();
else if( '5' == c )
theDude.MoveWest();
}
return 0;
}
For your other problem/crash can you show how you define your array with strings?
monjardin
11-02-2005, 06:30 AM
First of all, strcmp returns zero if the strings match. So, you would need to do this
std::string str("lol");
if( !strcmp( str.c_str(), "lol" ) ) {...}
or
if( strcmp( str.c_str(), "lol ) == 0 ) {...}
However, since you are using std::string now you can just do this:
std::string str("lol");
if( str == "lol" ) {...}
Another thing to keep in mind is that these string comparisions are all case sensitive. For example, "lol" is not equal to "Lol".
I couldn't get to your code either. That looks like a No-IP redirect address. Anyway, the problem is likely with the iniditialization of your string array in the variable "results". I am assuming that results is a std::vector<std::string>? If the vector is empty, then accessing results[0] is a definite problem.
If you are only processing one word at a time then there is no need to grab a whole line and tokenize the string. Try this little program out. I just tested it and it works.
#include <iostream>
#include <string>
// case insensitive string comparison function
bool myCompare( const std::string& lhs, const std::string& rhs ) {
return stricmp( lhs.c_str(), rhs.c_str() ) == 0;
}
int main( int argc, char** argv ) {
std::string input;
while( 1 ) {
std::cin >> input; // reads one word
if( myCompare( input, "hello" ) )
std::cout << "Hello right back at you!\n";
else if( myCompare( input, "std::string" ) )
std::cout << "Sure beats a char*!\n";
else if( myCompare( input, "exit" ) )
break;
else
std::cout << "I didn't catch that there buddy.\n";
}
return 0;
}
xISOx
11-02-2005, 07:12 AM
For the code, try http://12.226.100.42/gt/
I'm gonna try out your code when I get out of school monjardin. Thanks :-)
eddie
11-02-2005, 09:31 AM
xISOx,
I couldn't find the specific area you were talking about in your code, but looking at your playerfunc.cpp, it looks like you're doing a lot of this jazz using character arrays.
I'd recommend against this, foremost because std::string is a lot easier to use.
i.e.:
The C Way Of Doing Things
#include <string.h> // strcmp
#include <stdio.h> // printf
void foo()
{
char *pMyStringOne = "One";
char *pMyStringtwo = "Two";
if(strcmp(pMyStringOne, pMyStringTwo) != 0)
{
printf("Strings don't match!");
}
else
{
printf("Strings match!");
}
}
The C++ Way Of Doing Things
#include <iostream> // cout
#include <string> // std::string
using namespace std; // So we don't have to prefix std:: everywhere.
// Use of this is subjective.
void foo()
{
const std::string firstString("One");
const std::string secondString("Two");
if(firstString == secondString) // Using operator overloading on the class! Whee!
{
cout << "Strings matched!" << endl;
}
else
{
cout << "Strings don't match!" << endl;
}
}
Now that is a small example, and the benefits of the C++ way of doing things vs. the C way are subtle, but they all stem from the beauty of the class system.
You'll notice we don't need to introduce a strange function to do our string compare. Instead, the string class allows us to do a boolean comparison operation against another string class, which makes the code more readable and symmetrical to other conditionals (The operator== is what's called an operator overload: the string class defines it to basically do the same thing as the strcmp() internally anyhow).
The other is the beauty of cout. cout has many benefits over printf, and that is mostly type safety and compile time checking. (If you miss the format-style specification of printf, I suggest you look at the Boost::Format (http://www.boost.org/libs/format/index.html) library.)
That said, perhaps to you, all of what I just mentioned is mostly subjective philosophical fluff that makes me sleep well at night, because I'm an OO bigot, or it's worth isn't readily apparent.
Then here's a compelling reason to use std::string vs. c-style strings:
The C Way Of Doing Things
/**
* Suture two strings together
*/
void MeldStrings()
{
char *pFirstString = "First";
char *pSecondString = "Second";
size_t newBufferLength = strlen(pFirstString) + strlen(pSecondString)
+ 1; // Don't forget the NULL!
char *pDestination = (char *)(malloc(sizeof(char) * newBufferLength);
strcpy(pDestination, pFirstString);
strcat(pDestination, pSecondString);
pDestination[newBufferLength] = 0; // Cap it with a NULL
printf("Melded string = '%s'", pDestination);
free(pDestination);
}
Now...
The C++ Way Of Doing Things
/**
* Suture two strings together.
*/
void MeldStrings()
{
const string kFirstString = "First";
const string kSecondString = "Second";
string destinationString = kFirstString + kSecondString;
cout << "Melded string = '" << destinationString << "'" << endl;
// Boost::Format version.
/*
cout << boost::format("Melded string = '%1%'")% destinationString
<< endl;
*/
}
Now, I've written this code without testing any of it , but I think that actually works to elucidate my point.
Of the code that's more likely not to work, it's the C-style code I've written, rather than the C++. That's because:
* The C++ code has less lines. Less lines = less chance for error.
* The C++ code doesn't have to deal with memory issues. It's all in the class
So, a well written C++ class (the Standard Library is a shining example of such things) will ease your load a great deal..
... I don't know why I made such a big post about this. But I feel bad to edit it now, maybe this isn't completely relevant to you, but it might serve someone. :)
</dismounds off his OO-horse>
xISOx
11-02-2005, 01:09 PM
My fstreams don't like c++ strings. That's why it is written with c-style strings. It works good enough for me.
But now to figure out how to fix this segmentation fault...
http://12.226.100.42/gt/StringUtils.cpp
http://12.226.100.42/gt/StringUtils.h
I got those off codeproject, and they work fine for what the original program did, but when I throw an if statement in there, it goes to hell with the faults.
Could a seg fault be caused by something trying to access a private part of a class?
Any ideas?
eddie
11-02-2005, 01:24 PM
My fstreams don't like c++ strings. That's why it is written with c-style strings. It works good enough for me.
Sorry, slight tangent. Can you explain this further?
What are you trying to do with fstream's that wont let you use c++ strings?
But now to figure out how to fix this segmentation fault...
http://12.226.100.42/gt/StringUtils.cpp
http://12.226.100.42/gt/StringUtils.h
I got those off codeproject, and they work fine for what the original program did, but when I throw an if statement in there, it goes to hell with the faults.
Any ideas?
I need more specific context. Where are you putting the if?
Feel free to use a pastebin like this http://cpp.sourceforge.net/ and send us the link.. File and line numbers to see where you're talking help too. :)
monjardin
11-02-2005, 01:28 PM
You need to make sure that the size of the results vector you get from that string splitter function is greater than the index you are trying to access. If results.size() returns 0 (i.e., results.empty() returns true) and you do this: if( results[0] == "lol" ), then you will likely crash.
xISOx
11-02-2005, 01:40 PM
I'm pretty sure that the results are filled when the user enters something. And, I have a check against null entrys:
firstspace = userinput.find_first_of(blank);
if (firstspace==0) {
cout<<"What?"<<endl;
}
I'm kinda reluctant to put it on that pasteboard, because it's all in different files, and I don't know if i can throw them all together correctly.
Especially the header files... I'll try for you though...
P.S. When I try to replace the strcmp's with compares, it says that there is no matching function for the line. I am happy with the way it works for now though, I'm more interested in fixing this fault.
xISOx
11-02-2005, 01:53 PM
Yummy.
http://cpp.sourceforge.net/?show=9603
So ugly looking.
eddie
11-02-2005, 02:03 PM
find_first_of, I believe functions just like find...
You have to make sure you don't hit myStringImSearching.end()...
Not sure if that's a problem you're hitting.
xISOx
11-02-2005, 02:08 PM
I don't think so, If I uncomment those other lines, it will function and tell me what I entered broken up into seperate strings for every word entered.
The check works for that, no idea why it wouldn't for anything else.
I have noticed some things witch strike my as odd. Though it might not all be related to the problem you are looking for.
The length of all your arrays and such is 20. This is a bit short. Try using a definition instead. I have mentioned it in an earlier post.
#define MAX_LENGTH 128
It’s much easier to adjust.
---
The interface of your login function seams strange too.
void login(char playername[20], char playerpass[20]) {. . .}
I would change it to
void login(char* playername, char* playerpass) {. . .}
---
and I have noticed that you open a file.
ifstream in(playername);
You do that on several places. You only need to open it once. Also you never close the file witch is not so good.
---
userinput is already a string so instead of
getline(cin, userinput);
string in(userinput);
just use
getline(cin, userinput);
and then later call
int num = StringUtils::SplitString(userinput, delim, results);
---
// instead of
firstArg = results[0];
if( stringcmp(firstArg, "lol") )
cout<<"Testing"<<endl;
else
cout<<"What?"<<endl;
// rather use
if( stringcmp(results[0], "lol") )
cout<<"Testing"<<endl;
else
cout<<"What?"<<endl;
// or since you use std::string
if( results[0] == "lol" )
cout<<"Testing"<<endl;
else
cout<<"What?"<<endl;
Be certain that results[0] contains something useful. Try checking it by writing to the console:
cout << results[0];
since results[0] is supposed to be a string it should work.
If that doesn’t work then you might have a problem with your split string function after all. I didn’t check that function.
xISOx
11-02-2005, 06:14 PM
Yeah, that seems to be the problem.
Maybe it has to be converted into a c-style string before it is interpreted?
It seems to work for the lines of code that came with the sample...
I was under the impression that if you use ifstream in(playername); that opens and closes the file again after it does the requested functions.
How would you close it? playername.close(); doesn't work, it says close is undefined.
xISOx
11-02-2005, 06:36 PM
Ehhh, I'm just gonna write my own string seperation module.
Wish me luck.
sample for fileread:
// working variables
char buffer[128];
int iSomething;
// open file
ifstream fin( “filePath” );
if( fin )
{
// read file
fin >> buffer;
fin >> iSomething;
// close file
fin.close();
}
xISOx
11-03-2005, 08:14 PM
Ok, I have added the close statement to my login function.
I have also written up a simple little function to seperate the strings into seperate arguments, but as I only need two arguments, I just dumbed the old one down alot.
I am getting a new error now. When I run the program, it flashes after i enter something, even if I use the debug mode of my compiler.
I ran it in command prompt and got this.
"This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information."
Does this look good to you guys?
int argsep(const string& input, vector<string>& results)
{
int isize = input.size();
int loc = input.find( " ", 0 );
if( loc != string::npos ) {
// Work on the last half first...
string argtwo = input.substr(loc+1);
int loc2 = argtwo.find( " ", 0 );
// See if there are any other spaces after that, and keel them.
if (loc2 == string::npos) { argtwo = argtwo.erase(loc2-1); }
// Now for the first part...
string argone = input;
argone = argone.erase(loc-1);
results.push_back(argone);
results.push_back(argtwo);
}
}
And the call to it in the main.cpp...
do {
getline(cin, userinput);
// Make sure the first character isn't a space, so we don't crash and burn...
firstspace = userinput.find_first_of(blank);
if (firstspace==0) { cout<<"What?"<<endl; }
else if( userinput.empty() ) { cout<<"What?"<<endl; }
else {
vector<string> result;
argsep(userinput, result);
cout<<"First Arg: "<<result[0].c_str()<<"\nSecond Arg: "<<result[1].c_str()<<endl;
}
} while (gameexit<1);
I don’t have much time right now. So just a simple tip.
Make your app run under the condition that the user made a correct input. Once that works you can add error handling. This keeps your code more readable. And it’s much easier to spot errors.
eddie
11-04-2005, 08:46 AM
I apologize for not directly answering your questoin, but maybe this will help you.
I've put together a small extension of the std::string, which is more OO and works for what you're looking for. Let me know if this works for you:
#include <string>
#include <vector>
#include <iostream>
class MyString : public std::string
{
private:
typedef std::string parent;
public:
MyString(parent str)
: parent(str)
{
}
typedef std::vector<std::string> SplitStringResult;
void Split(SplitStringResult &outputResult, std::string delimiter=" ")
{
size_type start = 0;
size_type end;
for(end = this->find(delimiter, start);
end != MyString::npos;
end = this->find(delimiter, start))
{
outputResult.push_back(std::string(*this,start, end-start));
start = end + delimiter.size();
}
outputResult.push_back(std::string(*this, start, end-start));
}
};
using namespace std;
int main(void)
{
MyString str = std::string("ONe two three four");
MyString::SplitStringResult result;
str.Split(result);
unsigned int count = 0;
for(MyString::SplitStringResult::iterator iter = result.begin();
iter != result.end();
++iter)
{
cout << "Result '" << count << "' = '" << *iter << "'" << endl;
++count;
}
return 0;
}
xISOx
11-04-2005, 10:42 PM
I am still getting the "This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information." error.
Anyone have any experience with this?
I'm not using a vector anymore. Is the program trying to close before it even tries to use the argsep function?
It is almost impossible to say what happened due to an error message if you do not have the source code.
You could have something like
cout << “my app reached this point \n”;
then place it after every function you call. This should give you a hint how far you get before crashing.
Another tip would be to only code one step at a time. For an instance you have a login function (do you actually need this?) and a string split function. Only use one until it works and then move on to additional code improvements or additional functionality.
eddie
11-05-2005, 06:46 PM
The debugger is your friend. :)
I already had it that the app would compile perfectly nice but the app crashes when running it. Somehow I thought that’s what he meant. Anyway you are right the debugger is your friend :)
You could also enter the entire text from your error message into google and then search. Normally that works quite well too.
eddie
11-05-2005, 08:58 PM
Ah, I see what you're saying..
Well, even still. If you're using MSVC you can step into the program initialization, even before the main, so you'll be able to see where things futz up.
But I imagine what you're seeing xISOx is something in your program logic that's doing something crazy.
I recommend two things:
- Step through the debugger and see what line is causing the crash.
- Utilize the Boost Program Execution Monitor for when you actually push this application out to clients, as it will catch all gross manner of exception and translate it into something more human readable.
Just my two cents. :)
TheNut
11-06-2005, 04:40 AM
It's a bit late, especially after all the work you've put in, but an alternative to all this is to use a finite state machine. It works like wonders especially for a text based game. You don't have to worry about switch/if/else statements. The FSM handles all that for you, so your main code is kept clean and organized.
Check out my article (with source code) here on devmaster: http://www.devmaster.net/articles/fsm_intro/. The article/code is a bit out of date compared to my latest, but it should get you started onto something really handy.
xISOx
11-06-2005, 11:35 AM
Ehh, I didn't really put that much into it, just kind of messing around with a bunch of stuff.
Thanks for the reccomendation. I'll be checking that out shortly. :yes:
vBulletin, Copyright ©2000-2010, Jelsoft Enterprises Ltd.