I have just started learning C and I have a basic question. How do I read out a command line argument. For example, if I execute:
./main "test"
How can I get the command line parameter "test" into a variable:
int main(int argc, char **argv){
char s[] is supposed to equal "test"
}
EDIT: Basically I want to create a new char array that equals argv[1].
char * s = argv[1];//to read the test
if(strcmp(s,"test") == 0){
//the command line argument is equal to the string test
}
The arguments argc and argv of the main function are used to access the string arguments passed to your program when it is started. argc is the number of arguments passed. For example when run like this - ./myprogram arg1 arg2 arg3, argc will have a value of 4. This is because along with the strings the user passes in the name of the program is also passed. That is argv[0] points to a string myprogram, argv[1] points to arg1 etc. To get the nth argument then you must access argv[n + 1].
Knowing this, to make a copy of the first argument you can do as follows
char * s = malloc(strlen(argv[1]) + 1);
strcpy(s, argv[1]);
However I would advise making sure that the argument you want doesn't point to NULL before copying it. This is where argc is handy. Before accessing argv[1] I would check if argc >= 2.
There is a much better explanation here http://crasseux.com/books/ctutorial/argc-and-argv.html or here http://www.cprogramming.com/tutorial/c/lesson14.html
Edit:
Remember to free any memory you allocate via free
eg. free(s).
Related
I am currently working on a project where I am manipulating command line data, but I can't seem to get it work if I initialize the size of the array before.
char* len2[50]; // will store "1","2","3" from command line args
int size_arr = sizeof(len2) / sizeof(len2[0]);
printf("%d", size_arr);
this will input 50 when I am looking for it to input 3. How would I be able to find the size?
int size_arr = sizeof(len2) / sizeof(len2[0]);
sizeof(len2) asks for the total allocated size of len2 in bytes. This only works because C knows how many you allocated at compile time and turns it into a constant. It doesn't tell you which ones you've filled in. C does not keep track of that; you have to.
Because len2 is an array of pointers, you can mark the end with a null pointer. The term for this is a sentinel value. First, be sure to initialize the array to null.
// This will initialize the entire array to NULL
char* len2[50] = {NULL};
Now you can find how many elements are in the array by looking for the first null, or by hitting the allocated size.
size_t len2_size = sizeof(len2) / sizeof(len2[0]);
int size = 0;
for( ; len2[size] != NULL && size < len2_size; size++ );
printf("size: %d\n", size);
This is, incidentally, basically how C strings work. The end of the string is marked with a 0.
Alternatively, you can store the allocated size and number of elements in a struct and keep track, but that's another question.
Finally, if you're just reading command line arguments, use argc and argv. argc is the size of argv. argv[0] is the name of the program, and the rest are the command line arguments.
int main( const int argc, const char **argv) {
printf("%d arguments in argv\n", argc-1);
}
And argv is also terminated with a NULL pointer so it's easy to iterate through.
// Because argv[0] is the name of the program,
// start at 1 and read until you hit a null pointer.
for( int i = 1; argv[i] != NULL; i++ ) {
printf("argv[%d] = %s\n", i, argv[i]);
}
From the comments:
I guess what I'm trying to find is the number of items. Since there are 3 numbers I'll be getting from the command line, I want to be able to manipulate the array using 3 for a for or while loop for example.
According to the standard you have two versions of main function available (while the implementation defining further ones is legal):
int main();
int main(int, char**);
The second form gets the command line parameters passed to directly while the first form can be used if command line parameters are irrelevant.
Typically (but not necessarily) these two arguments get named argc and argv with argc containing the total number of command line arguments and argv a null-terminated array to the actual arguments. First one of is always the name that has been used to call the programme (which can differ in some cases from the actual executable name, e.g. if symbolic links are involved) which you might want to skip.
So a programme simply iterating over all arguments and printing them back to console might look like this:
int main(int argc, char* argv[])
{
for(++argv; *argv; ++argv)
{
printf("%s\n", *argv);
}
return 0;
}
with first ++argv skipping the programme name, *argv profiting from and testing for the null-terminator of the array and second ++argv being the normal loop post operation.
If you want to see the programme name as well you might just skip very first pointer increment:
for(;*argv;++argv)
Alternative variants might use an integer to count up to argc – just a matter of personal taste...
I have to fill the parameters for:
int execve(const char *filename, char *const argv[], char *const envp[]);
If I execute this program:
#include <unistd.h>
int main() {
char *args[2];
args[0] = "/bin/sh";
args[1] = NULL;
execve(args[0], args, NULL);
}
the shell is spawned correctly as expected.
My problem is that the shell is spawned correctly also if I pass a NULL as second parameter like that:
#include <unistd.h>
int main() {
char *args[2];
args[0] = "/bin/sh";
args[1] = NULL;
execve(args[0], NULL, NULL);
}
So what's the purpose to use the args vector (with the "/bin/sh" + NULL) as second parameter instead of a NULL?
In this line: execve(args[0], NULL, NULL); you are simply using the first element of args array. You could also use something like char* command="/bin/sh". You have to pass something, because that's how execve() was defined. In your case you pass NULL because you don't need to pass anything.
The point of the second argument of execve() is to pass arguments to the command you are spawning. Suppose that instead of shell you simply want to execute ls, you could then pass f.e. these arguments:
#include <unistd.h>
int main() {
char *args[2];
args[0] = "/bin/ls";
args[1] = "-lh";
execve(args[0], args, NULL);
}
Also, quoting man execve:
argv is an array of argument strings passed to the new program. By
convention, the first of these strings should contain the filename
associated with the file being executed. envp is an array of
strings, conventionally of the form key=value, which are passed as
environment to the new program.
If you pass a null pointer as the second, or the third, argument of execve, your program is incorrect according to POSIX; both of these arguments are required to be non-null. (This is not all that clearly stated in the specification of execve, but it's in there.) I am currently typing this on an operating system that treats passing null pointers,
execve("executable", 0, 0);
as equivalent to passing empty arrays, e.g.
execve("executable", (char *[]){0}, (char *[]){0});
but it would not surprise me to learn that other operating systems would fire a segmentation fault or return -1 with errno set to EFAULT or EINVAL.
Passing empty arrays for these arguments is allowed, but the newly executed program will receive zero arguments in argc/argv if the second argument is an empty array, and/or zero environment variables in envp/environ if the third argument is an empty array. Many programs will malfunction under these conditions. For instance, it is very common to see things like
int main(int argc, char **argv)
{
if (argc != 4) {
fprintf(stderr, "usage: %s one two three\n", argv[0]);
return 2;
}
// ...
}
where the program implicitly assumes that argv[0] will always be non-null.
So, you should always provide non-empty arrays for both arguments. The usual convention is that if you don't have anything else to do, you use
execve(program, (char *[]){program, 0}, environ);
which supplies the program's own name as argv[0] and no further arguments, and the same set of environment variables you got from your own parent.
I want to call snmpget.c from another c program in the same project. For that reason I have changed the main() into a function say get_func() which takes the same arguments. But i an not sure how to give the arguments namely argv[0]
My arguments look something like this:
char *argstr[]=
{
"v",
"1",
"c",
"public",
"-Ovq",
"192.168.1.1",
"ifInOctets.7",
"ifOutOctets.7",
NULL
};
And then
i = get_func(10, argstr);
1.Should argv[0] be the app name or path?
2.Is using char *argstr[] correct for c?
3.snmpget is not taking these arguments correctly. What could the reason be?
It works correctly with the same args in command.
Your get_func expects the arguments starting at argv[1], so your argstr argument should not start with "v" but with something else (e.g. the programme name or just an empty string if get_func doesn’t use it).
Yes. But be aware that your argstr contains non-modifiable strings, if get_func wants to modify them, you can use compound literals
char *argstr[]=
{
(char []){ "v" },
(char []){ "1" },
/* etc */
NULL
};
See 1. and 2. Additionally, argc is incorrect (must be sizeof argstr/sizeof *argstr - 1, which is 8 in your case, not 10).
Not directly an answer to your question, but consider redesigning this (depends on what exactly you’re currently doing, however). For example, write a function accepting a structure where the different options are stored (already parsed and validated) and change the old main from snmpget.c to a function only scanning and validating arguments, initializing such a structure object, and calling this function. And then, perhaps split your files into snmpget.c, snmpget_main.c, another_c_file.c (with better names, of course) and link both user interface implementations against the object file of snmpget.c.
Yes, if your main uses it. If not, just pass NULL is enough >o<
Sure, it's array of pointers. char *argstr[9] is equal to
typedef char *pchar;
pchar argstr[9];
Well, I assume you don't give appropriate argc and don't pass the app name by argv[0] because the argc is 10, but the number of content of argv is 8. (I've counted excluding NULL, but the NULL is required yet - argv[argc] should be NULL.)
To reduce mistakes, I suggest to use sizeof(argstr) / sizeof(argstr[0]) - 1 instead of calculating argc yourself.
See live example. Code:
#include <stdio.h>
int test(int argc, char *argv[]);
int main()
{
char *argstr[] = {
"test.exe",
"--opt-1",
"--output",
"test.txt",
NULL
};
int argcount = sizeof(argstr) / sizeof(argstr[0]) - 1;
return test(argcount, argstr);
}
int test(int argc, char *argv[])
{
int i;
printf("argc: %d\n", argc);
printf("program name: %s\n", argv[0]);
for (i = 1; argv[i] != NULL; i++)
{
printf("argument %d is: %s\n", i, argv[i]);
}
return 0;
}
Output:
argc: 4
program name: test.exe
argument 1 is: --opt-1
argument 2 is: --output
argument 3 is: test.txt
I understand what argv and argc do and how they're used, but I am in need to recreate them. In C, how would you write a function to imitate them.
You just create an array to store the parameters to pass in as argv, and set argc accordingly, something like;
int argc = 3;
char* argv[argc + 1];
argv[0] = "binary name";
argv[1] = "first parameter";
argv[2] = "second parameter";
argv[3] = NULL;
int result = main(argc, argv);
argc and argv are used when you are starting a program from the command line, or want to pass some variables to the program.
argc contains the number of arguments and argv is an array of pointers to the arguments which are strings.
These arguments to main is
main(int argc, char** argv)
The syntax char** argv declares argv to be a pointer to a pointer to a character, that is, a pointer to a character array (a character string)--in other words, an array of character strings. You could also write this as char* argv[].
When you run a program, the array argv contains, in order, all the information on the command line when you entered the command (strings are delineated by whitespace), including the command itself. The integer argc gives the total number of strings, and is therefore equal to equal to the number of arguments plus one. For example, if you typed
a.out -i 2 -g -x 3 4
the program would receive
argc = 7
argv[0] = "a.out"
argv[1] = "-i"
argv[2] = "2"
argv[3] = "-g"
argv[4] = "-x"
argv[5] = "3"
argv[6] = "4"
In C and C++, the function prototype of the main function looks like this:
int main(int argc, char *argv[]);
You cannot recreate them but you could change their names.
In your main you could type in int main(int numberOfArguments, char *arrayOfArguments[]) and use numberOfArguments as argc and arrayOfArguments as argv.
I am writing a C program. It takes its arguments from commandLine. I want to change the commandLine arguments in the code. As they are defined as "const char *", I can not change them using "strcpy", "memcpy", ... Also, you know, I can not just change their type from "const char *" to "char *".
Is there any way to change them?
Thank you so much in advance.
Best regards,
Shadi.
According to C99 §5.1.2.2.1/1, the signature for main is
int main(int argc, char *argv[]) { /* ... */ }
So you are allowed to remove the const. Just don't cause a buffer overrun by strcpying in longer strings than the original arguments, or attempting to install more arguments than originally passed.
Everyone else is basically right that you should create a copy instead.
No, you are not allowed to modify those. However, there's no rule against copying them to a new buffer and using those instead.
This may be beside the point, but you can't change anything with neither strcpy() nor memcpy(); the suffix 'cpy' is short for copy (unsurprisingly.)
Regarding changing the argv pointer, you could of course change the pointer, but why? If you want the command line arguments to be something other than what's given, just ignore them, and use whatever values you prefer. Also note that argv is a parameter and thus local to main(); if it is needed elsewhere, you have to either pass it as a parameter, or save it as a global variable.
It doesn't matter if you change the const char * to char * of main function.
Only one thing you must care about is buffer overrunning of strcpy.
According to ELF spec(see figure 3-31 stack layout), http://refspecs.linuxbase.org/elf/abi386-4.pdf, function parameter area is followed by environment value area.
argv is array of pointers to each parameter, and environ is also array of pointers to each environment var=value string.
So layout is like below.
argv[0] --> 1st parameter
argv[1] --> 2nd parameter
argv[2] --> 3rd parameter
...
NULL
--------------------------------------- memory boundary between param and env
environ[0] --> 1st env_var=env_value
environ[1] --> 2nd env_var=env_value
environ[2] --> 3rd env_var=env_value
...
NULL
So if you copy very long string to argv[0], it can overrun the boundary between param and env.
In this case, you must move argv and environ memory area to another heap space like below.
I extracted below example code from Postgresql open source code. ps_status.c)
char ** new_environ;
char ** new_argv;
char ** org_argv;
int i;
new_argv = (char **) malloc((argc + 1) * sizeof(char *));
for (i = 0; i < argc; i++)
new_argv[i] = strdup(argv[i]);
new_argv[argc] = NULL;
org_argv = argv;
argv = new_argv;
new_environ = (char **) malloc((i + 1) * sizeof(char *));
for (i = 0; environ[i] != NULL; i++)
new_environ[i] = strdup(environ[i]);
new_environ[i] = NULL;
environ = new_environ;
Then, you can use getopt, getenv, etc.
They will read the values from newly allocated memory area.
In addition, if you change original parameter(org_argv[0]), you can manipulate the output name of your process in ps command. (also in top, htop utility)
See below.
$> ps -ef | grep my_proc
dplee 10855 1 0 7월28 pts/2 00:00:16 my_proc i can manipulate this name