C++ Code keeps crashing after a validation - c++

I have written a piece of code to validate a keyword, it validates and makes sure that the word is 5 letters long and it is all letters with no numbers in it. However, when I run it, the code seems to stop working at all and doesn't prompt me for the next question, I've tested it without this code and this part of the code is the problem, as it works fine without it.
The code:
cout<<name1<<", please enter the keyword (5 characters): "<<endl;
cin>>key;
for(int i = 0; i < keylength; i++){
if(isalpha(key[i]) == 1){
validnum += 1;
}
}
if(validnum == keylength && key.length() == keylength){
validated = true;
}
else{
validated = false;
}

As mentioned in the comments, there is no need for any loops to determine if the key is 5 characters and is all alphabetic.
Using std::all_of will test if all the characters are alphabetic:
#include <algorithm>
#include <string>
#include <cctype>
#include <iostream>
bool isValidData(const std::string& key)
{
return key.size() == 5 && std::all_of(key.begin(), key.end(), ::isalpha);
}
int main()
{
//Test data
std::string testKeys[] = {"1abcdef", "abcde", "abcdefghijkl", "a", "xyzab"};
for (size_t i = 0; i < std::size(testKeys); ++i)
{
// Output results
std::cout << testKeys[i] << " " << (isValidData(testKeys[i])?"OK":"BAD") << "\n";
}
}
Output:
1abcdef BAD
abcde OK
abcdefghijkl BAD
a BAD
xyzab OK
Also, if you took a look at your code, it is not clear what the goal of the code is without running the code. Compare that to the function isValidData: if you say what that function has in it, it reads almost as your description:
"The key size must be 5, and all of the characters must be alpha".

Before the for loop you need to check that key.length() is equal to keyLength. Otherwise the loop can invoke undefined behavior when the user enters a string with the length less than keyLength.
Also the function isalpha does not necessary returns 1. It can return any positive value.
Change your code something like the following
validated = key.length() == keyLength;
if ( validated )
{
size_t i = 0;
while ( i < keyLength && isalpha( ( unsigned char )key[i] ) ) ++i;
validated = i == keyLength;
}

Related

Encrypting a string but receiving an infinite loop

