How to parse integer command line arguments in C? - c

I would like a user to pass either two parameters or leave it blank. For instance:
./program 50 50
or
./program
When I tried to use int main(int argc, char *argv[]), first thing I have done was to change char *argv[] to int *argv[] but it did not work. What I want is from the user is just to enter two integers between 0 and 100. So if it is not two integers then it should give an error.
I was sort of thinking to give out an error with types (as I used to program on C#) but whatever I enter, argv[1] would be 'char' type all the time.
So what I have done is
for (int i = 0; i <= 100; i++) {
//printf("%d", i);
if (argv[1] == i) {
argcheck++;
printf("1st one %d\n", i);
}
else if (argv[2] == i) {
argcheck++;
printf("2nd one %d\n", i);
}
This does not work as well. Also it gives warning when compiling, but if I change argv with atoi(argv[1]) for instance, then it gives a Segmentation fault (core dumped) error.
I need a simple way to solve this problem.
EDIT:
So I fixed with atoi(), the reason why it was giving segmentation fault was because I was trying it with null value when I have no parameter. So I fixed it up by adding an extra cond. But now the problem is if the value is let's say
./program asd asd
Then the output of atoi(argv[1]) would be 0. Is there a way to change this value?

Don't use atoi() and don't use strtol(). atoi() has no error checking (as you found out!) and strtol() has to be error-checked using the global errno variable, which means you have to set errno to 0, then call strtol(), then check errno again for errors. A better way is to use sscanf(), which also lets you parse any primitive type from a string, not just an integer, and it lets you read fancy formats (like hex).
For example, to parse integer "1435" from a string:
if (sscanf (argv[1], "%i", &intvar) != 1) {
fprintf(stderr, "error - not an integer");
}
To parse a single character 'Z' from a string
if (sscanf (argv[1], "%c", &charvar)!=1) {
fprintf(stderr, "error - not a char");
}
To parse a float "3.1459" from a string
if (sscanf (argv[1], "%f", &floatvar)!=1) {
fprintf(stderr, "error - not a float");
}
To parse a large unsigned hexadecimal integer "0x332561" from a string
if (sscanf (argv[1], "%xu", &uintvar)!=1) {
fprintf(stderr, "error - not a hex integer");
}
If you need more error-handling than that, use a regex library.

This will do:
int main(int argc, char*argv[])
{
long a,b;
if (argc > 2)
{
a = strtol(argv[1], NULL, 0);
b = strtol(argv[2], NULL, 0);
printf("%ld %ld", a,b);
}
return 0;
}

The arguments are always passed as strings, you can't change the prototype of main(). The operating system and surrounding machinery always pass strings, and are not able to figure out that you've changed it.
You need to use e.g. strtol() to convert the strings to integers.

You want to check whether
0 or 2 argument is received
two values received are between 0 and 100
received argument is not a string. If string comes sscanf will return
0.
Below logic will helps you
int main(int argc, char *argv[])
{
int no1 = 0, no2 = 0, ret = 0;
if ((argc != 0) && (argc != 2))
{
return 0;
}
if (2 == argc)
{
ret = sscanf(argv[1], "%d", &no1);
if (ret != 1)return 0;
ret = sscanf(argv[2], "%d", &no2);
if (ret != 1)return 0;
if ((no1 < 0) || (no1 >100)) return 0;
if ((no2 < 0) || (no2 >100)) return 0;
}
//now do your stuff
}

The things you have done so innocently are blunder in C. No matter what, you have to take strings or chars as your arguments and then later you can do whatever you like with them. Either change them to integer using strtol or let them be the strings and check each char of the string in the range of 48 to 57 as these are the decimal values of char 0 to 9. Personally, this is not a good idea and not so good coding practice. Better convert them and check for the integer range you want.

You can still use atoi, just check whether the argument is a number first ;)
btw ppl will tell you goto is evil, but they're usually brainwashed by non-sensible "goto is bad", "goto is evil", "goto is the devil" statements that were just tossed out without elaboration on the internet.
Yes, spaggethi code is less managable. And goto in that context is from an age where it replaced functions...
int r, n, I;
for (I = 0; I < argc; ++I)
{
n = 0;
do
if ( !((argv + I) [n] >= '0' && (argv + I) [n] <= '9') )
{
err:
fprintf(stderr,"ONLY INTEGERS 0-100 ALLOWED AS ARGUMENTS!\n");
return 1;
}
while ((argv + I) [++n] != '\0')
r = atoi(argv[I]);
if (r > 100)
goto err;
}

You can not change the arguments of main() function. So you should just use atoi() function to convert arguments from string to integer.
atoi() has its drawbacks. Same is true for strtol() or strtoul() functions. These functions will return a 0 value if the input to the function is non-numeric i.e user enters asdf or anything other than a valid number. To overcome this you will need to parse the string before passing it to atoi() and call isdigit() on each character to make sure that the user has input a valid number. After that you can use atoi() to convert to integer.

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
main(int argc,char *args[])
{
int i,sum=0;
for(i=0;i<=argc;i++)
{
printf("\n The %d argument is: %s",i,args[i]);
}
printf("\nTHe sum of given argumnets are:");
for(i=1;i<argc;i++)
{
int n;
n=atoi(args[i]);
printf("\nN=%d",n);
sum += n;
}
printf("\nThe sum of given numbers are %d",sum);
return(0);
}
check this program i added another library stdlib.h and so i can convert the character array to string using function atoi.

Related

How to check if scanf("%s", &var) is a number, and thus turn it into an integer

I have this code and I need help converting the comments to c code
// if the input of scanf() is "q"
{
break;
}
else
{
// convert to int
}
Firstly, how do I check if an input is a certain character. Secondly, how do I turn a string into an integer. Example: "123" -> 123
Things I've tried, that didn't work: (it is possible that I implemented these solutions incorrectly)
how does scanf() check if the input is an integer or character?
Convert char to int in C and C++
I am not using any standard libraries except for stdio.h to print some logging information on the window
you have to know also that any string is terminated by null character which is '\0' to indicate the termination of the string , also you have to check is the user entered characters not numbers and so on (that's not implemented in this code).
I also handled if negative numbers are entered.
but you have to handle if the user entered decimals numbers , to sum up . there are so many cases to handle.
and here the edited code :
#include <stdio.h>
int main(){
char inputString[100];
printf("enter the input:\n");
scanf("%s", &inputString);
if(inputString[0] == 'q' && inputString[1] == '\0' )
{
printf("quiting\n");
//break;
}
else {
int i = 0;
int isNegative = 0;
int number = 0;
// check if the number is negative
if (inputString[0] == '-') {
isNegative = 1;
i = 1;
}
// convert to int
for ( ;inputString[i] != '\0' ; i++) {
number *= 10;
number += (inputString[i] - '0');
}
if(isNegative == 1)
number *= -1;
printf("you entered %d\n", number);
}
return 0;
}
The fundamental question here is, Do you want to use scanf?
scanf is everyone's favorite library function for easily reading in values. scanf has an input specifier, %d, for reading in integers.
And it has a different input specifier, %s, for reading in arbitrary strings.
But scanf does not have any single input specifier that means, "Read in an integer as an integer if the user types a valid integer, but if the user types something like "q", have a way so I can get my hands on that string instead."
Unless you want to move mountains and implement your own general-purpose input library from scratch, I think you have basically three options:
Use scanf with %d to read integers as integers, but check scanf's return value, and if scanf fails to read an integer, use that failure to terminate input.
Use scanf with %s to read the user's input as a string, so you can then explicitly test if it's a "q" or not. If not, convert it to an integer by hand. (More on this below.)
Don't use scanf at all. Use fgets to read the user's input as a whole line of text. Then see if it's a "q" or not. If not, convert it to an integer by hand.
Number 1 looks something like this:
while(some loop condition) {
printf("enter next integer, or 'q' to quit:\n");
if(scanf("%d", &i) != 1) {
/* end of input detected */
break;
}
do something with i value just read;
}
The only problem with this solution is that it won't just stop if the user types "q", as your original problem statement stipulated. It will also stop if the user types "x", or "hello", or control-D, or anything else that's not a valid integer. But that's also a good thing, in that your loop won't get confused if the user types something unexpected, that's neither "q" nor a valid integer.
My point is that explicitly checking scanf's return value like this is an excellent idea, in any program that uses scanf. You should always check to see that scanf succeeded, and do something different if it fails.
Number 2 would look something like this:
char tmpstr[20];
while(some loop condition) {
printf("enter next integer, or 'q' to quit:\n");
if(scanf("%19s", tmpstr) != 1) {
printf("input error\n");
exit(1);
}
if(strcmp(tmpstr, "q") == 0) {
/* end of input detected */
break;
}
i = atoi(tmpstr); /* convert string to integer */
do something with i value just read;
}
This will work well enough, although since it uses atoi it will have certain problems if the user types something other than "q" or a valid integer. (More on this below.)
Number 3 might look like this:
char tmpstr[20];
while(some loop condition) {
printf("enter next integer, or 'q' to quit:\n");
if(fgets(tmpstr, 20, stdin) == NULL) {
printf("input error\n");
exit(1);
}
if(strcmp(tmpstr, "q\n") == 0) {
/* end of input detected */
break;
}
i = atoi(tmpstr); /* convert string to integer */
do something with i value just read;
}
One thing to note here is that fgets includes the newline that the user typed in the string it returns, so if the user types "q" followed by the Enter key, you'll get a string back of "q\n", not just "q". You can take care of that either by explicitly looking for the string "q\n", which is kind of lame (although it's what I've done here), or by stripping the newline back off.
Finally, for both #2 and #3, there's the question of, what's the right way to convert the user's string to an integer, and what if it wasn't a valid integer? The easiest way to make the conversion is to call atoi, as my examples so far have shown, but it has the problem that its behavior on invalid input is undefined. In practice, it will usually (a) ignore trailing nonnumeric input and (b) if there's no numeric input at all, return 0. (That is, it will read "123x" as 123, and "xyz" as 0.) But this behavior is not guaranteed, so these days, most experts recommend not using atoi.
The recommended alternative is strtol, which looks like this:
char *endp;
i = strtol(tmpstr, &endp, 10); /* convert string to integer */
Unlike atoi, strtol has guaranteed behavior on invalid input. Among other things, after it returns, it leaves your auxiliary pointer endp pointing at the first character in the string it didn't use, which is one way you can determine whether the input was fully valid or not. Unfortunately, properly dealing with all of the ways the input might be invalid (including trailing garbage, leading garbage, and numbers too big to convert) is a surprisingly complicated challenge, which I am not going to belabor this answer with.
Here are some guidelines:
scanf("%s", &var) is incorrect: you should pass the maximum number of characters to store into the array var and pass the array without the & as it will automatically convert to a pointer to its first element when passed as an argument:
char var[100];
if (scanf("%99s", var) != 1) {
printf("premature end of file\n");
return 1;
}
to compare the string read to "q", you can use strcmp() declared in <string.h>:
if (strcmp(var, "q") == 0) {
printf("quitting\n");
return 0;
}
to convert the string to the number it represents, use strtol() declared in <stdlib.h>:
char *p;
long value = strtol(var, &p, 0);
testing for a proper conversion is tricky: strtol() updated p to point to the character after the number and set errno in case of range error:
errno = 0;
char *p;
long value = strtol(var, &p, 0);
if (p == var) {
printf("not a number: %s\n", p);
return 1;
}
if (*p != '\0') {
printf("extra characters: %s\n", p);
return 1;
}
if (errno) {
printf("conversion error: %s\n", strerror(errno));
return 1;
}
printf("the number entered is: %ld\n", value);
return 0;
Here is a complete program:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char var[100];
char *p;
long value;
printf("Enter a number: ");
if (scanf("%99s", var) != 1) {
printf("premature end of file\n");
return 1;
}
if (strcmp(var, "q") == 0) {
printf("quitting\n");
return 0;
}
errno = 0;
value = strtol(var, &p, 0);
if (p == var) {
printf("not a number: %s\n", p);
return 1;
}
if (*p != '\0') {
printf("extra characters: %s\n", p);
return 1;
}
if (errno) {
printf("conversion error: %s\n", strerror(errno));
return 1;
}
printf("the number entered is: %ld\n", value);
return 0;
}
You can try this: (Assuming only positive integers needs to convert)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// Write C code here
char var[100];
int numb_flag=1, i=0,number=0;
scanf("%s",var);
while(var[i]!='\0') { // Checking if the input is number
if(var[i]>=48 && var[i]<=57)
i++;
else {
numb_flag = 0;
break;
}
}
if(numb_flag==1) {
number = atoi(var);
printf("\nNumber: %d",number);
} else {
printf("\nNot A Number");
}
return 0;
}
//Mind that in order to be more precise you could also use atof().
//The function works the same way as atoi() but is able to convert float
// (returned value is 'double') the string s
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXILEN 100 /*change the value based on your needs*/
int main(){
int n, lim = MAXILEN;
char s[MAXILEN], *p = s, c;
/*taking the string from the input -- I do not use scanf*/
while(--lim > 0 && (c = getchar()) != EOF && c != '\n')
*p++ = c;
//here you can also do the check (if you want the '\n' char):
//if(c == '\n')
// *s++ = c;
*p = '\0';
if(s[0] == 'q' && s[1] == '\0')
exit(EXIT_SUCCESS); /*change the argument based on your needs*/
else
n = atoi(s);
printf("[DEBUG]: %d\n", n);
}

