Greetings,
Since my last question about C++, I actually learned quite an amount. I am now comfortable with classes, just not so comfortable with pointers and references yet.
Please note, I am not asking you nesceserally to solve my problem, I'm asking why I'm not getting the wished result.
here are some code snippets that that should help me explain the problem:
Im making a console based tic-tac-toe game(recently started learning C++, this imo is a good way for it)
main.cpp:
//Here I initalise 1 variable and an array
int move;
char board[9] = {' ',' ',' ',' ',' ',' ',' ',' ',' '};
First question: Is there a better way to define empty spaces in a char array?
The reason i'm doing it like this is, I want my tictactoe board to contain an empty space when an X or O has not been set yet.
main.cpp:
if(referee.validateMove(board, move))
{
board[move] = player2.getToken();
displayBoard(board);
}
What happens here is easily understood but i'll explain anyway;
A call to the validateMove method from the object referee is made, and passed 2 paramaters, the move that the player has selected (in between 0-8). and the tictactoe board.
Referee.cpp
bool Referee::validateMove(const char (&board)[9], int& move)
{
if(board[move] != 'X' || 'O')
{
return true;
}
else
{
return false;
}
}
Here is where the main trouble is, and my last question arises.
As seen before, I passed an array of chars with a size of 9.
The reference to the move variable works well(should i use a reference or pointer?) and it contains the wished result.
At this point, say player 1 just made its move and placed a token in position 2
I now want to place my token as PLAYER 2 on position 2
When I debug with visual studio, I get the following:
0x0024faa8 " O ÌÌÌÌÌÌÌÌÌÌÌ"
This is when i hold my mouse on the board parameter.
So the board does know, it is occupied.
Why however does the validateMove method always return true, and is board[move] never equal to O or X?
Thank you for taking the time to read my problem. If you have a question, or I explained something in a stupid matter, you see invalid naming conventions, please notify me. I am a student, and I want to pick up as much as possible.
This problem is resolved. Thanks for those who have answered. Highly appreciate it.
Your condition boils down to this:
if((board[move] != 'X') || ('O'))
'O' will always evaluate to true in this case, so you always pass the condition. What you want is this:
if((board[move] != 'X') && (board[move] != 'O'))
To verify, this code runs fine for me:
#include <iostream>
bool validateMove(const char (&board)[9], int move)
{
if((board[move] != 'X') && (board[move] != 'O'))
{
std::cout << "True" << std::endl;
return true;
}
else
{
std::cout << "False" << std::endl;
return false;
}
}
int main()
{
char board[9] = {' ',' ','O',' ','X',' ',' ',' ',' ',};
validateMove(board, 0);
validateMove(board, 2);
validateMove(board, 4);
}
The output is:
True
False
False
The reason you're displaying extra junk at the end is that your
"board" isn't a nul terminated string. If you also want to use
it for display purposes, you'll need to declare it board[10],
and add a '\0' at the end. From a design point of view,
however, I would recommend against this. I would, in fact,
define a Board class, with a << operator to display it, so that
I could change the representation at will, without having to
modify the framework. If the representation within the board
class is a char[9], and the board values are the actual
characters, then you could simply memcpy the board into
a char[10], append the missing '\0', and output that. Be ready
to adopt a more complex solution later, however, if you find
that char[3][3] is a better representation, or that it is
preferable to use, say 0, -1 and 1 as the status of a position
on the board. (I'd probably have the board class responsible
for determining the legality of a move, too.)
And while I'm at it: your validateMove function should be:
return board[move] == 'X' || board[move] == '0';
or perhaps even simpler:
return board[move] == ' ';
You were ||'ing with '0', which, converted to bool, is always
true. And an if which returns true or false is unnecessary
complication and clutter, and suggests that the author either
doesn't understand the concept of 'bool', or is intentionally
trying to obfuscate the code.
Related
bool guess(char c)
{
if (guesses[c])
{
guesses[] = c;
return true;
}
else if (c > ='a' && c <= 'z')
{
guesses[] = c;
return false;
}
}
bool guesses[255] = {};
I need to use this to see if the person has enter a char between a - z and if they haven't I return true else I will return false. either way I will also update guesses with the char. Right now I don't understand how to add char to the array, so that next time I check the it will be false and tell them it was already guessed. I understand this is using the ASCII table but beyond that I am lost. Could anyone explain why this won't work.
I currently get the error
expected primary-expression before']'
but if I take bracket out I get
incompatible type char to bool
which make sense but then how do I make it so where char c is will be mark true in the Boolean array
You've left your brackets empty, so you currently aren't providing an index:
guesses[c] = c;
But you also don't want to assign the char to guesses, you'd want to assign a bool:
guesses[c] = true;
That will compile* and fix your problem.
* Note you also have a syntax error with > =, which I assume was just a copy+paste issue from the editor to the question, but you should fix that also to be >=. Your function guess can also potentially not return (if neither the if or else if are true), which is undefined behaviour. You should ensure all control paths return a value, and you should make sure you compile at the highest warning level so you are warned about these things.
But not your design.
Since you're only dealing with characters a-z, you don't need to allocate all 255 elements like you do. You could simply minus the character to obtain the correct index:
bool guesses[26];
if (c >='a' && c <= 'z')
guesses[c-'a'] = true;
Consider instead using a std::set, a container of unique elements, to track whether a character has been pressed:
#include <set>
std::set<char> guesses;
bool guess(char c)
{
// Have we already inserted this character?
if (guesses.find(c) != std::end(guesses))
{
// Character has already been guessed:
std::cout << "This character has already been guessed";
return true;
}
else if (c >= 'a' && c <= 'z')
{
// Valid guess:
guesses.insert(c);
return false;
}
}
I've written the code bits below. I have a constructor which takes five arguments. Unfortunately, the setGender method spits out a default 'M' for all instances of a class rather than setting the gender to the specified parameter. What am I doing incorrectly? Any advice would be greatly appreciated. Thank you.
DateProfile::DateProfile(char gdr,
char searchGdr, int romanceScale, int financeScale, string theName)
bool DateProfile::setGender(char gdr)
{
if (gdr != 'M' || gdr != 'F')
return false;
gender = gdr;
return true;
}
if (gdr != 'M' || gdr != 'F') is always true, irrespective of input. If you're passing 'M', the second part of the expression is true. If you're passing anything else, the first part of the expression becomes true.
What you meant to write is if (gdr != 'M' && gdr != 'F') instead.
Increasing the warning level of your compiler may have helped you spot the error. Most compilers will warn about expressions always evaluating to a single value, or at least about the unreachable code following it.
This is a group assignment and it's become rather difficult to the point our professor has extended the project by 1 week. there are 50 stages/tests, we've only been able to reach up to stage 11 and then the function fails.
this function is in our .cpp file (we're positive it's this function causing the problem's because when we change parts of it, it affects stage 11 which we've passed).
int segment::match(const char word[]) {
int i;
cout << data[0];
data[0] == "OOP";
cout << data[0];
for(i=0;i<NUM_MAX;i++) {
cout << "word = " << &word[i] << " data[i] = " << data[i];
if(strstr(&word[i],data[i])!= NULL)
break;
}
return i==NUM_MAX ? 1 : i-1;
and from the main.cpp (provided to us as the assignment) this is the what we are trying to accomplish
Passed test 11...
Your match( ) return value ----> -1
Actual match( ) return value --> -1
Press the ENTER key to continue...
word = OOP data[i] =
Failed while testing the match( )
function... Failed on test 12...
Your match( ) return value ----> -1
Actual match( ) return value --> 1
Press the ENTER key to continue...
You passed 11/50 tests...
Your program is 22.00% complete!
Your program still needs some work!
Keep at it!
what the function is suppose to do is check for "oop" and if it isn't there it exits with -1, and if it is there it should return true with 1.
I guess what I'm asking is how do I make that function that it returns both -1 and 1 in the proper order?
If you would like access to the main.cpp and segement.cpp i can upload that as files somewhere because they're very long and I did not want to cram the post.
Any help is appreciated, thank you.
EDIT*
Here is the full code that we have
http://jsfiddle.net/h5aKN/
The "html" section has the segement.cpp which is what we built.
and the jscript section has the a2main.cpp which is what our professor built.
data[0] == "OOP"; is probably not what you want to do. The double = (==) tests for equality, so here you're testing if the item at the first index of data (data[0]) and the character string "OOP" are equal.
In the running of the test, you are cout'ing: word = OOP data[i] =, which means that word[i] is probably defined correctly, but data[i] is not. This goes back to the usage of the equivalence test above.
If you set initialize data correctly, (correctly meaning allocating the memory correctly, I don't know where data is instantiated), then the test would likely return -1, as it would get a non NULL pointer from the strstr() call (assuming that data is the correct type), i would be 0 on breaking, and the ternary operator would yield i-1, = -1.
So fix the initialization / assignment of the data variable
And if you're not limited to c style strings (char arrays), I'd use the std::string type and its associated methods (see the c++ string reference if you haven't already). Usually much nicer to work with
If you are passing a list of words to the function:
As the use of (strstr(&word[i],data[i])) suggests you are looking for a string inside another string. Thus you are looping over a list of strings (words).
Then this looks wrong:
int segment::match(const char word[]) {
Here you are passing one word.
Its impossable to tell what it should be, but a guess would be:
int segment::match(const char* word[]) {
// ^^^^^
But to be honest the whole thing is rather ugly C++. If you were writting C I would say fine, but if you had been writing C++ correctly the type system would have saved you from all these problems. Use std::string to represent words.
The error I'm getting is error: expected ' ; ' before ' { ' token
I tried fixing the code by adding ; after if (thisisanumber==5) as well as after else (thisisanumber!=5). While this solves the first error it creates another error that says error: ' else ' without a previous ' if '. I'd really love to know what error I've made in writing the code, thanks.
Here is my code:
#include <iostream>
using namespace std;
int main()
{
int thisisanumber;
cout<<"Whats the Password?: ";
cin>> thisisanumber;
cin.ignore();
if (thisisanumber==5) {
cout<<"You've discovered the password! Wow, you're a genious you should be proud./n";
}
else (thisisanumber!=5) {
cout<<"You've failed in knowing the password and therefore cannot enter, leave and do not come back. Goodbye!/n";
}
cin.get();
}
You're missing a keyword if:
else if (thisisanumber!=5) {
^^
Alternately, since the opposite condition to thisisanumber == 5 is that thisisanumber is not 5, you don't need the condition:
else {
You don't need another condition as there are only two cases - just use else { ... } and it will catch all cases in which thisisanumber==5 is false.
The structure of an if statement is:
if (condition) { ... }
else if (another condition) { ... }
// ... more conditions
else { ... all cases in which no previous condition matched end up here ... }
... but the else if and else parts are always optional.
What happens is the compiler looks at the following:
else (thisisanumber!=5) {
and thinks to itself:
"OK, here's else. Is the next token if? No. Ok, so this is an else clause, and the next thing is what to do in the else-case. Is the next token {? No. Ok, so in the else-case, we execute a single statement, instead of a block. Is the next token (? Yes. Ok, so our statement is wrapped in parentheses... [insert here: the rest of the thought process for interpreting an expression that's wrapped in parentheses] Ok, there's the matching ). Whew. Now let's just match up the ; for this statement... wait, what's this? A {! That's not right."
The compiler is reading the code one token at a time, left to right. It does not report an error at the point where, in a logical sense that humans understand, the error actually is. It reports an error at the point where, by reading the code one token at a time, left to right, it is first able to detect that something is wrong.
It would be legal to write else (thisisanumber!=5);. That would mean "if the number is not equal to 5 (because the if test failed), then check if the number is not equal to 5, and do nothing with the result of that comparison". Meaningless, but legal. It would also be legal to write else if (thisisanumber!=5) {...}, which is presumably what you meant. That would mean "if the number is not equal to 5 (because the if test failed), and the number is not equal to 5, then do this stuff inside the {}". But this is redundant: given that something is not equal to 5, it is guaranteed to be not equal to 5, so there is no point in specifying the test twice. So we should just write else {...}.
"else" is really a shorter word for "otherwise", and has that purpose in C++ as well.
This is a lab assignment I am stuck on.
I need to accept this grammar (ab)*b, which basically means any number of "ab" and ending with b.
I have written this code but somehow, it checks only the first 2 letters.
#include <iostream.h>
#include <conio.h>
#include <string.h>
enum track {true, false};
void main()
{
clrscr();
char*str;
enum track track_pos, track_pos_2;
cout<<"enter the string: ";
cin>>str;
int len=strlen(str);
cout<<"length of the string is "<<len;
getch();
int i;
for(i=0;i<len; i++)
{
++str;
cout<<"loop"<<i;
if(*str=='a' && i%2==0)
{
cout<<"\nchecking a...";
track_pos=true;
cout<<"\na.check";
++str;
if (*str=='b')
{
cout<<"\nchecking b...";
track_pos=true;
cout<<"\nb.check";
}
else{
track_pos=false;
cout<<"\nb.uncheck";
}
}
}
if(*str=='b')
track_pos_2=true;
else
track_pos_2=false;
if(track_pos==true && track_pos_2==true)
cout<<"\nThe string is accpeted.";
else
cout<<"\nThe string is rejected.";
getch();
cout<<"\n\nDo you want to continue (Y/N)? ";
char ch;
cin>>ch;
if(ch=='y' || ch=='Y')
main();
}
I'm going to regret this, but each time I look at this question I see something else wrong with your code. Here is the line by line. I've probably missed a lot.
The correct name for this header is "iostream", not "iostream.h" - the ".h" version is deprecated. Similarly, use "string", not "string.h" in modern C++, and use the modern STL string classes.
#include <iostream.h>
#include <conio.h>
#include <string.h>
As pointed out, don't do this. You have redefined the standard bool type to have the opposite value from the standard types. I don't even know that this is legal.
enum track {true, false};
The return value of the main function is int, not void.
void main()
{
clrscr();
Do you know what a buffer overflow is? You have defined str as a pointer here, with no allocated memory, and you write to that undefined bit of memory a bit later on. This is undefined behaviour, and you are pretty much guaranteed to crash. I recommend, you should defined str as a std::string - this will nicely avoid the buffer overflow, and it has many useful methods that you can use in your program.
char*str;
enum track track_pos, track_pos_2;
cout<<"enter the string: ";
This is the buffer overflow right here. You are writing to who knows what area of memory.
cin>>str;
If str was a std::string - you would do size_t len=str.length();
int len=strlen(str);
cout<<"length of the string is "<<len;
It's probably not a good idea to mix console IO functions like this with iostreams functions - there are some buffering issues that can lead to difficulties.
getch();
Declare i in the body of the loop, since you aren't using it again. Like so:
for (int i=0; i<len; i++) etc...
int i;
for(i=0;i<len; i++)
{
Instead of using poiter arithmetic, since you are keeping track of the index of the current character in i, just use that and treat str as an array. This way, you don't have to keep str in synch with i all of the way through. This is the cause the bug you are reporting, by the way.
++str;
cout<<"loop"<<i;
You should change this to:
if (str[i]=='a' && i%2==0)
(That works even if str is a std::string by the way, unlike the pointer arithmetic version).
if(*str=='a' && i%2==0)
{
You really should drop out at some point, if you figure out that the string doesn't match, then there is no point going on to the end of the string.
cout<<"\nchecking a...";
I don't favour status flags like this - your code is partly hard to understand because of the proliferation of these flags, you cannot keep track of the proper behaviour. The name track_pos is not mnemonic, that makes it hard to work out what it is meant to signify without detailed study of the code.
I would recommend that you would refactor your code inside the body of the for loop to call a function, the purpose of which is simply to match a single group of "ab" - this function could return true if it did, and false if it did not.
track_pos=true;
cout<<"\na.check";
Note that since we are dealing with the buffer overflow mentioned before, you are iterating undefined memory. Also note that you did not increment i here.
++str;
if (*str=='b')
{
cout<<"\nchecking b...";
track_pos=true;
cout<<"\nb.check";
}
else{
track_pos=false;
cout<<"\nb.uncheck";
}
}
}
When we get to here, according to your for loop, we have iterated the whole string, so we must be looking past the end of the string (even ignoring the buffer overflow) so there is no possible way this test can succeed. In short, your for loop must be going too far.
if(*str=='b')
track_pos_2=true;
else
track_pos_2=false;
if(track_pos==true && track_pos_2==true)
Should I mention the spelling mistake?
cout<<"\nThe string is accpeted.";
else
cout<<"\nThe string is rejected.";
getch();
cout<<"\n\nDo you want to continue (Y/N)? ";
char ch;
cin>>ch;
If you refactor your code into appropriate sub-routines, you will find the structure of the program takes care of itself. Note that calling main recursively is not strictly illegal, but it is kind of weird and has an obvious vulnerability that will lead to an eventual stack overflow, if the program never exits.
if(ch=='y' || ch=='Y')
main();
}
Implement a simple state machine. It has these states:
0 = start
1 = 'received a of (ab)'
2 = 'received b of (ab)'
3 = 'received final b'
-1 = error, invalid grammar
Then you just need a function like this:
int nextState(int currentState, char inputChar) {
if (currentState == 0 && inputChar == 'a') return 1; // handled string is "a"
if (currentState == 0 && inputChar == 'b') return 3; // handled string is "b"
if (currentState == 1 && inputChar == 'b') return 2; // handled string is "ab", or "abab", or ...
if (currentState == 2 && inputChar == 'a') return 1; // handled string is "aba", or "ababa", or ...
if (currentState == 2 && inputChar == 'b') return 3; // handled string is "abb", or "ababb", or ...
return -1;
}
Iterate this "state machine" over your input chars, starting with state 0, and if you end up in state 3, your input is valid.
int isValid(char* inputString) {
int state = 0;
for(int i=0; i<str_len(inputString); i++) {
state = nextState(state, inputString[i]);
}
return (state == 3);
}
Things wrong with your code:
#include <iostream.h>
should be:
#include <iostream>
The following is a non-standard (and very old) header:
#include <conio.h>
The following is illegal - true and false are reserved words.
enum track {true, false};
In C and C++, main must return an int:
void main()
Non standard function:
clrscr();
No memory allocated to this pointer:
char*str;
which is then used here - result undefined behaviour:
cin>>str;
Illegal call to main:
main();
I suspect you are using a very old and obsolete C++ compiler. You should replace it with something like MinGW.
Don't do this!
enum track {true, false};
Here your true is equal to 0 and false is equal to one! When you later assign track_pos, you may get the wrong value! (Because when converting bool to int, true converts to 1 and false converts to 0.)
That's only a guess though. Maybe it's something else that matters.