Problem:
I was trying to encrypt a std::string password with a single rule:
Add "0" before and after a vowel
So that bAnanASplit becomes b0A0n0a0n0A0Spl0i0t.
However, I got stuck in an infinite loop.
Here is the code:
const std::string VOWELS = "AEIOUaeiou";
std::string pass = "bAnanASplit";
//Add zeroes before and after vowels
for (int i = 0; i < pass.length(); ++i)
{
i = pass.find_first_of(VOWELS, i);
std::cout << pass << "\n";
if(i != std::string::npos)
{
std::cout << pass[i] << ": " << i << "\n";
pass.insert(pass.begin() + i++, '0');
pass.insert(pass.begin() + ++i, '0');
}
}
...And the result:
bAnanASplit
A: 1
b0A0nanASplit
a: 5
b0A0n0a0nASplit
A: 9
b0A0n0a0n0A0Split
i: 15
b0A0n0a0n0A0Spl0i0t
b0A0n0a0n0A0Spl0i0t
A: 2
b00A00n0a0n0A0Spl0i0t
a: 8
b00A00n00a00n0A0Spl0i0t
A: 14
b00A00n00a00n00A00Spl0i0t
i: 22
b00A00n00a00n00A00Spl00i00t
b00A00n00a00n00A00Spl00i00t
...
Any help? This sure seems strange.
Edit: All the answers were useful, and therefore I have accepted the one which I think best answers the question. However, the best way to solve the problem is shown in this answer.
Never, ever, modify the collection/container you are iterating upon!
Saves you a lot of trouble that way.
Let's start with your code and generate a new string with vowels surrounded by 0.
const std::string VOWELS = "AEIOUaeiou";
std::string pass = "bAnanASplit", replacement;
//Add zeroes before and after vowels
for (auto ch : pass)
{
if(VOWELS.find(ch) != std::string::npos)
replacement += '0' + ch + '0';
else
replacement += ch;
}
And there you have it!
As the OP seems to look for the exact reason for the misbehavior, I thought to add another answer as the existing answers do not show the exact issue.
The reason for the unexpected behavior is visible in following lines.
for (int i = 0; i < pass.length(); ++i)
{
i = pass.find_first_of(VOWELS, i);
...
Problem 1:
The loop counter i is an int (i.e. a signed int). But std::string::find_first_of returns std::string::npos if there's no match. This is usually the maximum number representable by an unsigned long. Assigning a huge unsigned value to a shorter signed variable will store a totally unexpected value (assuming you are not aware of that). In this case, i will becomes -1 in most platforms (try int k = std::string::npos; and print k if you need to be sure). i = -1 is valid state for the loop condition i < pass.length(), so the next iteration will be allowed.
Problem 2:
Closely related to the above problem, same variable i is used to define the start position for the find operation. But, as explained, i will not represent the index of the character as you would expect.
Solution:
Storing a malformed value can be solved by using the proper data type. In the current scenario, best options would be using std::string::size_type as this is always guaranteed to work (most probably this will be equal to size_t everywhere). To make the program work with the given logic, you will also have to use a different variable to store the find result.
However, a better solution would be using a std::stringstream for building the string. This will perform better than modifying a string by inserting characters in the middle.
e.g.
#include <iostream>
#include <sstream>
int main() {
using namespace std;
const string VOWELS = "AEIOUaeiou";
const string pass = "bAnanASplit";
stringstream ss;
for (const char pas : pass) {
if (VOWELS.find(pas) == std::string::npos) {
ss << pas;
} else {
ss << '0' << pas << '0';
}
}
cout << pass << "\n";
cout << ss.str() << endl;
}
You are not exiting the loop in case i becomes std::string::npos. So, the i value is changed to some unexpected value (likely something like -1) when it gets to the position of last i or 0 after i(here I am referring to i of split). This is because i is an signed integer but in this case find_first_of() returns std::string::npos which is largest value that can be held by a size_t. In that case the terminating condition i < pass.length() may hold true and the loop continues. So, I am recommending following changes in your code -
for (size_t i = 0; i < pass.length(); ++i)
{
i = pass.find_first_of(VOWELS, i);
if(i == std::string::npos)
break;
pass.insert(pass.begin() + i++, '0');
pass.insert(pass.begin() + ++i, '0');
}
On the same note if (i != std::String::npos) does not do what you are expecting it to do.
But then again it better not to modify the container while you are iterating over it which #Tanveer mentioned in his answer

How to convert a string of integer numbers into an array in c++?

The problem:
A function which gets degrees and factors as inputs and returns a equation as output.
The issue:
I did not know how to read an array of numbers in form of a string in c++ back then in 2016 when I was a super junior. I also did not know how to search good enough!
Update:
I answered my question and you can test this in this link: http://cpp.sh/42dwz
Answer details:
Main part of the code will be like this:
int main()
{
Poly mypoly("2 -4 3", "1 5 1");
return 0;
}
Inputs are 2 -4 3 and 1 5 1.
Output should be (2X) + (-4X5) + (3X)
Class Poly has a built-in feature to print the result
To make it easier we should convert degrees and factors from a single string into an array of strings.
This means that a string like 2 -4 3 changes into [2, -4, 3] which makes it easy to iterate over items and create equation sentences
This action is called splitting a string into an array by a delimiter which I found here for c++ https://stackoverflow.com/a/16030594/5864034
Rest of the code is just looping over the array of degrees and factors to create sentences(which is pretty easy just check the answer link http://cpp.sh/42dwz)
The code:
// Example program
#include <iostream>
#include <string>
#include <sstream>
#include <iterator>
using namespace std;
template <size_t N>
void splitString(string (&arr)[N], string str)
{
int n = 0;
istringstream iss(str);
for (auto it = istream_iterator<string>(iss); it != istream_iterator<string>() && n < N; ++it, ++n)
arr[n] = *it;
}
class Poly {
public:
string degree[10];
string factor[10];
Poly(string input_degree, string input_factor) {
splitString(degree, input_degree);
splitString(factor, input_factor);
for (int i = 0; i < 10; i++){
int this_degree = stoi(degree[i]);
int this_factor = stoi(factor[i]);
string this_sentence = "";
if(this_degree != 1 && this_degree != 0 ){
this_sentence = this_sentence + degree[i];
if(this_factor != 0){
if(this_factor != 1){
this_sentence = this_sentence + "X" + factor[i];
}else{
this_sentence = this_sentence + "X";
}
}
}
if(this_sentence != ""){
cout << "(" << this_sentence << ")";
}
if(stoi(degree[i+1]) != 0 && stoi(degree[i+1]) != 1){
cout << " + ";
}
}
}
};
int main()
{
Poly mypoly("2 -4 3", "1 5 1");
return 0;
}
The process of reading a string and extracting information from it into some sort of structure is called parsing. There are many ways to do this, and which way is appropriate depends on exactly what you want to do, how quickly it needs to run, how much memory you've got available and various other things.
You can write a simple loop which steps over each character and decides what to do based on some variables that store current state - so you might have a flag that says you're in the middle of a number, you see another digit so you add that digit to another variable which is collecting the digits of the current number. When the current number completes (perhaps you find a character which is a space), you can take what's in the accumulator variable and parse that into a number using the standard library.
Or you can make use of standard library features more fully. For your example, you'll find that std::istringstream can do what you want, out of the box, just by telling it to extract ints from it repeatedly until the end of the stream. I'd suggest searching for a good C++ input stream tutorial - anything that applies to reading from standard input using std::cin will be relevant, as like std::istringstream, cin is an input stream and so has the same interface.
Or you could use a full-blown parsing library such as boost::spirit - total overkill for your scenario, but if you ever need to do something like parsing a structured configuration file or an entire programming language, that kind of tool is very useful.
So for the community rules and to make it clear i want to answer my question.
#include <iostream>
#include <string>
#include <sstream>
#include <iterator>
using namespace std;
template <size_t N>
void splitString(string (&arr)[N], string str)
{
int n = 0;
istringstream iss(str);
for (auto it = istream_iterator<string>(iss); it != istream_iterator<string>() && n < N; ++it, ++n)
arr[n] = *it;
}
class Poly {
public:
string degree[10];
string factor[10];
Poly(string input_degree, string input_factor) {
splitString(degree, input_degree);
splitString(factor, input_factor);
for (int i = 0; i < 10; i++){
int this_degree = stoi(degree[i]);
int this_factor = stoi(factor[i]);
string this_sentence = "";
if(this_degree != 1 && this_degree != 0 ){
this_sentence = this_sentence + degree[i];
if(this_factor != 0){
if(this_factor != 1){
this_sentence = this_sentence + "X" + factor[i];
}else{
this_sentence = this_sentence + "X";
}
}
}
if(this_sentence != ""){
cout << "(" << this_sentence << ")";
}
if(stoi(degree[i+1]) != 0 && stoi(degree[i+1]) != 1){
cout << " + ";
}
}
}
};
int main()
{
Poly mypoly("2 1 -4", "1 3 5");
return 0;
}

separate sequence of same numbers from string

I'm trying to do a little task which asks to convert numbers to letters of phone keypad, for example if input is 222 it means phone button "2" ( http://upload.wikimedia.org/wikipedia/commons/7/7d/Telephone-keypad.png ) is pushed 3 times and output should be "C" and etc.
So first thing what i should do is to separate all the sequences, for example 22255-444 into 222 , 55 , - , 444 and then i think figure everything out, but now problem is that my function can't read last sequence
#include <iostream>
#include <fstream>
using namespace std;
//-------------------------------------------------------------------------
void encode(string text, string &result, int &i)
{
char keyboard[10][4] = {
{' ',' ',' ',' '},
{'.','?','!','.'},
{'a','b','c','a'},
{'d','e','f','d'},
{'g','h','i','g'},
{'j','k','l','j'},
{'m','n','o','m'},
{'p','r','q','s'},
{'t','u','v','t'},
{'w','x','y','z'}
};
int j;
for(j = i; j<text.size();j++)
{
if(text[i] != text[j] || j == text.size())
{
result = text.substr(i, j-i);
i = j-1;
break;
}
}
cout << result << endl;
}
int main()
{
ifstream fd("sms.in");
string text;
string result;
getline(fd, text);
for(int i = 0; i<text.size();i++)
{
encode(text, result, i);
}
return 0;
}
as a test now im using this input : 5552-22-27777 , output should be 555 2 - 22 - 2 7777, but for me its 555 2 - 22 - 2 2 2 2 2.
In this if statement:
if(text[i] != text[j] || j == text.size())
The second condition (j == text.size()) will never be true because the loop will terminate before that. So when you reach the end of the string, the values of result and i will not be updated correctly.
What you can do is remove the termination condition from the loop (it's not necessary to have one because you will break out of the loop anyway). And you will need to reverse the order of the conditions in the if so that you don't read past the end of the string:
for(j = i; ;j++)
{
if (j == text.size() || text[i] != text[j])
...
I'd pull that last bit out of the for loop, it doesn't really belong in there because it's a special case. I've also eliminated some other things that seemed unnecessary and fixed the inside of the loop up. See if this all makes sense to you.
I pulled the keymap declaration out because it was not used in your example, and we value what are known as "minimal working examples" here as a way to isolate and discuss problems cogently.
Note that I've tried to move all the encoding work into a single function and out of the main() function. This frees up main to handle high-level parts of the program. On the lines I've marked "Decode here" you could call to yet another function that translates the string of numbers into a character, if that's what you're going for.
I've marked the special case and explicitly moved it out of the for-loop so that everything within the for-loop can be handled the same. This is better than trying to make the for-loop do everything.
I didn't agree with the logic that i=j-1, so I changed that (I did test this).
I've also switched to read input directly from the command line so that it's quicker to test.
I added the #include <string> directive at the beginning so that the program would compile.
Putting all the encoding work inside a single function simplified that functions declaration to a single argument.
I switched the brackets to conform to my own understanding of the One True Style.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void encode(string text) {
int j=0,i=0; //Declare j here so we can use in special case
for(j=0; j<text.size(); j++){
if(text[j] != text[i]){
cout << text.substr(i, j-i) << endl; //Decode here
i = j;
}
}
cout << text.substr(i,j-1) << endl; //Decode here. Special case
}
int main(){
string text;
getline(cin, text);
encode(text, result);
return 0;
}

How do I increment letters in c++?

I'm creating a Caesar Cipher in c++ and i can't figure out how to increment a letter.
I need to increment the letter by 1 each time and return the next letter in the alphabet. Something like the following to add 1 to 'a' and return 'b'.
char letter[] = "a";
cout << letter[0] +1;
This snippet should get you started. letter is a char and not an array of chars nor a string.
The static_cast ensures the result of 'a' + 1 is treated as a char.
> cat caesar.cpp
#include <iostream>
int main()
{
char letter = 'a';
std::cout << static_cast<char>(letter + 1) << std::endl;
}
> g++ caesar.cpp -o caesar
> ./caesar
b
Watch out when you get to 'z' (or 'Z'!) and good luck!
It works as-is, but because the addition promotes the expression to int you want to cast it back to char again so that your IOStream renders it as a character rather than a number:
int main() {
char letter[] = "a";
cout << static_cast<char>(letter[0] + 1);
}
Output: b
Also add wrap-around logic (so that when letter[0] is z, you set to a rather than incrementing), and consider case.
You can use 'a'+((letter - 'a'+n)%26);
assuming after 'z' you need 'a' i.e. 'z'+1='a'
#include <iostream>
using namespace std;
int main()
{
char letter='z';
cout<<(char)('a' + ((letter - 'a' + 1) % 26));
return 0;
}
See this https://stackoverflow.com/a/6171969/8511215
Does letter++ work?
All in all char is a numeric type, so it will increment the ascii code.
But I believe it must be defined as char letter not an array. But beware of adding one to 'Z'. You will get '[' =P
#include <iostream>
int main () {
char a = 'a';
a++;
std::cout << a;
}
This seems to work well ;)
char letter = 'a';
cout << ++letter;
waleed#waleed-P17SM-A:~$ nano Good_morning_encryption.cpp
waleed#waleed-P17SM-A:~$ g++ Good_morning_encryption.cpp -o Good_morning_encryption.out
waleed#waleed-P17SM-A:~$ ./Good_morning_encryption.out
Enter your text:waleed
Encrypted text:
jnyrrq
waleed#waleed-P17SM-A:~$ cat Good_morning_encryption.cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
//the string that holds the user input
string text;
//x for the first counter than makes it keeps looping until it encrypts the user input
//len holds the value (int) of the length of the user input ( including spaces)
int x, len;
//simple console output
cout << "Enter your text:";
//gets the user input ( including spaces and saves it to the variable text
getline(cin, text);
//give the variable len the value of the user input length
len = (int)text.length();
//counter that makes it keep looping until it "encrypts" all of the user input (that's why it keeps looping while its less than len
for(x = 0; x < len; x++) {
//checks each letts (and spaces) in the user input (x is the number of the offset keep in mind that it starts from 0 and for example text[x] if the user input was waleed would be w since its text[0]
if (isalpha(text[x])) {
//converts each letter to small letter ( even though it can be done another way by making the check like this if (text[x] =='z' || text[x] == 'Z')
text[x] = tolower(text[x]);
//another counter that loops 13 times
for (int counter = 0; counter < 13; counter++) {
//it checks if the letts text[x] is z and if it is it will make it a
if (text[x] == 'z') {
text[x] = 'a';
}
//if its not z it will keeps increamenting (using the loop 13 times)
else {
text[x]++;
}
}
}
}
//prints out the final value of text
cout << "Encrypted text:\n" << text << endl;
//return 0 (because the the main function is an int so it must return an integer value
return 0;
}
Note: this is called caeser cipher encryption it works like this :
ABCDEFGHIJKLMNOPQRSTUVWXYZ
NOPQRSTUVWXYZABCDEFGHIJKLM
so for example my name is waleed
it will be written as : JNYRRQ
so its simply add 13 letters to each letter
i hope that helped you
It works but don't forget that if you increment 'z' you need to get 'a' so maybe you should pass by a check function that output 'a' when you get 'z'.
cast letter[n] to byte* and increase its referenced value by 1.

bool function problem - always returns true?

#include <iostream>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
using namespace std;
static bool isanagram(string a, string b);
int main(void)
{
int i,n,j,s;
cin >> n;
string a, b;
cin >> a >> b;
if(!isanagram(a,b)) cout << "False" << endl;
else cout << "True" << endl;
return 0;
}
static bool isanagram(string a, string b)
{
int i, j, size, s=0;
size = a.size();
bool k;
for(i=0;i<size;i++)
{
k=false;
for(j=0;j<size;j++)
{
if(a[i] == b[j]) { k = true; break; }
}
if(k==true) s+=1;
}
cout << a[2] << b[2] << endl;
if(s == size) return true;
else return false;
}
I don't know where exactly is the problem so i just pasted the whole code.
It should be a simple program capable for finding if two strings are anagrams, but it's not working and i don't know why. I used pointers in the program so thought the might be the problem and removed them, i removed other things additionally but still it's not working. If you can give it a look-see and tell me some idea where i might've gone wrong with my code ?
Thank you in advance.
The logic for your isanagram function is fatally flawed - it will never work correctly, even if you manage to fix the bugs in it.
You need to make sure that you have a correct algorithm before you start coding. One simple algorithm might be:
sort a
sort b
isanagram = (a == b)
It's not always return true:
Here's my input:
0
sdf
fda
Here's output I got:
fa
False
Regarding your task: if performance is not an issue for you task, just sort 2 strings (using std::sort) and compare results.
Regarding your style:
use string::length() instead of size() -- it's more idiomatic
instead of if(s == size) return true; else return false; consider return s == size
pass your strings by const reference, not by value
consider declaring variables as close to point of their usage as possible (but not closely) and initialize them when declaring (i, j, k, size all fit this hint)
Your approach is fine but it has a small flaw. You ensuring that every char from string a is present in string. So if a = "aab" and b = "abc", your approach will flag them as anagram. You also need to take the count of char in account.
The definition of anagram is:
An anagram is a type of word play, the result of rearranging the letters of a word or phrase to produce a new word or phrase, using all the original letters exactly once;
Easiest way as many have suggested is to ensure that the strings are of the same length . If they are, sort the two string and check for equality.
If you want to patch your approach, you can make the char in string b NULL after it has been matched with a char in string a.
Something like:
if(a[i] == b[j]) { b[j] = 0; k = true; break; }
in place of your:
if(a[i] == b[j]) { k = true; break; }
This way once a char of b has been matched it cannot participate again.
There are essentially two ways of checking for anagrams:
Sort both strings and see if they match. If they are anagrams, they will both have the same letters and a sort would order them into the same sequence.
Count the frequency of each char in each string. If they are anagrams, the frequency counts for each char will be the same for both strings.
First things first: don't declare the method static. It's a confusing keyword at the best of times given all the roles it can fulfill... so reserve for times when you really have to (method or attribute of a class that is not tied to any instance for example).
Regarding the algorithm: you're nearly there, but presence only is not sufficient, you need to take the number of characters in account too.
Let's do it simply:
bool anagram(std::string const& lhs, std::string const& rhs)
{
if (lhs.size() != rhs.size()) return false; // does not cost much...
std::vector<int> count(256, 0); // count of characters
for (size_t i = 0, max = lhs.size(); i != max; ++i)
{
++count[lhs[i]];
--count[rhs[i]];
}
for (size_t i = 0, max = count.size(); i != max; ++i)
if (count[i] != 0) return false;
return true;
} // anagram
Let's see it at work: anagram("abc","cab")
Initialization: count = [0, 0, ...., 0]
First loop i == 0 > ['a': 1, 'c': -1]
First loop i == 1 > ['a': 0, 'b': 1, 'c': -1]
First loop i == 2 > ['a': 0, 'b': 0, 'c': 0 ]
And the second loop will pass without any problem.
Variants include maintaining 2 counts arrays (one for each strings) and then comparing them. It's slightly less efficient... does not really matter though.
int main(int argc, char* argv[])
{
if (argc != 3) std::cout << "Usage: Program Word1 Word2" << std::endl;
else std::cout << argv[1] << " and " << argv[2] << " are "
<< (anagram(argv[1], argv[2]) ? "" : "not ")
<< "anagrams" << std::endl;
}
I see some problems with your code. Basically the algorithm is wrong. It will match characters within a.size(). It takes no account for duplicates (in either a or b).
Essentially, you should sort the strings and then compare for equality.
If you can't sort, at least remove the b characters from the comparison, eliminate the k variable.