I am trying to validate user input from the command line with argc and argv but am running into a segmentation fault and am not sure why.
I want to validate the user has entered a positive int (so argc =2 and argv is positive).
Here is my code:
int main (int argc, string argv[])
{
int k = atoi(argv[1]);
if (argc != 2 && k <1)
{
return 1;
}
}
The k < 1 part of my code seems to be working fine, but I get segmentation errors every time I try to run without the program name and an argument (agrc !=2).
EDIT:
More clear description of the error handling problem:
If I run ./myprogram -2
then I get my return 1 as expected.
If I run ./myprogram hjdksfhdsk
then I get my return 1 as expected.
If I run ./myprogram
then I get a segmentation fault.
It is this behaviour that makes me think my handling of the argc value is at fault, but I am not sure why I cannot just test argc !=2.
This is incorrect, since in C string is not a built-in type (and is not a standard type defined in some standard header - notice that C++ has std::string defined in its <string> standard header).
The signature of main has to be
int main(int argc, char**argv);
The convention is that argv[argc] is the null pointer, and the argc pointers from argv[0] to argv[argc-1] are non-null pointers to null-terminated strings.
Notice that (at least on Linux and Posix systems) program arguments are not user input to the program. The shell has been given a command line as input and has expanded that command line into program arguments. Your program could later read some input, e.g. with scanf.
You cannot convert a NULL pointer with atoi, so you should check argc before doing the conversion.
int main(int argc, char**argv) {
if (argc!=2) {
fprintf(stderr, "%s needs two arguments\n", argv[0]);
exit(EXIT_FAILURE);
};
int k = atoi(argv[1]);
if (k<=0) {
fprintf(stderr,
"%s wants a positive first argument, but got %s\n",
argv[1]);
exit(EXIT_FAILURE);
}
// now do the real thing
}
BTW, I believe that (at least on Linux or Posix system) a program should accept the --help argument per the GNU coding standard. I suggest you to use getopt (notably getopt_long) or argp to parse program arguments.
At last, compile with all warnings and debug information (e.g. with gcc -Wall -g) and learn how to use the debugger (e.g. gdb).
Your main should be
int main(int argc, char*argv[])
And do the check before using on atoi on argv[1]
Also all paths should return a value. Bung return 0; at the end
As others have noted string is not a base type. However since you are getting results in one case your segmentation fault has to do with the atoi on argv 1. In c arrays are 0 based so you're trying to convert uninitialized memory. Use the argc test before the atoi.
Related
I'm writing a code that appends text to a file.
It uses fopen in the beginning of WriteToFile so even if the file does not exist, it creates it.
But, what happens when I enter no file at all? no arguments at all? Just ./a.out?
Segmentation fault.
I don't know why, it seems to me I did everything fine to avoid any problems.
int main(int argc, char **argv)
{
char file_name[30] = "file.txt";
printf("%s",file_name); /* for debugging : doesn't print it */
if (0 != argc)
{
strcpy(file_name, argv[1]);
}
WriteToFile(file_name);
}
OR
(in case I can't really put a string literal into char array):
char file_name[30];
if (0 == argc)
{
strcpy(file_name, "file.txt");
}
else
{
strcpy(file_name, argv[1]);
}
For both of the cases i'm getting
Segmentation fault (core dumped)
if (0 != argc)
The argc value is normally(a) the count of arguments including the program name. Hence, running ./a.out will have an argc of one rather than zero. And, since argv[argc] is usually NULL, dereferencing it is not going to end well :-)
If you want to ensure another argument is available, you can use:
if (argc > 1) { // Have both argv[0] AND argv[1].
nowSafeToUse(argv[1]);
}
In more detail, the C11 standard states:
If they are declared, the parameters to the main function shall obey the following constraints:
The value of argc shall be nonnegative.
argv[argc] shall be a null pointer.
If the value of argc is greater than zero, the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment. If the host environment is not capable of supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the strings are received in lowercase.
If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name; argv[0][0] shall be the null character if the program name is not available from the host environment. If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc-1] represent the program parameters.
The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.
As an aside regarding this line:
printf("%s",file_name); /* for debugging : doesn't print it */
If this is not printing, it's probably because standard output is line buffered (default if it's determined to be an interactive device, otherwise fully buffered).
By not outputting a \n at the end, the characters are probably still sitting in a buffer somewhere, ready to be written. The crash will probably kill off the process without flushing the buffer. So a simple solution may be just to use one of:
printf("%s",file_name);
puts(file_name);
As another aside, you're going to get into trouble if the filename you enter is larger than 29 characters since it will overflow file_name, allowing for the \0 at the end as well.
A better approach may be just to use either your default string or argv[1] directly (without copying), something like:
int main(int argc, char **argv) {
char *file_name = (argv > 1)
? argv[1]
: "file.txt";
printf("%s\n", file_name); // for debugging : probably does print it :-)
WriteToFile(file_name);
}
(a) Not required by the standard since it allows for implementation-specific differences, but it's the usual case. Specifically, the phrase:
... which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment.
pretty much means it can do whatever it wants :-)
A related answer (though a non-duplicate question) can be found here.
When argc is 1, argv is treated as an array of 2 pointers to char. The first is a valid pointer (typically to the program name), the second is NULL.
argv[1] accesses the second element of argv. With no arguments supplied, argc will be 1 and argv[1] will be NULL. You're therefore dereferencing a NULL pointer.
The condition 0 != argc should instead be argc >= 2 or argc > 1, and the condition 0 == argc should be argc < 2 or argc <= 1.
You have to account for the program's name so you should write if (argc >= 2) instead. See the man
The value of the argc argument is the number of command line arguments. The argv argument is a vector of C strings; its elements are the individual command line argument strings. The file name of the program being run is also included in the vector as the first element; the value of argc counts this element. A null pointer always follows the last element: argv[argc] is this null pointer.
argv[1] means index 1 but in C you start at index 0.
Fixed code
int main(int argc, char **argv)
{
char file_name[30] = "file.txt";
printf("%s",file_name); /* for debugging : doesn't print it */
if (argc >= 2)
strcpy(file_name, argv[1]);
else
return 1; // exit program with error code.
WriteToFile(file_name);
return 0; // exit with success
}
This is a sample code from a book. This program prints a given string to repeat given number of times.
#include <stdio.h>
#include <stdlib.h>
void usage(char *program_name)
{
printf("Usage: %s <nessage> <# of times to repeat>\n", program_name);
exit(1);
}
int main(int argc, char *argv[]) {
int i, count;
if(argc < 3)
usage(argv[0]);
count = atoi(argv[2]);
printf("Repeating %d times..\n", count);
for(i=0; i < count; i++)
printf("%3d - %s\n", i, argv[1]);
}
It does what it should do:
kingvon#KingVon:~/Desktop/asm$ ./convert 'Stackoverflow is the best place to ask questions about programming' 6
Repeating 6 times..
0 - Stackoverflow is the best place to ask questions about programming
1 - Stackoverflow is the best place to ask questions about programming
2 - Stackoverflow is the best place to ask questions about programming
3 - Stackoverflow is the best place to ask questions about programming
4 - Stackoverflow is the best place to ask questions about programming
5 - Stackoverflow is the best place to ask questions about programming
kingvon#KingVon:~/Desktop/asm$
Q. Now although main takes two arguments in this specific order: (int argc, char *argv[]), why is that when I ./convert 'string' (number) it works fine but other way around `./convert (number) 'string' does not work?
kingvon#KingVon:~/Desktop/asm$ ./convert 5 'Stackoverflow is the best place to ask questions about programming'
Repeating 0 times..
Q. This line
if(argc < 3) usage(argv[0]);
I have 2 questions about: This line specifies that if the integer argument given is less than 3, the program should output the usage. ./convert 'string' 2 does not print the usage? So what is happening here? Also usage takes char *program_name as an argument(what is meant by char *program_name?) But in line above is given argv[0] as an argument. Why is this and what does this do?
argc is the number of arguments on the command line, not the value of any particular argument. argv contains the actual arguments, which are passed as strings. argv[0] is the command used to invoke the program, argv[1] is the first argument, etc.
When you call the program as
./convert 'Stackoverflow ...' 6
then
argv[0] == "./convert"
argv[1] == "Stackoverflow ..."
argv[2] == "6”
argc == 3
The code assumes that the number is passed in argv[2] and uses the atoi function to convert it from a string representation of an integer to an integer value, which is why the code didn’t behave as expected when you switched the order of the arguments. If you want to be able to switch up the order of the arguments, then your code has to know how to detect which argument is which.
The argc variable is the number of elements in the argv array. And the actual command line arguments will be in the argv array.
The first argument on the command line will always be in argv[1], the second in argv[2], etc.
If you change the order when running the program, the program doesn't know about that, and will think that the string to print will still be in argv[1] and the number in argv[2]. If that's not true the program will fail to work properly.
The argc check only check the number of arguments, not their order.
The name of the program ("./convert" in your question) is always passed as argument zero, i.e. in argv[0].
write c program that accepts one command line argument (your first name) and prompts the user for user input (your last name), then print ""Welcome to operating systems, "" to the screen.
Can anyone help me with this question? I know its using something like this from the below, but I dunno how to print out the thing? Can anyone help by giving the full answer? Thanks in advance.
int main (int argc, int *argv[])
argc is an integer that represents the number of command line arguments passed in to the program. It is the argument count, hence the name. *argv[] (or **argv depending on developer preference) represents the actual arguments. The proper name for argv is argument vector, which makes sense if you're familiar with that particular data type.
The first argument passed in, argc = 1 is the program's name. Argc is always at least one because argv will always contain at a minimum the name of the program.
To answer your question, you need to pass in a second command-line argument, argc = 2, where argv[1] equals the user's first name. We can accomplish that like this:
int main(int argc, char** argv)
{
// This line will print out how many command line arguments were passed in.
// Remember that it will always be at least one because the name of the program
// counts as an argument.
printf("argc: %d", argc);
// Remember that you want the second argument in argv,
// so you have to call argv[1] because arrays in C
// are 0-index based. Think of them as offsets.
printf("\nWelcome, %s", argv[1]);
return 0;
}
This should get you started. All you need to do now is write the code to read the string from the standard input and output it to the console.
Let's say I have a C program whose function declaration is void square(int n), (it's also defined) all it does it printf the squared value of n. I want to be able to run it from bash shell like so: square 5, where 5 is the input to the C program.
How would I go about this? I've looked into using getopt, read, I've read the man pages several times and watched a few getopt tutorials, but I can't seem to figure out a way to do this. I can't find an example of getopt that doesn't use flags in the examples, so I don't know how to apply it to a simple integer input. Could anyone share with me how to do this? I would really appreciate it.
If you don't have any other command line options you need to handle, getopt is probably overkill. All you need is to read the value from argv:
int main(int argc, char *argv[])
{
int n;
// need "2 args" because the program's name counts as 1
if (argc != 2)
{
fprintf(stderr, "usage: square <n>\n");
return -1;
}
// convert the first argument, argv[1], from string to int;
// see note below about using strtol() instead
n = atoi(argv[1]);
square(n);
return 0;
}
A better solution will use strtol() instead of atoi() in order to check if the conversion was valid.
This question already has answers here:
Pass arguments into C program from command line
(6 answers)
Closed 6 years ago.
I don't know what to do! I have a great understanding of C basics. Structures, file IO, strings, etc. Everything but CLA. For some reason I cant grasp the concept. Any suggestions, help, or advice. PS I am a linux user
The signature of main is:
int main(int argc, char **argv);
argc refers to the number of command line arguments passed in, which includes the actual name of the program, as invoked by the user. argv contains the actual arguments, starting with index 1. Index 0 is the program name.
So, if you ran your program like this:
./program hello world
Then:
argc would be 3.
argv[0] would be "./program".
argv[1] would be "hello".
argv[2] would be "world".
Imagine it this way
*main() is also a function which is called by something else (like another FunctioN)
*the arguments to it is decided by the FunctioN
*the second argument is an array of strings
*the first argument is a number representing the number of strings
*do something with the strings
Maybe a example program woluld help.
int main(int argc,char *argv[])
{
printf("you entered in reverse order:\n");
while(argc--)
{
printf("%s\n",argv[argc]);
}
return 0;
}
it just prints everything you enter as args in reverse order but YOU should make new programs that do something more useful.
compile it (as say hello) run it from the terminal with the arguments like
./hello am i here
then try to modify it so that it tries to check if two strings are reverses of each other or not then you will need to check if argc parameter is exactly three if anything else print an error
if(argc!=3)/*3 because even the executables name string is on argc*/
{
printf("unexpected number of arguments\n");
return -1;
}
then check if argv[2] is the reverse of argv[1]
and print the result
./hello asdf fdsa
should output
they are exact reverses of each other
the best example is a file copy program try it it's like cp
cp file1 file2
cp is the first argument (argv[0] not argv[1]) and mostly you should ignore the first argument unless you need to reference or something
if you made the cp program you understood the main args really...
For parsing command line arguments on posix systems, the standard is to use the getopt() family of library routines to handle command line arguments.
A good reference is the GNU getopt manual
Siamore, I keep seeing everyone using the command line to compile programs. I use x11 terminal from ide via code::blocks, a gnu gcc compiler on my linux box. I have never compiled a program from command line. So Siamore, if I want the programs name to be cp, do I initialize argv[0]="cp"; Cp being a string literal. And anything going to stdout goes on the command line??? The example you gave me Siamore I understood! Even though the string you entered was a few words long, it was still only one arg. Because it was encased in double quotations. So arg[0], the prog name, is actually your string literal with a new line character?? So I understand why you use if(argc!=3) print error. Because the prog name = argv[0] and there are 2 more args after that, and anymore an error has occured. What other reason would I use that? I really think that my lack of understanding about how to compile from the command line or terminal is my reason for lack understanding in this area!! Siamore, you have helped me understand cla's much better! Still don't fully understand but I am not oblivious to the concept. I'm gonna learn to compile from the terminal then re-read what you wrote. I bet, then I will fully understand! With a little more help from you lol
<>
Code that I have not written myself, but from my book.
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
printf("The following arguments were passed to main(): ");
for(i=1; i<argc; i++) printf("%s ", argv[i]);
printf("\n");
return 0;
}
This is the output:
anthony#anthony:~\Documents/C_Programming/CLA$ ./CLA hey man
The follow arguments were passed to main(): hey man
anthony#anthony:~\Documents/C_Programming/CLA$ ./CLA hi how are you doing?
The follow arguments were passed to main(): hi how are you doing?
So argv is a table of string literals, and argc is the number of them. Now argv[0] is
the name of the program. So if I type ./CLA to run the program ./CLA is argv[0]. The above
program sets the command line to take an infinite amount of arguments. I can set them to
only take 3 or 4 if I wanted. Like one or your examples showed, Siamore... if(argc!=3) printf("Some error goes here");
Thank you Siamore, couldn't have done it without you! thanks to the rest of the post for their time and effort also!
PS in case there is a problem like this in the future...you never know lol the problem was because I was using the IDE
AKA Code::Blocks. If I were to run that program above it would print the path/directory of the program. Example: ~/Documents/C/CLA.c it has to be ran from the terminal and compiled using the command line. gcc -o CLA main.c and you must be in the directory of the file.
Main is just like any other function and argc and argv are just like any other function arguments, the difference is that main is called from C Runtime and it passes the argument to main, But C Runtime is defined in c library and you cannot modify it, So if we do execute program on shell or through some IDE, we need a mechanism to pass the argument to main function so that your main function can behave differently on the runtime depending on your parameters. The parameters are argc , which gives the number of arguments and argv which is pointer to array of pointers, which holds the value as strings, this way you can pass any number of arguments without restricting it, it's the other way of implementing var args.
Had made just a small change to #anthony code so we can get nicely formatted output with argument numbers and values. Somehow easier to read on output when you have multiple arguments:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("The following arguments were passed to main():\n");
printf("argnum \t value \n");
for (int i = 0; i<argc; i++) printf("%d \t %s \n", i, argv[i]);
printf("\n");
return 0;
}
And output is similar to:
The following arguments were passed to main():
0 D:\Projects\test\vcpp\bcppcomp1\Debug\bcppcomp.exe
1 -P
2 TestHostAttoshiba
3 _http._tcp
4 local
5 80
6 MyNewArgument
7 200.124.211.235
8 type=NewHost
9 test=yes
10 result=output