atoi() always returning zero if false - c++

I use atoi() to convert argv to int, the problem is when argv = zero is a considered parameter in my problem, it will return zero as well.
I tried to loop about all the arguments except file name for sure, what to do ?
for (int i = 2; i < argc; i++) {
if (!atoi(argv[i]) && atoi(argv[i]) != zero) {
std::cout << "invalid" << std::endl;
return 0;
}
}
I used few cases like == zero, || instead of && and so on, same problem always .. I even used strtol but same problem as well, I dunno if it's a problem with the algorithm, but I thought about it for a long time.
edit : my arguments are like next : a1.exe add 3 2 1 4 .. I started i = 2 to begin with 3, my arguments are all numbers. the atoi returns 0 if an argument is letter or zero so I want zero to be accepted as a parameter since it's a number. Sorry if I sounded vague or something
reason for editing : people misunderstood my question.

If you want to convert a number and know wether the input string was correct, then you can use the std::strtol family of functions.
http://www.cplusplus.com/reference/cstdlib/strtol/
const char *val = "123abc";
char *end = nullptr;
int i = std::strtol(val, &end, 10);
if (end != &val[strlen(val)])
std::cout << "invalid characters in number" << std::endl;
end points to the first character not converted, so if the whole string is a valid number, it points to the end of it.

You can do the following.
SO your Problem is that you can't determine if your argv[i] contains either a numeric 0 or a letter or other sign.
for (int i = 2; i < argc; i++) {
for(int x = 0; x < strlen(argv[i])){
if(!isDigit(argv[i][x])){
std::cout << "invalid" << std::endl;
return 0;
}
}
}
In this example we get the size of the actual char array that's contained inside of argv[i] than we check every single char if it is a digit.
If it's not we write "invalid" onto the console and return 0;
ofc you probably need to make some exceptions but I think this could be a decent start and help you with your problem

Related

Why does assigning an integer to a string result in blanks?

I was trying to write Fizz Buzz and I came across an unexpected interaction. If I do std::cout << i, it automatically converts i (int) into a string and prints it? But if assign i to a string variable, it prints a blank instead? I managed to solve it by using std::to_string, but I was just wondering why printing to_print prints a blank instead of either an integer or throwing some sort of error?
#include <iostream>
#include <string>
int main() {
for (int i = 1; i <= 10; i++) {
// prints i
std::cout << i;
}
std::cout << std::endl;
for (int i = 1; i <= 10; i++) {
std::string to_print;
to_print = i;
// prints blank rather than i
std::cout << to_print;
}
}
There is no string::operator=(int), but there is string::operator=(char), which is selected as the best viable candidate.
So you're assigning single characters with codes 1..10 to the string, which apparently get printed by your terminal as blanks.
Try assigning 65, it should print A.
Your variable i gets converted to a character based on its value and the ASCII table. The first few characters are not visible.
Changing your code to start iterating at 49 which is the decimal value for the character "0":
for (int i = 49; i <= 57; i++) {
std::string to_print;
to_print = i;
std::cout << to_print;
}
It prints: 123456789
ASCII table is the most likely culprit. Your "string" contained control characters that aren't printed.
This happened because when you assigned the integer, the compiler treated it like a character. This is because char can be treated like a small integer.
Per asciitable.com, your string contained characters like linefeed, bell, horizontal tab, etc.
for (int i = 1; i <= 10; i++) {
// prints i
std::cout << i;
}
Here std::cout knows that it has to print int so no problem.
for (int i = 1; i <= 10; i++) {
std::string to_print;
to_print = i;
// prints blank rather than i
std::cout << to_print;
}
Here you put an int into a std::string so it takes your number (0, 1, 2, etc.) as a char so as ASCII.
Try to extend your for loop to 255 instead of 10, you will see other characters.
Like #rustyx said:
There is no string::operator=(int), but there is
string::operator=(char), which is selected as the best viable
candidate.
You can translate an int to std::string with to_string.
Data is stored in computer in bits. When you trying to Assign integer variable value to to a char datatype variable or String variable it will read memory contents of that variable as a bits and at printing time it will recognized as string datatype so its Look up for Ascii Value. while in case of integer printing it treat bits as a integer..

Checking if the first character of all the strings are same or not in a array of strings

