I'm trying to make sure all arguments passed to main are valid integers, and if not, I'll print an error. For example, if I have an executable named total, I would enter total 1 2 3 4.
I want to print an error if there's an invalid integer, so if I enter total 1 2 3zy it will print an error message. My code is as follows.
#include <iostream>
#include<stdlib.h>
using namespace std;
bool legal_int(char *str);
int main(int argc, char *argv[])
{
//int total = 0;
for(int i = 1; i < argc; i++)
{
if( (legal_int(argv[i]) == true) )
{
cout << "Good to go" << endl;
}
else
{
cerr << "Error: illegal integer." << endl;
return 1;
}
}
// int value = atoi(argv[i]);
//cout << value << endl;
}
bool legal_int(char *str)
{
while(str != 0) // need to
if( (isdigit(str)) )// do something here
{
return true;
}
else
{
return false;
}
}
What I need to know is how can I index through all the characters in the string and make sure they are digits with the legal_int function?
When comparing every character, the logic should be if it's not legal, return false, otherwise continue:
bool legal_int(char *str)
{
while (str != 0)
{
if (!isdigit(*str))
{
return false;
}
str++;
}
return true;
}
What about:
bool legal_int(char *str) {
while (*str)
if (!isdigit(*str++))
return false;
return true;
}
It is not the best function but it should serve the purpose. The isdigit function needs a character to look at so pass in *str. The other key point is that you need to advance the pointer inside of the loop.
bool legal_int(char *str)
{
while(str != 0) // need to
if( (isdigit(str)) )// do something here
{
return true;
}
else
{
return false;
}
}
You have three mistakes:
while (str != 0) should be while (*str != 0). You want to continue until you encounter a zero in the string, not until the string itself goes away.
if( (isdigit(str)) ) should be if( (isdigit(*str++)) ). You want to look at what str points to and see if that's a digit, and you need to point to the next digit.
return true; That should not be there. You don't want to return just because you found a single digit.
Related
I want to implement a simple is_number function that checks if it's an integer, float or an unsigned long int using this method:
bool isNumber(const std::string& str)
{
size_t idx = 0;
//Check if it's an integer
std::stoi(str,&idx);
if (idx == str.size())
return true;
//Check if it's a float
std::stof(str,&idx);
if (idx == str.size() || str[str.size()-1] == 'f' && idx == str.size()) //Cause I do have some float numbers ending with 'f' in the database
return true;
//Check if it's an unsigned long int
std::stoul(str,&idx);
if (idx == str.size())
return true;
return false;
}
But if I test it with a pure string like "test" or "nan", it will throw an error because I'm trying to change a pure string to an integer.
terminate called after throwing an instance of 'std::invalid_argument'
what(): stoi
However if I test it with "0nan" for example, stoi or the others will retrieve the first number and assign the index position of the first found number to the idx variable.
Is it possible to find a workaround for pure strings like "nan" or any other?
Or is there a better method to implement this without regex or try-catch?
std::stoi throws when it fails. Instead of using C i/o you can use C++ streams, try to read from the stream and check if there is something left in the stream:
#include <string>
#include <sstream>
#include <iostream>
enum Number {Float,Signed,Unsigned,NotANumber};
template <typename T>
bool is_only_a(const std::string& str){
std::stringstream ss(str);
T x;
return (ss >> x && ss.rdbuf()->in_avail() ==0);
}
Number isNumber(const std::string& str)
{
size_t idx = 0;
if (is_only_a<unsigned long>(str)) return Unsigned;
else if (is_only_a<int>(str)) return Signed;
else if (is_only_a<float>(str)) return Float;
return NotANumber;
}
int main() {
std::cout << isNumber("1.2") << "\n";
std::cout << isNumber("12") << "\n";
std::cout << isNumber("-12") << "\n";
std::cout << isNumber("asd") << "\n";
std::cout << isNumber("nan") << "\n";
}
Order is important, because 12 could be a float as well.
The link I posted in the comments is most probably what you need.
The only slight modification needed from the answers there is adding a +/- sign, and an optional (at most one) decimal point:
bool isNumber(const std::string &s) {
bool first_char = true;
bool saw_decpt = false;
for (const auto &it: s) {
if (std::isdigit(it)) { first_char = false; }
else if (it == '+' && first_char) { first_char = false; }
else if (it == '-' && first_char) { first_char = false; }
else if (it == '.' && !saw_decpt) { first_char = false; saw_decpt = true; }
else return false;
}
return true;
}
So writing a palindrome with pointers and boolean. I have it working with a single word but then I began building it to work with a sentence. The problem is I am unsure how to keep the new modified sentence after making it lowercase and getting rid of the spaces for it to return whether it is or isn't a palindrome. It keeps returning the palindrome as false and when I went to check why I see that the program ignores the modification and kept the original string. I can't use "&" on the parameter as I tested it out. Any hints or takes on what I can do to keep the new modified string?
int main()
{
userInput();
return 0;
}
void userInput()
{
char str[90];
std::cout<<"Please enter a string to check if it is a palindrome: ";
std::cin.getline(str, 90);
modifyString(str);
}
void modifyString(char *string)
{
int count = 0;
for (int i=0; i<strlen(string); i++)
{
putchar(tolower(string[i]));
}
for (int i = 0; string[i]; i++)
{
if (string[i] != ' ')
{
string[count++] = string[i];
}
}
string[count] = '\0';
std::cout<<string<<std::endl;
results(string);
}
bool checkPalindrome(char *string)
{
char *begin;
char *end;
begin = string;
end = (string + strlen(string)-1);
while(begin != end)
{
if ((*begin) == (*end))
{
begin ++;
end--;
}
else
{
return false;
}
}
return true;
}
void results(char *string)
{
bool isItPalindrome;
isItPalindrome = checkPalindrome(string);
if( isItPalindrome == true)
{
std::cout<<"\nCongrats, the string is a palindrome!";
}
else
{
std::cout<<"\nThis string is not a palindrome.";
}
}
For starters this definition of main
int main()
{
userInput();
return 0;
}
does not make a sense. According to the function name main the function should perform the main task that is to output whether the entered sentence is a palindrome or not.
This for loop
for (int i=0; i<strlen(string); i++)
{
putchar(tolower(string[i]));
}
does nothing useful. It just outputs the string in the lower case.
This statement
end = (string + strlen(string)-1);
can invoke undefined behavior if an empty string was passed.
This while loop
while(begin != end)
{
if ((*begin) == (*end))
{
begin ++;
end--;
}
else
{
return false;
}
}
also can invoke undefined behavior for a string containing an even number ofo characters because after this if statement
if ((*begin) == (*end))
{
begin ++;
end--;
}
if the two adjacent characters are equal then begin after incrementing will be greater than end after its decrementing. And as a result the loop will continue its iteration.
In general the approach when the original string is changed is just a bad approach.
Your program has too many functions. It is enough to write one function that will determine whether the passed string is a palindrome or not.
Here is a demonstrative program.
#include <iostream>
#include <cstring>
#include <cctype>
bool checkPalindrome( const char *s )
{
const char *t = s + std::strlen( s );
do
{
while ( s != t && std::isspace( ( unsigned char )*s ) ) ++ s;
while ( s != t && std::isspace( ( unsigned char )*--t ) );
} while ( s != t &&
std::tolower( ( unsigned char )*s ) == tolower( ( unsigned char ) *t ) &&
++s != t );
return s == t;
}
int main()
{
const size_t N = 100;
char s[N] = "";
std::cout << "Please enter a string to check if it is a palindrome: ";
std::cin.getline( s, N );
std::cout << '\n';
if ( checkPalindrome( s ) )
{
std::cout << "Congrats, the string is a palindrome!\n";
}
else
{
std::cout << "This string is not a palindrome.\n";
}
return 0;
}
Its output might look like
Please enter a string to check if it is a palindrome: 1 23 456 6 54 321
Congrats, the string is a palindrome!
Okay, I solved it!
As one of the users on here brought up a point that my lowercase did not modify the string and only prints it out. I try my best to solve the problem and I think I found the solution and everything works perfectly fine. comment back to debug it if you like to see how it looks but what I did was create a for loop again for the lower case but made another pointer with it. here how it looks.
for (char *pt = string; *pt != '\0'; ++pt)
{
*pt = std::tolower(*pt);
++pt;
}
Now that definitely changes the string into a lower case and keeps it as a lower case.
so now the modified function looks like this and ready to take any sentence palindrome you give it. Example: A nUt fOr a jAr of tUNa. We make this all lowercase and take out space and boom palindrome and return true.
void modifyString(char *string)
{
int count = 0;
for (char *pt = string; *pt != '\0'; ++pt)
{
*pt = std::tolower(*pt);
++pt;
}
for (int i = 0; string[i]; i++)
{
if (string[i] != ' ')
{
string[count++] = string[i];
}
}
string[count] = '\0';
//take out the forward slash below to see how it looks after being modified
// std::cout<<std::endl<<string<<std::endl;
results(string);
}
I am trying to write a code that has two functions: one that determines whether the string is an isogram or not and another one to print the outcome (true or false) to the console (for the purpose of solving the task).
Some of the things are not working correctly though. And I wonder where I need to improve the code (probably all over...). I would appreciate any advice :)
#include <iostream>
#include<string>
#include<bits/stdc++.h>
#include<iomanip>
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end()); //sorted the string for the for loop (e.g. eHllo)
int length = str.length();
for (int i = 0; i < length; i++)
{
if (str.at(i) == str.at(i+1))
{
return false;
break;
}
else
{
return true;
}
}
}
void print_result()
{
std::string str;
if (!find_Isogram (str))
{
std::cout << "false" << std::endl;
}
else
{
std::cout << "true" << std::endl;
}
}
int main()
{
find_Isogram ("gdtub");
print_result();
return 0;
};
````````````````````````````````````````````````````
There are some problems here:
1) You always check an empty string:
print_result will just check an empty string, but it's redundant anyway.
void print_result()
{
std::string str; // empty string
if (!find_Isogram (str)) // finding isogram on empty string
{
std::cout << "false" << std::endl;
}
...
}
It can be simplified with std::boolalpha that allows you to print a bool as "true" or "false" (instead of 1 or 0). main would become
int main()
{
std::cout << std::boolalpha << find_Isogram ("gdtub"); // prints true or false
};
2) Isogram check always ends after first character
Take a look at the condition in find_Isogram. It has a return-statement in the if and else, so you always return after checking the first character.
The idea to detect duplicate characters this way is correct (except for the off-by-one-error already mentioned by others). But you want to return true; only after checking all of the characters, e.g. outside the loop:
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end()); //sorted the string for the for loop (e.g. eHllo)
int length = str.length();
for (int i = 0; i < length - 1; i++)
{
if (str.at(i) == str.at(i+1))
{
return false; // whoops duplicate char, stop here
}
}
return true; // no duplicates found, it's an isogram
}
For some further C++-magic, you could simplify it even more with standard library functions :D
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end());
return std::unique(str.begin(), str.end()) == str.end();
}
The condition where you check the consecutive characters for equality is wrong. It will yield true for strings like ABAB. You instead need to use a map with count of each character that has appeared.
Something like:
std::map<char, int> map_of_chars;
for(int i = 0; i < length; i++) {
map_of_chars[str.at(i)] = map_of_chars[str.at(i)] + 1;
}
If any value in the map is more than 1 return false;
Another implementation would be using the return value of std::unique():
std::sort(str.begin(), str.end());
auto intial_size = str.size();
std::unique(str.begin(), str.end());
if(str.size() == initial_size) {
/is an isogram
}
else {
//is not an isogram
}
I'm currently doing an assignment that requires us to create our own library for string comparison without using compare(), etc.
I got it to work, but during my research I created a bool function for character compare and return values.
It needs to work as if it returns like compare(), where 0 = strings are equal and 0 > or 0 < for not equal instead of true or false like I currently set it up to be.
I tried to change the bool functions to int but now when I run the program that was correctly returning strings are equal, it's showing not equal.
Header code:
bool compare_char(char &c1, char &c2)
{
if (c1 == c2)
return true;
else if (toupper(c1) == toupper(c2))
return true;
else
return false;
}
bool insensitive_string_comparision(string &string_one, string &string_two)
{
return ((string_one.size() == string_two.size()) &&
equal(string_one.begin(), string_one.end(), string_two.begin(), &compare_char));
}
string remove_spaces(string string)
{
string.erase(remove(string.begin(), string.end(), ' '), string.end());
return string;
}
string remove_punctuation(string string)
{
for (size_t i = 0, len = string.size(); i < len; ++i)
{
if (ispunct(string[i]))
{
string.erase(i--, 1);
len = string.size();
}
}
return string;
Int header changes
int compare_char(char &c1, char &c2)
{
if (c1 == c2)
return 0;
else if (toupper(c1) == toupper(c2))
return 0;
else if (toupper(c1) > toupper(c2))
return -1;
else if (toupper(c1) < toupper(c2))
return 1;
}
int insensitive_string_comparision(string &string_one, string &string_two)
{
return ((string_one.size() == string_two.size()) &&
equal(string_one.begin(), string_one.end(), string_two.begin(), &compare_char));
}
Int main changes
int result = insensitive_string_comparision(string_one, string_two);
if (result == 0)
cout << "Both Strings are equal." << endl;
else (result == 1 || result == -1)
cout << "Both Strings are not equal." << endl;
return 0;
I feel like I'm going to have to redesign the entire function to return the value that is similar to compare().
I'm assuming bool was the wrong decision to begin with? Where should I go moving forward to return a correct value?
In your question you are not entirely clear about how you want to compare the strings, but I made some assumptions based on your example code. You can fix your problem by writing insensitive_string_comparision like:
int insensitive_string_comparision(string &string_one, string &string_two) {
int len_one = string_one.length();
int len_two = string_two.length();
int len_comparison = 0;
if (len_one > len_two) {
len_comparison = -1;
} else if (len_one < len_two) {
len_comparison = 1;
}
int minlen = (len_comparison == -1) ? len_one : len_two;
for (int i = 0; i < minlen; i++) {
int order = compare_char(string_one[i], string_two[i]);
if (order != 0) {
return order;
}
}
return len_comparison;
}
I'd also recommend turning on warnings on your compiler. You don't need to put some of your return statements in else blocks.
So, the goal is to check to see if the C style string ends with a period or exclamation mark. However, for some reason, i keep getting false.
bool isItSentence(const char* s)
{
int x = strlen(s);
for (int c = 0; s[c] != '\0'; c++)
{
if (!isupper(s[0])) return false;
if (isupper(s[c]) && c > 0) return false;
if (s[x-1] != '.') return false;
if (s[x-1] != '!') return false;
}
return true;
}
int main()
{
std::string str = "Smelly.";
reverse(str.c_str());
std::cout << isItSentence(str.c_str()) << std::endl;
std::cout << strlen(str.c_str()) << std::endl;
system("pause");
Heres what I have so far. But when I add the last if statement to handle exclamation marks, it returns zero. Any suggestions?
First, note s[x-1] is a loop invariant, so you'd rather move it out of the for loop
if (s[x-1] != '.') return false;
if (s[x-1] != '!') return false;
this is always false (a char cannot be both a dot and an explanation mark).
the test should rather be
if (s[x-1] != '.' && s[x-1] != '!') return false;