Suppose we are given a task to write a function that add 2 numbers.
#include <stdio.h>
int main(int argc, char ** av) {
int a = atoi(av[1]);
int b = atoi(av[2]);
add_and_print(a, b)
return 0;
}
It works fine untill I pass following code:
./a.out
Just passing empty strings. Then it writes the following:
1495 segmentation fault (core dumped)
Could you please explain what is the problem and how do I deal with it ?
argc contains the number of arguments provided to the program, and if you don't check it then you might get a segfault trying to read from argv. You can display an error message and exit if there aren't enough arguments:
if (argc < 3) {
puts("Please provide 2 numbers as command line arguments.");
return 1;
}
How do I deal with segfault
The segfault happens because of a bug in your code.
So, you prevent it happening in the first place, by not writing buggy code.
In general though, the segfault makes it easy to find out exactly what bug triggered it: just run your program under the debugger, and it will stop exactly where the segfault occurs.
Could you please explain what is the problem
In this code:
int a = atoi(av[1]);
the expression av[1] is only legal if there are at least two elements in array av (since we start indexing at zero). If there is only one element, this code attempts to read beyond the end of the array.
Since the array is based on the command-line arguments, you must check it. You need to do this for all inputs from users, files, even other parts of your own code. Don't just assume the user did what you expected (or the file contained what you expected, or the caller passed the right values). This is a bug.
if (argc >= 2) {
// now it is safe to refer to av[1]
a = atoi(av[1]);
}
You have to do something similar for av[2], for the same reason.
A common solution might be instead
int main(int argc, char **argv) {
if (argc < 3) {
printf("Syntax: %s a b\n"
"\n"
"Two integer arguments are required.", argv[0]);
return -1;
}
int a = atoi(argv[1]);
int b = atoi(argv[2]);
add_and_print(a, b)
}
I'm just assuming that argc is at least 1, and that argv[0] is the name of the program. You can check this too if you want perfectly portable code.
Note that you might also want to check whether the arguments are really integers.
Related
This question already has answers here:
How to properly compare command-line arguments?
(4 answers)
Closed 4 years ago.
So I have to write a program that contains two possible options depending on what the user chooses by entering either -i or -w. I'm very new to command line arguments in general and I have no idea how to do this. So far I have:
#include <stdio.h>
int main(int argc, char *argv[])
{
if(argc == -'i') {
puts("Test 1");
}
else if(argc == -'w') {
puts("Test 2");
}
return 0;
}
It doesn't print anything...
Any explanation is greatly appreciated. I'm just trying to understand the logic behind this.
First of all, you are comparing oranges with appels. argc stores the number of
arguments. Second, even if you used argv[1], the comparison would be still
wrong, because it would be comparing pointers, not the contents. Note that in C
a string is a sequence of characters that terminates to '\0'-terminating byte.
A char* variable only points to the start of that sequence. The == operator
checks for equality of values, in case of pointers (and string literals), it
compares whether both pointers point to the same location.
When you want to compare strings, you have to compare the strings themselves,
that means you have to compare the contents where the pointers are pointing to.
For strings you have to use the strcmp function like this:
#include <stdio.h>
int main(int argc, char *argv[])
{
if(argc != 2)
{
fprintf(stderr, "usage: %s option\n", argv[0]);
return 1;
}
if(strcmp(argv[1], "-i") == 0)
puts("Test 1");
else if(strcmp(argv[1], "-w") == 0)
puts("Test 2");
else {
fprintf(stderr, "Invalid option '%s'\n", argv[1]);
return 1;
}
return 0;
}
Note that it is important to check first that you have enough command line
arguments (the first if of my code). If the user didn't pass any argument,
argc will be 1 and argv[1] will point to NULL, which would yield undefined
behaviour if it is passed to strcmp. That's why I only do strcmp when I'm
100% sure that argv[1] is not NULL.
Also if you are coding for a POSIX system (linux, mac, etc), then I recommend using
getopt for parsing of the command line arguments.
You have to check argv[i] where i is the array number of the command line argument being put in, argv[0] would be the file name called upon and after that argv[1] would be the first statement, argv[2] the next and so on
argc means "argument count". meaning the number of arguments
argv is a 2-dimensional array. Strings are 1-dimensional character arrays in C. The second dimension comes from you having multiple String.
So if you want the first String argument, you would access it as follows:
argv[0]
You are also attempting to compare strings, which are more than 1 character long. You should use strcmp to compare strings in C. See How do I properly compare strings?
and if you want to compare equality, you would not use ==, == is for basic data types such as int or char.
argc represents the number of parameters that were passed in at the command line including the program name itself.
In c, a character, e.g., 'i' is an 8-bit number representing the ASCII code of the letter i. So your conditional statement if(argc == -'i') is actually checking whether -105 (105 is the ascii value of the letter i) is the number of arguments that was passed to your program.
To check whether the arguments passed in are "-i" or "-w" you need to perform string comparison, using the c library functions or your own algorithm, and you need to be comparing those strings to argv[i] (where i is the position of the parameter you're checking in the program invocation)
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("The name of the program is %s\n", argv[0]);
if( strcmp(argv[1], "-i") == 0 ) { puts("Test 1"); }
if( strcmp(argv[1], "-w") == 0 ) { puts("Test 2"); }
return 0;
}
This is my main function code
os2.c
#include <stdio.h>
int main( int argc, char *argv[]){
int item;
item = argc;
printf("%d", item);
return 0;
}
I run the following command line in Ubuntu's terminal
gcc -o test os2.c
./test 5
The result printed is equal to 2 instead of 5, What's wrong with my code?
First, your question is not just for Ubuntu/Linux.
It works in Windows and Macintosh too including every OS using the terminal.
argc = argument count: the number of argument that are passed to a program
argv = argument vector: passed arguments
argc is an int that count the arguments of your command line.
I run the following command line in Ubuntu's terminal: gcc -o test os2.c
./test 5
Here your arguments are
argv[0] == ./test
argv[1] == 5
So we conclude that:
argc is 2 based on the number of arguments above.
argv contains the arguments that we've passed to the program.
This is an example of how you use arguments in the right way:
source.c
#include <stdio.h>
int main(int argc, char **argv){
for(int i = 0;i < argc;i++)
printf("arg %d : %s\n",i,argv[i]);
return 0;
}
Command Line
gcc -o test source.c
./test this is a test
Output
arg 0 : ./test
arg 1 : this
arg 2 : is
arg 3 : a
arg 4 : test
But anyways, I recommend to never use the first argument; It'd be a gap in your software cause it can be hacked easily. There're many ways to do whatever you want in C.
Now; You should know what you've to do if you want to get the value 5 instead of counting the number of arguments that you've passed to your application which in the OP case were 2.
argc means the number of argument that are passed to the program. not printed which value you have passed.
Use argv[1] to print value of 5.
#include <stdio.h>
int main(int argc, char **argv)
{
if (argc >= 2)
printf("%d\n", atoi(argv[1]));
return(0);
}
argc (argument count) and argv (argument vector) are how command line arguments are passed to main() in C and C++.
argc is number of arguments passed to program (number of strings pointed to by argv), which is correct in your case. First string is program name, second string is "5" (so you have to convert "5" to int).
This might be a useful reading for you.
If you want to convert second argument to int try this
if (argc < 2)
{
return -1;
}
int item = atoi(argv[1]);
atoi may lead to undefined behavior so you should use strtol instead.
Or you may loop through all arguments
for(int i = 0; i < argc; i++)
{
// argv[i] is the argument at index i
// You may print them
printf("%s", argv[i]);
// Convert them, ...
}
Nothing wrong with code. You are passing two arguments ./test and 5. So it shows 2. It is the number of arguments passed to the program.
argc : argument count.
To get the argument passed you can do this.
printf("%s",argv[1]);
In general you check it like this:
if(argc!=2)
{
printf("Usage: ./program-name argument\n");
return EXIT_FAILURE; // failure-considering you are writing this in main.
}
// do your work here.
But in argv[1] you will get the char string. To get an integer out of it, you have to convert it using something like atoi or your custom conversion function. Also you can use strtol() which is useful in conversion from string to long.
1. In case of main return EXIT_FAILURE works but not in other functions but exit(EXIT_FAILURE) works in all the functions
argc is the count of arguments, which is 2 here. If you intend to print 5, you need to print argv[1] (or if you always want the last argument, argv[argc-1]) instead.
I've the following code :
#include <stdio.h>
int main(int argc, char* argv[]){
int a = argv[1]?atoi(argv[1]):10;
int b = argv[2]?atoi(argv[2]):20;
printf("a = %d, b = %d\n", a, b);
return 0;
}
If I do not provide any command line inputs, the values in "a" and "b"
should be 10 and 20 respectively, but what happens instead is "a" gets value as 10 whereas "b" gets 0.
I cant understand why this is happening, since I am doing exactly same
thing in both cases.
Thanks.
The runtime (often thru crt0 & kernel) guarantees (per C99 or POSIX standards) that (for main's arguments argc & argv) :
argc is positive
argv is a valid non NULL pointer to an array of argc+1 pointers
argv[argc] is the NULL pointer
for each i between 0 and argc-1 included, argv[i] is a (valid non NULL) pointer to a zero-terminated string
hence access to argv[j] with j>argc (or j<0) is undefined behavior (UB) - so explaining what happens is only possible by diving into implementation details...
the valid argv[i] are not pointer aliases, so if i & j are both between 0 and argc-1 included, and i != j, argv[i] != argv[j]
therefore, your code is wrong when argc==1 because accessing argv[2] is forbidden (UB).
You should code:
int main(int argc, char* argv[]){
int a = (argc>1)?atoi(argv[1]):10;
int b = (argc>2)?atoi(argv[2]):20;
Be very scared of undefined behavior (see also the references here). Sadly, a program with UB might sometimes appear to "work" (that is might not crash). But at other times bad things may happen. So you should imagine the worst.
If I do not provide any command line inputs, the values in "a" and "b"
should be 10 and 20 respectively.
No, if you don't provide any command-line inputs, you're accessing beyond the end of the argv array and anything can happen (including your program crashing and burning).
Your checks should be:
int a = argc > 1 ? atoi(argv[1]) : 10;
int b = argc > 2 ? atoi(argv[2]) : 20;
That's what argc is for, to tell you how many entries argv has in it that you can access.
I’m not sure if this is the correct way to do this. See my code below.
I want to be able to pass a list of arguments to main, which would then get stored in another array.
So, I want to be about to start the program with at least 1 argument… or as many arguments as I like. I might set a max amount of arguments to 32.
Eg.
./foo 3
Or
./foo 3 56 12 34 56 111 2222 33
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i;
int numbersEntered[argc];
if (argc <= 1){
printf("Not enough arguments entered\n");
exit(1);
}
printf("Arg count %i\n",argc-1);
for (i=1;i<argc;i++)
numbersEntered[i]=atoi(argv[i]);
for (i=1;i<argc;i++)
printf(" numbersEntered %i\n", numbersEntered[i]);
}
That is already the case, argv is an array of pointers, one pointer for each argument on the command line (plus two, actually, the first one is the name of the program, then the arguments, and then a terminating NULL-pointer).
Regarding the array, the problem is that traditional C requires a size that is known at compile time, you can't just use argc; that said, some compilers like GCC, and more recent C standards, do allow it.
I am solving a problem on USACO. In the problem, I have to take two strings as inputs and calculate the numerical values modulo 47. If the values are same, then GO is to be printed otherwise STAY has to be printed. The initial numerical value will be calculated by taking the product of the numerical values of the alphabets ( 1 for A and similarily 26 for Z ) and then the final number will be calculated by using modulo.
My program is being compiled withour any error and the first case is also a success. But the problem is in the second case and the way my file is being appended. The program is as follows:-
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define MAX 6
main()
{
int cal(char *ptr);
int a,b;
char *comet,*group;
FILE *fptr;
comet=malloc(6*sizeof(char));
group=malloc(6*sizeof(char));
scanf("%s",comet);
a=cal(comet);
scanf("%s",group);
b=cal(group);
fptr=fopen("ride.out","a+"); (1)
//fptr=fopen("ride.txt","a+"); (2)
if(a==b)
fprintf(fptr,"GO\n"); (3)
//printf("GO\n"); (4)
else
fprintf(fptr,"STAY\n"); (5)
//printf("STAY\n"); (6)
fclose(fptr);
return 0;
}
int cal(char *ptr)
{
int c,prod=1,mod;
while(*ptr)
{
c=(*ptr++)-'A'+1;
prod=prod*c;
}
mod=prod%47;
return mod;
}
OUTPUT:-
The first case is the set two strings:-
COMETQ
HVNGAT
and the second case is given in the error notification itself.
If I remove the comment symbols from (2) and put it on (1), then the program is working fine because I can see the contents of the file and they appear just as the grader system wants. It isn't happening for the actual statement of (1). The comments of line (4) and (6) are also fine but not the line (1). I am not able figure this out. Any help?
First a few notes:
main(): a decent main is either:
int main(void)
or
int main(int argc, char *argv[])
Using malloc() you should always check if it returns NULL, aka fail, or not.
Always free() malloc'ed objects.
Everyone has his/hers/its own coding style. I have found this to be invaluable when it comes to C coding. Using it as a base for many other's to. Point being structured code is so much easier to read, debug, decode, etc.
More in detail on your code:
Signature of cal()
First line in main you declare the signature for cal(). Though this works you would probably put that above main, or put the cal() function in entirety above main.
Max length
You have a define #define MAX 6 that you never use. If it is maximum six characters and you read a string, you also have to account for the trailing zero.
E.g. from cplusplus.com scanf:
specifier 's': Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence.
Thus:
#define MAX_LEN_NAME 7
...
comet = malloc(sizeof(char) * MAX_LEN_NAME);
As it is good to learn to use malloc() there is nothing wrong about doing it like this here. But as it is as simple as it is you'd probably want to use:
char comet[MAX_LEN_NAME] = {0};
char group[MAX_LEN_NAME] = {0};
instead. At least: if using malloc then check for success and free when done, else use static array.
Safer scanf()
scanf() given "%s" does not stop reading at size of target buffer - it continues reading and writing the data to consecutive addresses in memory until it reads a white space.
E.g.:
/* data stream = "USACOeRRORbLAHbLAH NOP" */
comet = malloc(szieof(char) * 7);
scanf("%s", buf);
In memory we would have:
Address (example)
0x00000f comet[0]
0x000010 comet[1]
0x000011 comet[2]
0x000012 comet[3]
0x000013 comet[4]
0x000014 comet[5]
0x000015 comet[6]
0x000016 comet[7]
0x000017 /* Anything; Here e.g. group starts, or perhaps fptr */
0x000018 /* Anything; */
0x000019 /* Anything; */
...
And when reading the proposed stream/string above we would not read USACOe in to comet but we would continue reading beyond the range of comet. In other words (might) overwriting other variables etc. This might sound stupid but as C is a low level language this is one of the things you have to know. And as you learn more you'll most probably also learn to love the power of it :)
To prevent this you could limit the read by e.g. using maximum length + [what to read]. E.g:
scanf("%6[A-Z]", comet);
| | |
| | +------- Write to `comet`
| +-------------- Read only A to Z
+---------------- Read maximum 6 entities
Input data
Reading your expected result, your errors, your (N) comments etc. it sound like you should have a input file as well as an output file.
As your code is now it relies on reading data from standard input, aka stdin. Thus you also use scanf(). I suspect you should read from file with fscanf() instead.
So: something like:
FILE *fptr_in;
char *file_data = "ride.in";
int res;
...
if ((fptr_in = fopen(file_data, "r")) == NULL) {
fprintf(stderr, "Unable to open %s for reading.\n", file_data);
return 1; /* error code returned by program */
}
if ((res = fscanf(fptr_in, "%6[A-Z]%*[ \n]", comet)) != 1) {
fprintf(stderr, "Read comet failed. Got %d.\n", res);
return 2;
}
b = cal(comet);
if ((res = fscanf(fptr_in, "%6[A-Z]%*[ \n]", group)) != 1) {
fprintf(stderr, "Read group failed. Got %d.\n", res);
return 2;
}
...
The cal() function
First of, the naming. Say this was the beginning of a project that eventually would result in multiple files and thousand of lines of code. You would probably not have a function named cal(). Learn to give functions good names. The above link about coding style gives some points. IMHO do this in small projects as well. It is a good exercise that makes it easier when you write on bigger to huge ones. Name it e.g. cprod_mod_47().
Then the mod variable (and might c) is superfluous. An alternative could be:
int cprod_mod_47(char *str)
{
int prod = 1;
while (*str)
prod *= *(str++) - 'A' + 1;
return prod % 47;
}
Some more general suggestions
When compiling use many warning and error options. E.g. if using gcc say:
$ gcc -Wall -Wextra -pedantic -std=c89 -o my_prog my_prog.c
This is tremendous amount of help. Further is the use of tools like valgrind and gdb invaluable.