I am writing the hangman game in C++ and I was wondering how I can make sure that the word that my first user inputs just contains alphabetic characters, nothing else. I have to prompt the user to enter a new word when the word that they have already entered is not valid.
there are functions I use to do that but for some my check boundary function does not work properly. Please help, I have no idea how to fix it. In my first function I ask the user's input but and then I use another function to error check this word.
word1 is the array that has stored my first word, and I assume that the letters are all in lower case for now . so I use the ASCII value of the characters to make sure that it is within the boundary. but say if I enter 45 it does ask me to reenter the word but the second word will be accepted no matter what it is . it could be |*%^% it accepts it anyway.
void CheckBound (char word1[], int SIZE1)
{
int i;
int w1[SIZE4];
int found;
for (i=0;i<strlen(word1);i++)
{
w1[i]=(int)word1[i];
if (w1[i] >= 97 && w1[i] <= 122)
found=1;
else
{
printf("Please re-enter your word: ");
fgets(word1, SIZE1, stdin);
word1[strlen(word1)-1]='\0';
printf("%s \n", word1);
}
}
return;
}
When you detect a non-alphanumeric character, you are still in the first loop iterating over each character of word1. Once the user has entered a new word, the loop continue with i!=0, which is of course incorrect.
Try this instead:
oid CheckBound (char word1[], int SIZE1)
{
int i;
bool ok = false;
while(!ok)
{
ok = true;
for (i=0;i<strlen(word1);i++)
{
int c = word1[i];
if (c < 97 || c > 122)
{
ok = false;
break;
}
}
if(!ok)
{
printf("Please re-enter your word: ");
fgets(word1, SIZE1, stdin);
word1[strlen(word1)-1]='\0';
printf("%s \n", word1);
}
}
}
By the way, this is C, not C++.
typical C++ would use:
std::string instead of char array/char pointers for storing strings
std::vector, std::array for arrays (instead of plain C arrays)
streams for printing and inputting text
Related
This question already has answers here:
Reading a password from std::cin
(4 answers)
Closed 7 months ago.
I want to mask my password with "*" while the user is inputting it in. I used the getch() function but it accepts backspace and return as characters.
This is the code I have written:
#include <iostream>
#include <conio.h>
using namespace std;
int main()
{
char password[7];
char PASSWORD[7]="abc123";
pass:
cout<<"Enter the 6 character password: "<<endl;
for(int i=0;i<6;i++) {
password[i]=getch();
cout<<"*"; //To mask the user input with '*'
}
cout<<endl;
if(strcmp(password,PASSWORD)==0) {
cout<<"LOGIN SUCCESSFULL..."<<endl<<flush;
system ("PAUSE");
}
else{
cout<<"Incorrect Password;"<<endl;
goto pass; //goes back to "pass:" and asks for password input again.
}
return 0;
}
Please how can I make it accept numbers and alphabets only.
You can check if what is entered are numbers or alphabets, and ignore the input otherwise.
for(int i=0;i<6;) {
password[i]=getch();
if (isalnum(password[i])) {
cout<<"*"; //To mask the user input with '*'
i++;
}
}
You should add #include <cctype> to use isalnum().
First of all, the standard warning: this method of checking a password has essentially no security at all, so don't use it for anything where security actually matters.
You can write a small "editor" that knows how to deal with backspace and carriage return characters.
bool IsAlnum(int ch) {
if (ch < 0 || ch > 255)
return false;
return isalnum(ch);
}
// use getch() to read a keystroke, including possible extended keystroke
int getkey()( {
int ch = getch();
if (ch == 0 || ch == 0xe0) { // if it's an extended key
ch = (ch << 8) + getch(); // return lead byte + extended byte
}
return ch;
}
void readpassword(char *dest, size_t length) {
int pos = 0;
for (;;) {
// when they press return, we're done
if (ch == '\r') {
dest[pos] = '\0';
return;
}
// if it's alphanumeric, add it to password, if there's length
if ((IsAlnum(ch)) && pos < length) {
char[pos++] = ch;
printf("*");
}
// if it's a backspace and there's at least one character entered,
// erase the last character
if (ch == '\b' && pos > 0) {
printf("\b");
--pos;
}
}
}
Note that if you use getch() on its own, you can run into problems, if the user presses something like a cursor key. These are read as two consecutive bytes, and if you don't read them together, the second byte will contain a value you don't want.
Though it's rarely useful for passwords, you can add support for more keys pretty much the same way, if you want (e.g., cursor keys, control-cursor to move by word, and so on). If you're going to support many more, you may want to use a switch statement instead of if statements (but switch doesn't work all that well with a Boolean function like isAlnum).
I am making a cypher program for my C++ project. My approach is to declare and initialise two strings, the first one being alphabet and the other being key, as shown below.
string alphabet {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
string key {"ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba"};
I want to pair all these 52 letters to one another in the cypher. That is, small a is replaced with capital Z, small b with Y and so on.
The user will be prompted to enter a string, which will be stored in input. My idea is to loop through the input string and match it with alphabet, and hence find out its pair in key string. This is easy, since the pairs will have the same index. However, how do I swap them? I can use a loop in swap(input[i], key[i]) but that will just make every string as ZYXW... I am not able to write the logic here... Below is my code till now in entirety.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string alphabet {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
string key {"ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba"};
int choice {};
cout<<"Welcome to the Cypher Program";
cout<<"\nYou can encode and decode your messages to make sure they remain secret!";
cout<<"\nWould you like to encode(Press 1) or decode(Press 2) a message?"<<endl;
cin>>choice;
//Encoding
if (choice == 1)
{
string input {};
cout<<"Enter a string to encrypt"<<endl;
getline(cin.ignore(), input); //testString
cout<<"Your encrypted message is: "<<endl;
for(int i {0}; i<input.length(); i++){
swap(input[i], key[i]);
}
cout<<input; //ZYXWVUTSRQ
}
return 0;
}
What I really want to do is:
Get input from user
For each letter in input, find out its index in alphabet
Using this index, swap the character with key.
Display the new string back to user.
I'm going to discuss two simple approaches here.
First is to just do what you've suggested in the first place, find the index of the letter from alhphabet and use that index to find encoded letter from key.
You can use a simple trick here by observing the pattern in your encoding. Whenever it's an uppercase letter, you can just subtract 'A' from its ASCII value to get offset and subtract that offset from ASCII value of z to get encoded letter. You can notice similar pattern when it's a lowercase letter.
Below is the sample code for both approaches.
#include <iostream>
#include <string>
using namespace std;
int main(){
string alphabet {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
string key {"ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba"};
string input1 {"testString"}, input2 {"testString"};
cout<<"Your encrypted message is (Approach 1) : "<<endl;
// Approach 1
for(int i {0}; i<input1.length(); i++){
int idx;
for(idx=0;idx<alphabet.length();idx++) // find index from alphabet
if(input1[i]==alphabet[idx])
break;
input1[i] = key[idx]; // replace with key
}
cout<<input1<<endl; //GVHGhGIRMT
// Approach 2
cout<<"Your encrypted message is (Approach 2) : "<<endl;
for(int i {0}; i<input2.length(); i++){
if(input2[i] >= 'A' && input2[i]<='Z')
input2[i] = 'z' - (input2[i]-'A');
else if(input2[i] >= 'a' && input2[i]<='z')
input2[i] = 'A' + ('z'-input2[i]);
}
cout<<input2; //GVHGhGIRMT
return 0;
}
Output
Your encrypted message is (Approach 1) :
GVHGhGIRMT
Your encrypted message is (Approach 2) :
GVHGhGIRMT
Step 1: Find index of character in original string
if (input[i] >= 97)
{
index = input[i]-97;
}
else
{
index = (input[i]-65) + 26;
}
now use
input[i] = key[index];
Hm, your original code was not that bad. You just need to replace the swap with an assignment. That leaves you originla data untouched.
input[i] = key[alphabet.find(input[i])];
Youd should add const before "alphabet" and "key" then the compiler would have prevented your code.
By the way, with this symmetric key, encoding and decoding is the same.
Not sure why you are writing getline(cin.ignore(), input); instead of getline(cin, input);. That should be corrected.
The calculation approach has the advantage that the key string will not be in exe file.
You could calculate the result also with XOR 255 (result += input[i] ^255, which flips all bits, or with 256-input[i];
Below a "more modern" C++ solution using the std::transform-algorithm
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
// The encoding alphabet and key
constexpr std::string_view alphabet{ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ _" };
constexpr std::string_view key{ "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba_ " };
// String to encrypt
std::string message{"Hello world"};
// Here we will store the result
std::string result;
std::transform(message.begin(), message.end(), std::back_inserter(result), [&key, &alphabet](const char c)
{ size_t pos{ alphabet.find(c) }; return (pos != std::string::npos) ? key[pos] : '_'; });
// Show result
std::cout << "\nEncrypted: " << result << "\n";
message = result;
result.clear();
std::transform(message.begin(), message.end(), std::back_inserter(result), [&key, &alphabet](const char c)
{ size_t pos{ alphabet.find(c) }; return (pos != std::string::npos) ? key[pos] : '_'; });
// Show result
std::cout << "\nDecrypted: " << result << "\n";
return 0;
}
#include<iostream>
#include<string>
#include<array>
#include<locale>
using namespace std;
class endeMachine
{
public:
int findIndex(char letter)
{
int index = 0;
while (letter != alphabet[index])
{
index++;
}//end while letter test
return index;
}//findIndex
string subEncrypt(string clear)
{
string subString = clear;
for (int i = 0; i < clear.length(); i++)
{
subString[i] = substitution[findIndex(clear[i])];
}//end for
return subString;
}//subEncrypt
string transEncrypt(string clear)
{
string subString = clear;
for (int i = 0; i < clear.length(); i++)
{
subString[i] = alphabet[findIndex(clear[i]) + offset];
}//end for
return subString;
}//transEncrypt
private://---------------------------------------------------------
array<char, 26> alphabet = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' };
array<char, 26> substitution = { 'm','l','k','j','i','h','g','f','e','d','c','b','a','z','y','x','w','v','u','t','s','r','q','p','o','n' };
int offset = 3;
};//end endoMachine
int main()
{
endeMachine text;
string clear_text = { "Hello" };
cout << text.subEncrypt(clear_text) << endl;
cout << text.transEncrypt(clear_text) << endl;
cin >> clear_text;
}//end main
So in this program I am trying to eventually get to the point where it can:
Encrypt a string entered by the end user
Choose between a substitution or transposition method for the encryption
Decrypt the string previously encrypted post-entry
Choose between either one of the encryption methods to do so
Decrypt the encrypted string without knowing the method of encryption, therefore generating all possible results
My problem is:
When the input string contains an uppercase letter, the whole program shut downs. However if I do something in line 12 like:
while (tolower(letter) != alphabet[index])
the encryption methods both work, but return the strictly lowercase version of the originally input word, making the input of "Hello" result in:
fibby
knoor
upon output, rather than:
Fibby
Knoor
This means that in some way, I need to check for the capitalization of each letter in the word individually, so when it comes time for output, the corresponding letter of the ciphered string can be capitalized before it is output to the screen.
PLEASE HELP!!!
Your findIndex function will fail if an UPPER case char is passed.
The reason is it uses the constant arrays below:
array<char, 26> alphabet = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' };
array<char, 26> substitution = { 'm','l','k','j','i','h','g','f','e','d','c','b','a','z','y','x','w','v','u','t','s','r','q','p','o','n' };
So it will not find a match for an UPPER case letter, and your while loop means your index value returned will be out of bounds....That is 1 more than your array size.
You can:
Check if char is upper case
convert to lower case
process via your functions as normal
if it WAS uppercase, then set your encrypted char to uppercase
...And repeat in reverse for decryption I guess.
There are ugly and elegant ways to check if a char is uppercase...
Ugly:
Convert to lower case and compare with original..Are they the same? If not, Original is upper case. This is probably more portable across similar languages. tolower function here.
Elegant:
The char values (for normal English) uppercase characters are between and including 65 and 90. You could check for the char value in this range
I want to write a program in C or C++ which takes a string as a input character by character and gives output when enter key is pressed. I have to take the input character by character.
while (1)
{
scanf("%c",&a); //cin>>a;
if(a=='\n')
break;
//do operation on the character
}
//give output
something like this but I am not able to do it.
IIUC, you're looking for the getchar function:
while (1)
{
char c = (char)getchar();
if(c=='\n')
break;
//do operation on the character
}
//give output
Ideally your code should work properly.
Since a scanf reads a character and stores it.
What is the error/output you are getting?
Also try comparing (a==10)
10 is the ascii value of '\n'
Try this:
int main()
{
char str[100],c;
int i =0;
while((c=getc(stdin)) != '\n')
{
str[i] = c;
i++;
}
str[i] = '\0';
printf("%s",str);
return 0;
}
Here is one way:
char ch;
while(1)
{
if((ch=getchar())=='\n')
break;
}// its working fine
And another way:
char ch;
while(1)
{
scanf("%c",&ch);
if((ch=='\n'))
break;
}
I am working on a "dictionary" for my class. I have an int array called NumOfWordsInFile[] where NumOfWordsInFile[0] corresponds to how many words are in A.txt and NumOfWordsInFile[25] corresponds to Z.txt
As it is now I have a huge switch for the 26 different conditions of letters. I have a function called AddWord(string word). AddWord gets the first letter of the word passed to it and inserts it into the appropriate .txt file. Now here is the problem. Everytime a word is added to A.txt I must increment NumOfWordsInFile[0] by 1. The only way I can think of to do this is with these huge switches. I also have a deleteWord function which conversely decrements NumOfWordsInFile[] if the word is deleted. Now I dont want to have two 26 case swithes but the problem is I dont know how else to do it. Now I could just do the same thing for the delete function but I really dont want to have hundreds of more lines of code to go through. Is there a better way to do this?
Sample of the switch in the AddWord function:
case 'w':
if (numOfWordsInFile[22] < maxWordsPerFile) {
fout.open(fileName.data(), ios::app);
fout << word << " " << endl;
numOfWordsInFile[22]++;
if (totalWordsInDict < maxWordsInDict) {
totalWordsInDict++;
}
return(Dictionary::success);
} else {
return(Dictionary::failure);
}
case 'x':
if (numOfWordsInFile[23] < maxWordsPerFile) {
fout.open(fileName.data(),ios::app);
fout << word << " " << endl;
numOfWordsInFile[23]++;
if (totalWordsInDict < maxWordsInDict) {
totalWordsInDict++;
}
return(Dictionary::success);
} else {
return(Dictionary::failure);
}
Delete function.
bool Dictionary::DeleteAWord(string word)
{
ofstream fout;
ifstream fin;
string x;
string fileName="#.txt";
int count=0;
vector <string> words;
bool deleted=false;
fileName[0]=toupper(word[0]);
fin.open(fileName.data()); //makes the file depending on the first letter of the argument "word"
while (fin >> x)
{
words.push_back(x);
count++;//number of elements in vector
}
if (SearchForWord(x))
{
for ( ;count > 0; count--)
{
if (words[count-1] == word)
{
// cout << "Found word " << word << " during search, now deleting" << endl;
words.erase(words.begin()+(count-1));
deleted = true;
/*
This clearly doesn't work and is what I need help with, I know why it
doesn't work but I don't know how to make it better than having another
huge switch.
*/
numOfWordsInFile[toupper(word[0])]--;
/*
*/
totalWordsInDict--;
fin.close();
}
}
if (deleted)
{
fout.open(fileName.data());
for (int i = 0; i < words.size(); i++)
fout << words[i] << endl;
return(Dictionary::success);
}
return(Dictionary::failure);
}
return(Dictionary::failure);
}
Just taking a very quick look, it seems like you're using the position of the letter in the alphabet to do stuff.
You could replace all your switch statements with one statement that looks like:
int letter = (int)(ActualLetter - 'a');
if(numOfWordsInFile[letter]<maxWordsPerFile){
fout.open(fileName.data(),ios::app);
fout<<word<<" "<<endl;
numOfWordsInFile[letter]++;
if(totalWordsInDict<maxWordsInDict){
totalWordsInDict++;
}
return(Dictionary::success);
}else{
return(Dictionary::failure);
}
ActualLetter is something like, 'a', for example.
On a related note, in the future if you actually have large switch statements, consider encapsulating the code in functions:
switch (letter)
{
case 'a':
LetterA();
break;
case 'b':
LetterB();
break;
...
}
Or even better, you can use polymorphism to have C++ dispatch to the method you want based on the specific derived class:
class BaseLetter
{
...
public:
virtual void DoStuff() = 0;
};
class LetterA : public BaseLetter
{
public:
void DoStuff();
};
class LetterB : public BaseLetter
{
public:
void DoStuff();
};
void Foo(BaseLetter *letter)
{
// Use dynamic dispatch to figure out what to do
letter->DoStuff();
}
Just note, dynamic dispatch does have a (slight) performance hit, and the above is a very bad place to actually use it. The solution I, RedX, and others have posted is much better suited to your specific example.
struct FileInfo {
int NumWords;
std::string Filename;
};
std::map<char, FileInfo> TheFiles;
FileInfo & FI = TheFiles[letter];
// Work with FI.NumWords and FI.Filename
Alternatively:
std::vector<FileInfo> TheFiles;
FileInfo & FI = TheFiles[std::tolower(Letter) - 'a'];
In most practical character encodings that you're likely to encounter whilst using C or C++, 'a' to 'z' are contiguous, so you can get the array index to use simply by doing (c - 'a'), where c is the char you're looking at.
Chars are basically numbers. 'a' is 97, 'b' is 98 and so on.
The easiest way is to simply replace every numOfWordsInFile[n] with numOfWordsInFile[current_char - 'a'] and the whole code repeated for each case may reside in a function, like this:
int AddWord(char current_char) {
if(numOfWordsInFile[current_char - 'a']<maxWordsPerFile){
fout.open(fileName.data(),ios::app);
fout<<word<<" "<<endl;
numOfWordsInFile[current_char - 'a']++;
if(totalWordsInDict<maxWordsInDict){
totalWordsInDict++;
}
return(Dictionary::success);
}else{
return(Dictionary::failure);
}
}
For more general solutions read about hash maps and function pointers (when, for instance, for each char you might want to assign a different function.
if(numOfWordsInFile[letter - 'A']<maxWordsPerFile){
fout.open(fileName.data(),ios::app);
fout<<word<<" "<<endl;
numOfWordsInFile[letter - 'A']++;
if(totalWordsInDict<maxWordsInDict){
totalWordsInDict++;
}
return(Dictionary::success);
}else{
return(Dictionary::failure);
}
This will only work if you only have english letter in your use-case.
Single characters in C++ are really just numbers corresponding to their ASCII values. You can subtract letters from each other to get numerical values. So if word[0] contains the letter A, then word[0] - 'A' will be 0.
So you can index your numOfWordsInFile array directly, and you won't need a switch at all: numOfWordsInFiled[word[0] - 'A'].
Note that 'A' and 'a' have different numeric values, so you'll have to do some extra work if you're mixing upper and lower case.
If your file is A.txt, let your array index be 'A' - 'A' (= 0), if the file is B.txt, let the array index be 'B' - 'A' (= 1), etc.
It depends on how portable you want to be, or how
internationalized. If you can afford to ignore the possibility
that the first letter might be an accented character, and assume
that you're never going to have run on a mainframe, or anywhere
else that uses EBCDIC, then you can convert the first letter to
a specific case, and subtract 'a' or 'A' (depending on the case)
from it to obtain the index. The C++ standard doesn't guarantee
that the letters are contiguous however, and they aren't in
EBCDIC, nor in any of the encodings which support accented
characters. At the very least, you'll have to test that the
first character is a letter, of course.
Handling the internationalization issue is difficult, since
there is no one generally used encoding, and some of the
encodings are multibyte. For the single byte encodings, it's
fairly straight foreward to use a mapping table; a table with
256 entries, indexed by the first letter (cast to unsigned
char), which returns the index into your table. For multibyte
encodings, like UTF-8, the issue is more complicated: you can
translate the initial character in a UTF-8 sequence to an int,
but you can end up with values around a million or more, and you
don't want a table with a million entries (most of which are
completely irrelevant. One simple solution might be to add
a 27th entry for "other". (This would also catch "words" like
"2nd".)
A very portable way to do this would be:
int mappingTable[256];
std::fill_n(mappingTable, 256, 26);
static char const upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ;
static char const lower[] = "abcdefghijklmnopqrstuvwxyz;
for (int i = 0; i < 26; ++ i) {
mappingTable[upper[i]] = i;
mappingTable[lower[i]] = i;
}
Just don't forget to cast the initial character to unsigned char
before indexing.