C if statement, optimal way to check for special characters and letters

Hi folks thanks in advance for any help, I'm doing the CS50 course i'm at the very beginning of programming.
I'm trying to check if the string from the main function parameter string argv[] is indeed a number, I searched multiple ways.
I found in another topic How can I check if a string has special characters in C++ effectively?, on the solution posted by the user Jerry Coffin:
char junk;
if (sscanf(str, "%*[A-Za-z0-9_]%c", &junk))
/* it has at least one "special" character
else
/* no special characters */
if seems to me it may work for what I'm trying to do, I'm not familiar with the sscanf function, I'm having a hard time, to integrate and adapt to my code, I came this far I can't understand the logic of my mistake:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int numCheck(string[]);
int main(int argc, string argv[]) {
//Function to check for user "cooperation"
int key = numCheck(argv);
}
int numCheck(string input[]) {
int i = 0;
char junk;
bool usrCooperation = true;
//check for user "cooperation" check that key isn't a letter or special sign
while (input[i] != NULL) {
if (sscanf(*input, "%*[A-Za-z_]%c", &junk)) {
printf("test fail");
usrCooperation = false;
} else {
printf("test pass");
}
i++;
}
return 0;
}
check if the string from the main function parameter string argv[] is indeed a number
A direct way to test if the string converts to an int is to use strtol(). This nicely handles "123", "-123", "+123", "1234567890123", "x", "123x", "".
int numCheck(const char *s) {
char *endptr;
errno = 0; // Clear error indicator
long num = strtol(s, &endptr, 0);
if (s == endptr) return 0; // no conversion
if (*endptr) return 0; // Junk after the number
if (errno) return 0; // Overflow
if (num > INT_MAX || num < INT_MIN) return 0; // int Overflow
return 1; // Success
}
int main(int argc, string argv[]) {
// Call each arg[] starting with `argv[1]`
for (int a = 1; a < argc; a++) {
int success = numCheck(argv[a]);
printf("test %s\n", success ? "pass" : "fail");
}
}
sscanf(*input, "%*[A-Za-z_]%c", &junk) is the wrong approach for testing numerical conversion.
You pass argv to numcheck and test all strings in it: this is incorrect as argv[0] is the name of the running executable, so you should skip this argument. Note also that you should pass input[i] to sscanf(), not *input.
Furthermore, lets analyze the return value of sscanf(input[i], "%*[A-Za-z_]%c", &junk):
it returns EOF if the input string is empty,
it returns 0 if %*[A-Za-z_] fails,
it also returns 0 if the conversion %c fails after the %*[A-Za-z_] succeeds,
it returns 1 is both conversions succeed.
This test is insufficient to check for non digits in the string, it does not actually give useful information: the return value will be 0 for the string "1" and also for the string "a"...
sscanf() is very tricky, full of quirks and traps. Definitely not the right tool for pattern matching.
If the goal is to check that the strings contain only digits (at least one), use this instead, using the often overlooked standard function strspn():
#include <stdio.h>
#include <string.h>
int numCheck(char *input[]) {
int i;
int usrCooperation = 1;
//check for user "cooperation" check that key isn't a letter or special sign
for (i = 1; input[i] != NULL; i++) {
// count the number of matching character at the beginning of the string
int ndigits = strspn(input[i], "0123456789");
// check for at least 1 digit and no characters after the digits
if (ndigits > 0 && input[i][ndigits] == '\0') {
printf("test passes: %d digits\n", ndigits);
} else {
printf("test fails\n");
usrCooperation = 0;
}
}
return usrCooperation;
}
Let's try this again:
This is still your problem:
if (sscanf(*input, "%*[A-Za-z_]%c", &junk))
but not for the reason I originally said - *input is equal to input[0]. What you want to have there is
if ( sscanf( input[i], "%*[A-Za-z_]%c", &junk ) )
what you're doing is cycling through all your command line arguments in the while loop:
while( input[i] != NULL )
but you're only actually testing input[0].
So, quick primer on sscanf:
The first argument (input) is the string you're scanning. The type of this argument needs to be char * (pointer to char). The string typedef name is an alias for char *. CS50 tries to paper over the grosser parts of C string handling and I/O and the string typedef is part of that, but it's unique to the CS50 course and not a part of the language. Beware.
The second argument is the format string. %[ and %c are format specifiers and tell sscanf what you're looking for in the string. %[ specifies a set of characters called a scanset - %[A-Za-z_] means "match any sequence of upper- and lowercase letters and underscores". The * in %*[A-Za-z_] means don't assign the result of the scan to an argument. %c matches any character.
Remaining arguments are the input items you want to store, and their type must match up with the format specifier. %[ expects its corresponding argument to have type char * and be the address of an array into which the input will be stored. %c expects its corresponding argument (in this case junk) to also have type char *, but it's expecting the address of a single char object.
sscanf returns the number of items successfully read and assigned - in this case, you're expecting the return value to be either 0 or 1 (because only junk gets assigned to).
Putting it all together,
sscanf( input, "%*[A-Za-z_]%c", &junk )
will read and discard characters from input up until it either sees the string terminator or a character that is not part of the scanset. If it sees a character that is not part of the scanset (such as a digit), that character gets written to junk and sscanf returns 1, which in this context is treated as "true". If it doesn't see any characters outside of the scanset, then nothing gets written to junk and sscanf returns 0, which is treated as "false".
EDIT
So, chqrlie pointed out a big error of mine - this test won't work as intended.
If there are no non-letter and non-underscore characters in input[i], then nothing gets assigned to junk and sscanf returns 0 (nothing assigned). If input[i] starts with a letter or underscore but contains a non-letter or non-underscore character later on, that bad character will be converted and assigned to junk and sscanf will return 1.
So far so good, that's what you want to happen. But...
If input[i] starts with a non-letter or non-underscore character, then you have a matching failure and sscanf bails out, returning 0. So it will erroneously match a bad input.
Frankly, this is not a very good way to test for the presence of "bad" characters.
A potentially better way would be to use something like this:
while ( input[i] )
{
bool good = true;
/**
* Cycle through each character in input[i] and
* check to see if it's a letter or an underscore;
* if it isn't, we set good to false and break out of
* the loop.
*/
for ( char *c = input[i]; *c; c++ )
{
if ( !isalpha( *c ) && *c != '_' )
{
good = false;
break;
}
}
if ( !good )
{
puts( "test fails" );
usrCooperation = 0;
}
else
{
puts( "test passes" );
}
}
I followed the solution by the user "chux - Reinstate Monica". thaks everybody for helping me solve this problem. Here is my final program, maybe it can help another learner in the future. I decided to avoid using the non standard library "cs50.h".
//#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
void keyCheck(int);
int numCheck(char*);
int main(int argc, char* argv[])
{
//Error code == 1;
int key = 0;
keyCheck(argc); //check that two parameters where sent to main.
key = numCheck(argv[1]); //Check for user "cooperation".
return 0;
}
//check for that main received two parameters.
void keyCheck(int key)
{
if (key != 2) //check that main argc only has two parameter. if not terminate program.
{
exit(1);
}
}
//check that the key (main parameter (argv [])) is a valid number.
int numCheck(char* input)
{
char* endptr;
errno = 0;
long num = strtol(input, &endptr, 0);
if (input == endptr) //no conversion is possible.
{
printf("Error: No conversion possible");
return 1;
}
else if (errno == ERANGE) //Input out of range
{
printf("Error: Input out of range");
return 1;
}
else if (*endptr) //Junk after numeric text
{
printf("Error: data after main parameter");
return 1;
}
else //conversion succesfull
{
//verify that the long int is in the integer limits.
if (num >= INT_MIN && num <= INT_MAX)
{
return num;
}
//if the main parameter is bigger than an int, terminate program
else
{
printf("Error key out of integer limits");
exit(1);
}
}
/* else
{
printf("Success: %ld", num);
return num;
} */
}

Clang-Tidy: 'fscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead

Somewhat unexperienced with C here!
I'm using CLion to write a program and keep getting this warning message whenever I use fscanf to store a value from an input file into a variable:
Clang-Tidy: 'fscanf' used to convert a string to an integer value, but
function will not report conversion errors; consider using 'strtol'
instead
I don't understand this error as I thought fscanf was the function I should be using to read input files? Can someone explain (at a noob level) what's wrong with the way I'm using it?
Here's a sample of my code:
FILE *initial_configuration_box_1_pointer;
initial_configuration_box_1_pointer = fopen("initial_configuration_box_1.xyz", "r");
fscanf(initial_configuration_box_1_pointer, "%d\n", &N1); // Warning here.
fscanf(initial_configuration_box_1_pointer, "pid\tx\ty\tz\n"); // No warning here.
for (i = 1; i <= n1; i++)
{
fscanf(initial_configuration_box_1_pointer, "p\t%lf\t%lf\t%lf\n", &rx1[i - 1], &ry1[i - 1], &rz1[i - 1]); // Warning here.
}
fclose(initial_configuration_box_1_pointer);
I'm aware similar questions have been asked, but I couldn't understand any of the (few) answers they got...
There are a lot of good reasons for a beginner to avoid scanf completely. (Read http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html). If you're going to use it interactively, never end a format string with whitespace, since doing so will just confuse the user. And always check the value returned by scanf to see if it actually matched any input. A common error is for the input to fail to match the expected data, and the scanf loop becomes an infinite loop repeatedly checking the same invalid input. Perhaps the warning is suggesting the second point above: since scanf does not validate the input for you, you have to do it explicitly by checking how many conversion specifiers scanf was able to match. Try something like:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char ** argv)
{
int n1;
const char *path = argc > 1 ? argv[1] : "initial_configuration_box_1.xyz";
FILE *ifp;
if( (ifp = fopen(path, "r")) == NULL ){
perror(path);
return EXIT_FAILURE;
}
if( 1 != fscanf(ifp, "%d", &n1) || n1 <= 0 ){
fprintf(stderr, "Invalid input\n");
return EXIT_FAILURE;
}
fscanf(ifp, " pid x y z");
double rx1[n1];
double ry1[n1];
double rz1[n1];
for( int i = 0; i < n1; i++ ){
if( 3 != fscanf(ifp, " p %lf %lf %lf", rx1 + i, ry1 + i, rz1 + i) ){
fprintf(stderr, "Invalid input near line %d\n", i);
return EXIT_FAILURE;
}
}
if( fclose(ifp) ){
perror(path);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Note that whitespace in a scanf format string does not match exactly, so using \n or \t or is all the same. Usually, people just use a single space to make it easier to read. Also, whitespace between certain conversion specifiers (notable %d and %lf) is irrelevant, and only included for readability.

How to check if command line parameters are integers

First of all, I am talking about old-fashioned ANSI-C (I mean the ANSI standard and no C99 or newer) compiled with gcc. I am only allowed to use the libraries that can be seen below in the code.
My problem is I have a program that is called in the following way on the Terminal:
program < integer_1 integer_2
While I have been able to figure out how to check for the number of arguments, I'm stuck on checking if those are integers.
If the program is called like this:
program < 1 -13
it should run without complaining but if it is run like this:
program < s 7
it should throw out an error.
Whatever I have tried so far has been utter rubbish. The best thing I have managed so far has been an error message if the second number has been a character. None of my tries has been able to deal with more than one digit but I have figured out why that is.
The problem is that I haven't used command line / terminal arguments with any programming language i now (C++, Java). I would really appreciate it if someone could show me how check for correct input as frankly I am out of ideas.
Am I correct that if I want to deal with numbers bigger than 9, I have to iterate through argv starting from index 2 until I find a space?
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int arc, char *argv[])
{
if(arc != 3)
{
printf("Error: You have entered %d arguments, but two were expected!", arc - 1);
return -1;
}
return 0;
}
The easiest way out is to iterate over the argv[n]s and pass one by one to them to strtol() or similar. Then, check for the error and make the decision. To quote the man page, (emphasis mine)
long int strtol(const char *nptr, char **endptr, int base);
[...]
If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, strtol() stores the original value of nptr in *endptr (and returns 0). In particular, if *nptr is not '\0' but **endptr is '\0' on return, the entire string is valid.
That said, program < integer_1 integer_2 is not exactly the way to pass the command-line arguments. If you want to pass the values arguments as command-line arguments, you shall lose the redirection operator and work with argc and argv[n]s directly..
Best way is to create a function for checking whether it is number or not.if the below function returns true then use atoi(argv[]) to convert them to integers to use it further.
bool isNumber(char number[])
{
int i = 0;
//checking for negative numbers
if (number[0] == '-')
i = 1;
for (; number[i] != 0; i++)
{
//if (number[i] > '9' || number[i] < '0')
if (!isdigit(number[i]))
return false;
}
return true;
}
Just a comment: not an answer
If you are going to use
program < arg1 arg2
You will not see arg1 or arg2 in the main parameters. arg1 is typically a filename or device which contain data which will be read by the program. I don't know if the program will even be able to access arg2. If you wish to pick up arg1 arg2 etc, lose the <
program arg1 arg2
You can try something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int check_cmd_args(char const *str[], int numargs);
int
main(int argc, char const *argv[]) {
if (argc < 2) {
printf("Not enough command line arguements entered\n");
exit(EXIT_FAILURE);
}
if (check_cmd_args(argv, argc)) {
printf("All Command line arguements are integers\n");
} else {
printf("Error, non-integer command line arguement entered\n");
}
return 0;
}
int
check_cmd_args(char const *str[], int numargs) {
int n, i = 0;
for (n = 1; n < numargs; n++) {
if (str[n][0] == '-') {
i = 1;
}
for (; str[n][i]; i++) {
if (!isdigit(str[n][i])) {
return 0;
}
}
}
return 1;
}

How to convert a string of numbers (characters) to integer values in c

I need to convert an array of number characters to integer values, in order to perform math operations in C. When I use atoi(argv[2][count]), it only converts the first digit to an integer. So if argv[2]=123, it only converts the '1' to an integer 1. How can I get '123' to be one integer value, 123? Thanks!
atoi is a good function to use, however you can write your own atoi function in C.
int xatoi(char *s)
{
int result=0;
while(*s)
{
result=result*10+(*s-48);
s++;
}
return result;
}
the logic behind this is every character '1','2',......'s ascii value is stored for example '1' has ASCII value '49'. please compile above program and check for errors i haven't tested it but i am sure it will work.
please see the link below for your reference
http://www.newebgroup.com/rod/newillusions/ascii.htm
argv is an array of string arrays and so argv[N] gives you an array. But argv[N][J] gives you element at position J of the array stored in argv[N]. However, it is strange that compiler did not complain about your code because atoi() function, in fact, expects a pointer (to the null-terminated string) and not a character value. The compiler should have said something like warning: passing argument 1 of ‘atoi’ makes pointer from integer without a cast. I recommend you not to ignore warnings. Personally I tend to compile the code with the highest warning level and not have a single warning, though our codebase at work is many millions of lines of code.
Also, prefer to use strtol over atoi. The problem with atoi is that it ignores invalid input (i.e. just returns you 0 if there is no problem, without affecting errno).
Anyway, here is an example of how to grab an array of base 10 integers from a command line:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i;
int n;
char *e;
int *v;
if (argc < 2) {
fprintf(stderr, "Please specify some numbers\n");
return EXIT_FAILURE;
}
n = argc - 1;
v = alloca(sizeof(int) * n);
for (i = 1; i < argc; ++i) {
v[i-1] = strtol(argv[i][i], &e, 10);
if (!v && errno) {
fprintf(stderr, "Cannot convert '%s' into number: %s\n",
argv[i], strerror(errno));
return EXIT_FAILURE;
} else if (*e != '\0') {
fprintf(stderr, "%s is not a number\n", argv[i]);
return EXIT_FAILURE;
}
}
printf("You have entered the following numbers: %d", v[0]);
for (i = 1; i < n; ++i)
printf(", %d", v[i]);
printf("\n");
return EXIT_SUCCESS;
}
Hope it is useful.

Resources