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.
Related
I have a large legacy program in which programmatically argv parameter is changed programmatically in program init followed by logic that parses the parameters.
In Release mode the program terminates gracefully.
In Debug mode, the program does all the required computation and gives the correct output. But upon exit gives Heap corruption error:
Error Message:
Microsoft Visual C++ Runtime Library
Debug Error!
Program:
...sers\AMD\source\repos\ArgvOverflow\x64\Debug\ArgvOverflow.exe
HEAP CORRUPTION DETECTED: after CRT block (#62) at 0x00000259566FDC90.
CRT detected that the application wrote to memory after end of heap
buffer.
Memory allocated at
minkernel\crts\ucrt\src\appcrt\startup\argv_parsing.cpp(285).
(Press Retry to debug the application)
Abort Retry Ignore
Code:
#include <stdio.h>
int main(int argc, char **argv)
{
argc = 12;
argv[1] = "str1";
argv[2] = "str2";
argv[3] = "str3";
argv[4] = "str4";
argv[5] = "str5";
argv[6] = "str6";
argv[7] = "str7";
argv[8] = "str8";
argv[9] = "str9";
argv[10] = "str10";
argv[11] = "str11";
printf("Hello world\n");
return 0;
}
I have read several posts about modifying argv, where they claim that such modifications are legal according to C standards. I also tried the suggestion to have the line
argv[argc] = NULL;
This is not solving the problem.
It is legal to modify the characters of the argument strings. C11 5.1.2.2.1p2
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.
It is still not allowed to access the array out of bounds, argv will have only argc + 1 elements, not as many as you try to stuff in there.
You cannot mess around with argv like this. argv is not your's, it has been allocated and filled during program start according to the command line.
If you invoke your program like this:
program a b c
then argc is 4, argv[0] points to "program", argv[1] points to "a" etc.
argv[argc] is NULL
But accessing argv[5] and beyond is undefined behaviour because you access an array out of bounds.
This SO article may help too:
How dangerous is it to access an array out of bounds?.
To solve your problem: don't access arrays out of bounds.
You are allowed to modify argc and argv, but that doesn't mean that C suddenly handles (re)allocation of these variables for you. argv will be an array of type char* argv[argc];. It will contain as many pointers as argc says that it contains, no more, no less. Similarly, the length of each string pointed at by argv[i] is as long as what the caller passed.
Example:
myprog.exe foo
This means that argc == 2 and argv will have the length 2. This cannot be changed by your program.
argv[0] will point at a modifiable string "myprog.exe", size 10+1 = 11 bytes. You can change the contents but not store anything longer than 11 bytes there.
argv[1] will point at the string "foo", size 3+1 = 4 bytes. You can change the contents but not store anything longer than 4 bytes there.
(Curiosity: it is perfectly fine and arguably the most correct way to define argv as a VLA like this:
int main (int argc, char* argv[argc]), because argv decays into a char** anyway.)
That all being said, modifying argc and argv, although allowed by the C standard, is horribly bad practice. Don't do this. Instead you should use a local variable and let it refer to argv where needed. Example:
int main (int argc, char* argv[])
{
const char* argstr [12] =
{
"str0",
"str1",
"str2",
"str3",
"str4",
"str5",
"str6",
"str7",
"str8",
"str9",
"str10",
"str11",
};
for(int i=0; i<argc; i++)
{
argstr[i] = argv[i];
}
/* always use argstr here, never argv */
return 0;
}
To solve this, I created a separate char** variable, and used that variable in the code to solve the problem.
Here is what the new code looked like:
#include <stdio.h>
int main(int argc, char **argv)
{
int nargc = 12;
char **nargv;
nargv = malloc(sizeof(char*)*nargc);
nargv[0] = malloc(1 + strlen(argv[0]));
strcpy(nargv[0], argv[0]);
nargv[1] = malloc(1 + strlen("srt1"));
strcpy(nargv[1], "srt1");
nargv[2] = malloc(1 + strlen("srt2"));
strcpy(nargv[2], "srt2");
nargv[3] = malloc(1 + strlen("srt3"));
strcpy(nargv[3], "srt3");
nargv[4] = malloc(1 + strlen("srt4"));
strcpy(nargv[4], "srt4");
nargv[5] = malloc(1 + strlen("srt5"));
strcpy(nargv[5], "srt5");
nargv[6] = malloc(1 + strlen("srt6"));
strcpy(nargv[6], "srt6");
nargv[7] = malloc(1 + strlen("srt7"));
strcpy(nargv[7], "srt7");
nargv[8] = malloc(1 + strlen("srt8"));
strcpy(nargv[8], "srt8");
nargv[9] = malloc(1 + strlen("srt9"));
strcpy(nargv[9], "srt9");
nargv[10] = malloc(1 + strlen("srt10"));
strcpy(nargv[10], "srt10");
nargv[11] = malloc(1 + strlen("srt11"));
strcpy(nargv[11], "srt11");
/* Useful code */
free(nargv[11]);
free(nargv[10]);
free(nargv[9]);
free(nargv[8]);
free(nargv[7]);
free(nargv[6]);
free(nargv[5]);
free(nargv[4]);
free(nargv[3]);
free(nargv[2]);
free(nargv[1]);
free(nargv[0]);
free(nargv);
printf("Hello world\n");
return 0;
}
It is totally plausible to have this kind of setup when doing debug.
One work around which worked for me was to set up a dummy argument list when calling the program, then repopulate argv with the desired data once you get into main.
myprog.exe dummy dummy dummy dummy dummy dummy dummy dummydummy dummydummy dummy
and inside your code
int main (int argc , char* argv[]){
argc = 12;
argv[1] = "str1";
argv[2] = "str2";
argv[3] = "str3";
argv[4] = "str4";
argv[5] = "str5";
argv[6] = "str6";
argv[7] = "str7";
argv[8] = "str8";
argv[9] = "str9";
argv[10] = "str10";
argv[11] = "str11";
printf("Hello world\n");
return 0;
}
This question already has answers here:
What does int argc, char *argv[] mean?
(12 answers)
Closed 5 years ago.
in my C script my input is printing out gibberish and im not sure why
heres more or less what i have on it
int main (int arg, char argv[])
{
printf(argv);
}
this prints out giberish?
The following should yield the results you are looking for
#include <stdio.h>
int main(int argc, char **argv)
{
// Check if there is at least 2 arguments. First argument is the executable name.
if(argc > 1)
{
// Print out a string, followed by a new-line character.
printf("%s\n", argv[1]);
}
// Exit successfully
return 0;
}
Edit: After looking at your code here and some of the things I recommend to change:
The signature of your main function to int main(int argc, char **argv). Here argc is the argument count, and argv are the argument values. argv is a double-pointer. If we consider char* to be a string (sequence of characters in memory terminated by a null-character, or 0), then argv is a pointer to argc-many strings.
Secondly, to check the first program argument, consider making sure that there is in-fact an argument there. if(argc > 1) will make sure there is at least 1 argument to the program (the 0-index argument to a program is the executable path).
When you want to actually check the value of the first argument, de-reference argv to get a "string" with argv[1] //The first argument. Then you can de-reference this string to get the first character
if ( *(argv[1]) == 'f' )
{
....
}
If you want to check for a full string, rather than just a single character, consider using a function such as strcmp defined in <string.h>.
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 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).