I have an array of strings, I want to check whether the first characters of all the strings are the same or not.
I know how to retrieve the first character of a string, by this method
char first_letter;
first_letter = (*str)[0];
Initially, I thought to go the brute force way, by checking for the first letter for every strings, using a nested for loop.
int flag = 0
char f1,f2;
for(int i = 0;i < size_arr - 1;i++){
f1 = (*str[i])[0];
for(int j = i + 1;j < size_arr;j++){
f2 = (*str[j])[0];
if(f1 != f2)
flag += 1;
}
}
if(!(flag))
cout<<"All first characters same";
else
cout<<"Different";
But I need an approach to find whether the first letters of all the strings present in an array are the same or not. Is there any efficient way?
You needn't use a nested for loop.Rather modify your code this way
for(int i = 0;i < size_arr - 2;i++){
f1 = (*str[i])[0];
f2 = (*str[i+1])[0];
if( f1!=f2 ){
printf("not same characters at first position");
break;
flag=1;
}
}
if(flag==0)printf("same characters at first position");
I made this C approach for you (it's because you have used character arrays here, not std::string of C++ – so it's convenient to describe using C code):
#include <stdio.h>
#define MAX_LENGTH 128
int main(void) {
char string[][MAX_LENGTH] = {"This is string ONE.", "This one is TWO.",
"This is the third one."};
char first_letter = string[0][0];
int total_strs = sizeof(string) / sizeof(string[0]);
int FLAG = 1;
// Iterate through each letter of each string
for (int i = 0; i < total_strs; i++)
// First letter of the string is equal to first_letter?
if (string[i][0] != first_letter) {
FLAG = 0; // set to 0 as soon as it finds
break; // the initial_letter is NOT equal to the first
} // letter
if (FLAG)
fprintf(stdout, "The strings have the same initial letters.\n");
else
fprintf(stdout, "Not all strings have the same initial letters.\n");
return 0;
}
If you want to convert it to a C++ code, no big issue – just replace stdio.h with iostream, int FLAG = 1 with bool FLAG = true, fprintf() to std::cout statements, that's it.
In case you need to work with std::string for the same job, just simply get the array of those strings, set the flag as true by default, iterate through each string, and match in case the first string's initial letter is equivalent to others, eventually, mark the flag as false in as soon as a defected string is found.
The program will display (if same initial vs. if not):
The strings have the same initial letters.
Not all strings have the same initial letters.

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 extract numbers used in string?

I've got a std::string number = "55353" and I want to extract the numbers that I've used in this string (5 and 3). Is there a function to do that? If so, please tell me it's name, I've been searching for quite a while now and still haven't found it...
UPD:
I've solved my problem (kinda)
std::string number(std::to_string(num));
std::string mas = "---------";
int k = 0;
for (int i = 0; i < number.size(); i++) {
char check = number[i];
for (int j = 0; j < mas.size(); j++) {
if (check == mas[j])
break;
if (check != mas[j] && check != mas[j+1]) {
mas[k] = check;
k++;
break;
}
}
}
mas.resize(k); mas.shrink_to_fit();
std::string mas will contain numbers that were used in std::string number which is a number converted to std::string using std::to_string().
Try this:
std::string test_data= "55335";
char digit_to_delete = '5';
unsigned int position = test_data.find();
test_data.erase(position, 1);
cout << "The changed string: " << test_data << "\n";
The algorithm is to find the number (as a character) within the string. The position is then used to erase the digit in the string.
Your question looks like homework, so I can guess what you forgot to tell us.
mas starts with ten -. If you spot a 5, you should replace the 6th (!) dash with a '5'. That "6th" is just an artifact of English. C++ starts to count at zero, not one. The position for zero is mas[0], the first element of the array.
The one tricky bit is to understand that characters in a string aren't numbers. The proper term for them is "(decimal) digits". And to get their numerical value, you have to subtract '0' - the character zero. So '5' - '0' == 5 - the character five minus the character zero is the number 5.

How to read an char argv input and parse(check) it for non-integers

say my command line is a.out -a 3eF6
If I access argv[2], it will give me 3eF6 (which I think this is an array of chars?)
How would I loop through this to check that every single char is an integer, and not an alpha value like 'e' or 'F'?
How/Would I turn it into a string?
I know that if I do a = atoi(argv[2]), where argv[2] is 32, then a = 32.
I also know that if argv[2] is 3eF6, then the following will NOT result in "wrong input".
a = 0;
a = atoi(argv[2])
if( a = 0 )
cout << "wrong input";
Instead, a will be evaluated to 3. So it only reads the first integer in this instance, but I want to be able to access the whole argument, 3eF6.
I've tried using atoi(getline(argv[2], a), or something equivalent, but for some reason I get an error that says I cannot convert a string to const char.
Anyway, how would I convert argv[2] to a string which I could parse? Or how could I access each char in argv[2]?
I've also tried:
string string1 = argv[i+1] // argv[i] is an option like -a
but upon running the program with arguments, I get this error:
./a.out -b 2 -a 2 -s 2 -t 8
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct NULL not valid
Abort (core dumped)
TCHAR c;
int n(0);
int x(0);
int y(0);
for (x = 0; x < argc; ++x)
{
// Loop through each character in the argument.
n = _tcslen(argv[x]);
for (y = 0; y < n; ++y)
{
c = argv[x][y];
if (isdigit(c))
{
cout << c << "is a digit" << endl;
}
else
{
cout << c << "is not a digit" << endl;
}
}
}
In the end I created a char pointer that holds my char command line element:
char* charString = argv[i+1];
and passed it to a function to parse
parser(charString);
In this case, argv[i+1] is equivalent to argv[2] in my question.
The function definition of my parser function looks like this:
void parser(char* charString){
for(int i=0; charString[i] != '\0'; i++){
bool isAlpha = isalpha(charString[i]);
bool isPunct = ispunct(charString[i]);
if ((isAlpha == true)||(isPunct == true)){
printError();
exit(1);
} else;
}
}
Important to note is that to end parsing at the end of the char array, you cannot do
for(int i=0; charString[i] < sizeof(charString); i++){
as the array size will always return 8 or 9. Instead, you must end parsing when the character evaluated is equal to '\0', or in other words parse while the character charString[i] is not equal to '\0'.