In this code the value needed in the code is given by the user via command line. But I need the code to reject any numerical value <0 and every alphanumeric code or string (-23 is not accepted, h42b is not accepted,hello is not accepted, 10 is accepted)
int main(int argc, char* argv[])
{
int S = argc > 1 ? std::atoi(argv[1]) : 100;
if (S < 0) {
S = 100;
std::cout << "S value must be >0, value set to 100" << '\n';
}
If the user puts any value that's not a number>0 I want the code to print "S value must be >0, value set to 100".
I tried using a for loop, but I don't know how to reject alphanumerical codes or strings.
Can you tell me what can I use? It shouldn't be an advanced tool, just something that gets the job done nicely
I need the code to reject any numerical value <0 and every alphanumeric code or string
means you cannot assume numerical input, which means you cannot use atoi().
If the user puts any value that's not a number
... then you need to detect that. You can only detect if you can access the input.
Which means you need to read it in as input without assumptions on syntax or formatting. I.e. you need to store in a string.
We are however not looking at normal input, you are working on commandline. Which means you need to parse enough to decide when to give up. As far as I understand, that is when even the first parameter is not a number. For that a loop is not needed - if the program fails there is nothing which you can process in additional loop iterations (assuming that you do not want to ignore the first, non-numerical, parameter and process the second, i.e. whatever is after the first blank).
So all in all
verfiy that there is at least one paratemer (your code already does this)
get the first parameter
as a string, not as a number
try whether it is a number, with something NOT expecting it to be a number; i.e. not atoi()
if you select sscanf() make sure to interpret the return value (not only the scanned value)
if you detect a number use it
if you do not detect a number output the useage message
You can convert char array to std::string for convenience and then iterate over it, using std::isdigit to check whether it is a digit in range (0-9). If not, assign 100 to S, print error message and break the loop.
Quick solution looks might look like this:
#include <cctype>
#include <iostream>
#include <string>
int main(int argc, char *argv[]) {
int S{0};
bool correct_input{true};
std::string argument(argv[1]);
for (auto character : argument) {
if (!std::isdigit(character)) {
S = 100;
std::cout << "S value must be >0, value set to 100" << '\n';
correct_input = false;
break;
}
}
if (correct_input) {
S = std::stoi(argument);
}
}
If it is not too advanced you can use a regex to get the job done:
#include <iostream>
#include <regex>
#include <sstream>
int main(int argc, char* argv[]) {
std::regex regex("^(\\+)?([1-9][0-9]*)$");
for (int i = 0; i < argc; i++) {
std::string argument(argv[i]);
std::uint32_t value = 100;
// has argument the desired pattern, i.e. is it a positive number above 0?
if (std::regex_match(argument, regex)) {
std::stringstream strValue;
strValue << argument;
strValue >> value;
std::cout << "value: " << value << "\n";
} else
std::cout << "Input should be a number > 0 (value setted to 100)! provided: " << argument << "\n";
}
return 0;
}
Input:
1 +2 100 0 -1 h23b h3ll0 test
Output:
value: 1
value: 2
value: 100
Input should be a number > 0 (value setted to 100)! provided: 0
Input should be a number > 0 (value setted to 100)! provided: -1
Input should be a number > 0 (value setted to 100)! provided: h23b
Input should be a number > 0 (value setted to 100)! provided: h3ll0
Input should be a number > 0 (value setted to 100)! provided: test
Using regex has the benefit that this approach is highly customizable and you will only encounter numbers in your for-loop that are positive. You don't have to check if the current argument is a number or is above 0. The regex takes care of that. All you have to do is to check if the current argument matches with the regex. However, I don't know how "advanced" this feature is for someone starting with c++ or someone starting with programming. To convert your string you can use any method. I used a stringsteam. Simply write your value into the stream and then read it back into your desired variable. Hope it helped!
If you want to take a closer look at the regex: https://regexr.com/61bjl
I will try to implement this in the different ways as suggested. In the meantime I wrote this:
bool string_is_numeric(char* string) {
size_t length = strlen(string);
for(size_t i = 0; i < length; i++) {
if(!isdigit(string[i]) && static_cast<int> (string[i]) != 46 ) {
return false; }
}
return true;
}
int main(int argc, char* argv[])
{
int S = argc > 1 ? std::atoi(argv[1]) : 99;
if (argc > 1 && (S < 0 || !string_is_numeric (argv[1]))) {
S = 99;
std::cout << "S value not valid. Only numerical values > 0
are
allowed. Value set to 99" << '\n';
}
}
This code as far as I tried works. And let the user write the '.' for decimal numbers.
Related
I'm trying to use something like strcmp to compare a command like "Hello 4" and keep the 4 as a variable
Something like this:
if(strcmp(c, "Hello %d") == 0){
int num = %d;
}
You're looking for sscanf, which uses the scanf-style percent encoders you're using and takes a string to parse as its argument (as well as pointers to store the successful parses into).
It returns the number of arguments successfully stored, or a negative number in the case of an EOF error. In your case, we'll consider it a successful parse if we successfully store the one argument. If we get a zero, that's a failed parse, and if we get a negative number, that's a premature EOF, so we want the result of sscanf to be greater than zero.
#include <cstdio>
#include <iostream>
int main() {
const char* c = "Hello 100";
int num;
if (std::sscanf(c, "Hello %d", &num) > 0) {
std::cout << "Success! " << num << std::endl;
} else {
std::cout << "Failure..." << std::endl;
}
}
Note that in the else branch, the num variable won't be assigned, so it will have whatever value your code previously assigned to it (which, in the code sample I've shown here, is nothing at all, hence UB). So be careful not to reference that variable in the failure branch.
Regular expressions are a way to solve this if you're using C++ and not simply compiling C with a C++ compiler.
#include <iostream>
#include <string>
#include <regex>
int main() {
std::string foo = "hello 4";
std::smatch matches;
if (std::regex_match(foo, matches, std::regex("hello (\\d+)"))) {
std::cout << matches[1] << std::endl;
}
return 0;
}
Using regular expressions makes it trivial to account for varying formatting of the string. E.g. What if there are spaces before or after the items we're looking for?
std::regex("\\s*hello\\s+(\\d+)\\s*")
Or maybe we want to do that but also make it case-insensitive.
std::regex("\\s*hello\\s+(\\d+)\\s*",
std::regex_constants::icase)
I am trying to write a code that will accept an integer input and then calculate the smallest number possible using digits not found in the inputted integer. The possible digits would be 0-9, however, 0 can not be the leading value in the output.
For example, if the user enters:
6789
the the program would output:
102345
How can I solve this?
The lowest number possible from any set of digits (ignoring, for now, the issue of the zero) comprises those digits in order; thus, from the digits 2, 1, 6 and 3, the lowest number is 1236.
So, we can start of with a list of all digits, in order, then run through the digits in the given input number (after we have converted that to a string), removing each of those digits from our list (if it's still in it). If we end up with a list whose first element is zero, we simply swap that with the second digit.
Here's a possible implementation:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string numbs = "0123456789";
int input;
std::cout << "Enter a number: ";
std::cin >> input;
std::string check = std::to_string(input); // Convert our input to a string
for (auto digit : check) { // Remove each digit in that from our list...
size_t p;
if ((p = numbs.find(digit)) != std::string::npos) numbs.erase(p, 1);
}
// A basic error check that at least one digit remains ...
if (numbs.length() == 0) {
std::cout << "No digit left with which to make a number!\n";
return 1;
}
// Swap first two digits if first is zero and there is at least one other ...
if (numbs[0] == '0' && numbs.length() > 1) std::swap(numbs[0], numbs[1]);
int answer = std::stoi(numbs);
std::cout << answer << std::endl;
return 0;
}
In this example, I have used the std::string container class from the Standard Library; in many ways, that acts like an array of characters; however, if you want to use actual arrays, you could readily adapt the shown code to use them.
Yet another implementation. Same algorithm as from Adrian . . .
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
// Basic string
std::string allDigits{ "0123456789" };
// Get input. Digits only
if (std::string input{}; std::getline(std::cin, input) and std::all_of(input.begin(), input.end(), std::isdigit)) {
// Erase from the allDigits string the characters that are in the input string
std::erase_if(allDigits, [&](const char d) { return std::any_of(input.begin(), input.end(), [d](const char c) { return c == d; }); });
// Take care of leading 0
if ((allDigits.length() > 1) and allDigits.front() == '0') std::swap(allDigits[0], allDigits[1]);
// Show result
std::cout << allDigits << '\n';
}
else std::cerr << "\n*** Error: Invalid input\n\n";
}
I am writing a simple program that compares a single character from argv[] to a character in a char array. This is done using a for loop to check if argv[1] is any of the characters in the character array, which is to serve as an input error check.
What I have done to implement this is below:
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
const char validCharacters[] = "abcde01234";
int goodChars = 0;
for (int i = 0; i < sizeof(validCharacters) - 1; i++) {
if (strcmp(argv[1], &validCharacters[i]) == 0) {
cout << "Characters match!" << endl;
goodChars++;
}
}
if (goodChars > 0) {
cout << "Input OK!";
}
else {
cout << "Invalid input!";
}
return 0;
}
I inputted '0' as the value for argv[].
When I was debugging, this, I found that strcmp(argv[1], &validCharacters[i]) returns -1, and that sizeof(argv[1]) returns 4.
Why is it that argv[1] has the size of 4 despite only having '0' entered into it?
I'm certain that this is the reason why my program isn't working and would like to know if there is a way to resolve this problem.
Also, I'm not very experienced in C++, so anything you thing is bad practice, please let me know.
argv is an array of char pointers. In order to compare and get the size of the actual value, you'll have to dereference the char object.
For example, to get the size:
if(*argv[1] == '0'){
// Do Something
}
Checks if the first argument(argv[0] is the command itself), is equal to the character '0'. Here I dereference the char at index 1 of the argv array.
How to perform range checking using regular expressions?
Take a 4-bit number (i.e. "dddd") as an example, how can I check whether it is within given range, say [1256-4350] or not?
To check whether the input is a 4 digit number use regex_match, and then convert the string to an integer using std::stoi to check the range.
std::regex expr(R"(\d{4})");
if(std::regex_match(input, expr)) {
int num = std::stoi(input);
if(num >= 1256 && num <= 4350) {
// input is within range
}
}
As Jarod42 mentions in the comments, since you've already validated the input is a 4 digit number, it's not necessary to convert it to an integer. Assuming input is an std::string, this would work too
if(input >= "1256" && input <= "4350") {
// input is within range
}
Using this website, the regex you are after should look like this: ^(125[6-9]|12[6-9][0-9]|1[3-9][0-9]{2}|[23][0-9]{3}|4[0-2][0-9]{2}|43[0-4][0-9]|4350)$.
That being said, I think it is far more readable and maintainable do break it into two steps, first validate the data type and then the range. (What happens when the range shifts? Your entire regex will most likely be made useless).
Here is a great site that will give you the answer.
For your example:
(\b(125[6-9]|12[6-9][0-9]|1[3-9][0-9]{2}|[23][0-9]{3}|4[0-2][0-9]{2}|43[0-4][0-9]|4350)\b
Yeah, I know this will work. I just want to check if we can verify it's indeed a number and at the same time check its range using
Okay... But don't use regex for this task. It's a terrible choice.
#include <iostream>
#include <sstream>
using namespace std;
bool is_number_in_range(string s) {
istringstream str(s);
int i; char c;
str >> i;
if( str.fail() ) return false;
return i>=1256 && i<=4350 && str.eof();
}
int main() {
cout<< is_number_in_range("0") << '\n'<<
is_number_in_range("1234") << '\n'<<
is_number_in_range("1256") << '\n'<<
is_number_in_range("2000") << '\n'<<
is_number_in_range("4350") << '\n'<<
is_number_in_range("5000") << '\n'<<
is_number_in_range("abcd") << '\n'<<
is_number_in_range("1234.0") << '\n';
return 0;
}
see it live
I've been trying to create a program in C++ that tries to accomplish this pseudocode:
get argv[1] into int
get int’s digits into array[int length]
for int i = array length; i >= 0;
gen random number into check
if check == array[i]
i
say Number i was check
end if
And I think the part I'm really struggling with is the
get argv[1] into int
get int’s digits into array[int length]
part. In my full code there isn't even an attempt because nothing I've tried works. The error I get the most is that the code compiles, but everytime it tries to cout << "Number 1:" << number I just get Number 1: 0 no matter the actual number I enter. And when 0 == 0 the code doesn't even notice.
My broken propably convention-breaking code follows:
#include <iostream>
#include <string>
int main (int argc, char **argv) {
if (argc == 1 || argc == 3) {
std::cout << "Argument count does not match (one argument expected)\n";
return(-1);
}
std::cout << "Input: " << argv[1] << "\n";
const char* text = argv[1];
int number = atoi(text);
int check = rand() % 10;
std::cout << "Check 1: " << check << "\nNumber 1: " << number << "\n";
if (check == array[i]) {
i++;
std::cout << "Success! Number " << i << " was " << check << ".\n";
}
}
}
TL;DR: My "sort of" number cracker doesn't want to put argv1 into an int with the int's digits being later put into an array.
Feel free to make me feel stupid. Hope the question isn't too specific. I'll expand on details as asked.
EDIT: This is an earlier attempt at conversion:
int array[];
for (int i = strlen(text); i >= 0; i--) {
array[i] = number % 10;
number /= 10;
}
EDIT2: So many responses, no solutions. Thank you for trying to explain this newbie so many things at once. BTW: Git
The earlier attempt is almost good: it's just that you have to actually allocate space for the array, like this:
int array[strlen(text)];
if your compiler supports variable-length arrays as an extension, and
std::vector<int> array;
array.resize(strlen(text));
if you want to stick with standard C++ and follow some good practices.
However, if you want to be tricky, you don't even need to convert the argument to a number:
if (argv[1][i] == check % 10 + '0')
does the trick too. All in all, the complete program would look like this:
#include <iostream>
#include <cstdlib>
int main(int argc, char *argv[])
{
int check = std::rand();
std::cout << check << std::endl;
char *p = argv[1] + strlen(argv[1]);
while (p - argv[1] >= 0) {
if (*--p == '0' + check % 10)
std::cout << "guessed " << p - argv[1] << "th digit" << std::endl;
check /= 10;
}
return 0;
}
Your code is relatively close to being right. You are struggling with the declaration of the array (you must specify the size for it). 32-bit int cannot have more than ten digits, so declaring
int array[10];
should be sufficient.
Before converting the number to an array of digits, check if it is negative, and flip its sign if it is negative:
if (number < 0) {
number = -number;
}
Otherwise, your number%10 trick is not going to work.
When you do the conversion, count how many digits you have. Put the result in actualCount variable: chances are that you are not going to use up all the digits in your array, so
int check = rand() % 10; // 10 is the max, not the actual digit count
should be
int check = rand() % actualCount;
Your argument checking also needs improvement: think what would happen if the user passes five parameters? If you expect exactly one argument, you should write
if (argc != 2) {
std::cout << "Argument count does not match (one argument expected)\n";
return(-1);
}
In order to extract only one digit at a time from a number you have a couple of choices.
For convenience you can use a std::string, inserting the original string (argv[1]) in it, then extracting one char at a time:
#include <string>
...
// put the input in a string
std::string text = argv[1];
for (unsigned i = 0; i < text.size(); i++)
{
// extract only one char, a digit
char ch = text.at(i);
// convert that char in a number
int n = ::atoi(& ch);
// use n
...
}
If you don't want to use std::string, you can always use a c-like array (argv[1] itself):
#include <cstring>
...
for (unsigned i = 0; i < strlen(argv[1]); i++)
{
// extract only one char, a digit
char digit = argv[1][i];
// convert that char in a number
int num = ::atoi(& digit);
// use n
...
}