I am making a program that can take another program as an argument and run it.
I am using execv() to run the second program, but how can I use argv[] (that comes from the main program, is a char*) as arguments for execv()?
The first element of argv[] is the name of the main program, so I need to start at the second element where the name of the next program is located.
I am thinking there might be different solutions, for example:
Tell execv() to start from the second argument
copy the content of argv[] (except first element) to another array and use that
Something with pointers so maybe I can point to the second element and start there
What is the best way to do this?
And can I get an example of how to do it?
First of all, the argv is actually a pointer to array of pointers. The more correct way to define it would be char **argv.
Defining it as *argv[] is just a syntactic sugar. So your third guess is a best one:
#include <stdio.h>
void print_array(int array_size, char **array) {
for(int i=0; i<array_size; i++) {
printf("\t%s\n", array[i]);
}
}
int main(int argc, char **argv) {
char **argv_new = argv+1;
printf("argv:\n");
print_array(argc, argv);
printf("argv_new:\n");
print_array(argc-1, argv_new);
return 0;
}
You can also play with interchanging function arguments char **argv vs char *argv[] and you wont see a difference.
But code like:
int main(int argc, char *argv[]) {
char *argv_new[] = argv+1;
will give you an error - of invalid type conversion. That is due to a fact that defining an array on a stack requires to know the size of array during the compilation. But defining array as a function parameter - does not, the compiler in that case presumes that the stack manipulation is done in the caller function.
Related
I'm studying C in order to start doing some fun low-level code stuff, and I've stumbled into a scenario which I can't wrap my head around, and I'm sure it's because I don't have a lot of experience with it.
Currently my code is very simple: it takes some arguments, and gets the first parameter passed to main, and stores it as a path string. The first question that came to mind, was whether it would be correct to store the main params as char *args[] or char **args, and I decided to go with char **args since according to this question there could be some scenarios where the first would not be accessible, and I just wanted to make a code that would be as complete as possible, and learn the whys on the process.
Here's is the code:
int main(int argc, char **args) {
if (args[1] == NULL) return 1;
// Get path of input file
char *path = &*args[1];
fputs(path, stdout);
return 0;
}
Given the code above, what would be a better way of fetching the value stored in *args[1]? It seems very cryptic when I look at it, and it took me a while to get to it as well.
My understanding is that char **args, is a pointer, to an array of pointers. Thus, if I'm to store a string or any other value for later use in one of the indexes of args, I would have to assign a new pointer to a memory location (*path), and assign the value of the given index to it (&*args[i]). Am I over complicating things? Or is this thought process correct?
For starters these two function declarations
int main(int argc, char **args)
and
int main(int argc, char *args[])
are fully equivalent because the compiler adjusts the parameter that has an array type to pointer to the array element type.
In the initializer expression of this declaration
char *path = &*args[1];
applying the two operators & and * sequentially is redundant. So you may just write
char *path = args[1];
Also in general instead of the condition in the if statement
if ( args[1] == NULL) return 1;
it will be more safer to write
if ( argc < 2 ) return 1;
You can simply write:
char *path = args[1];
& and * operators are inverses of each other, so &* or *& can simply be removed from an expression.
I have a function
int executeCommand(char args[][TOKENSIZE]){
char *argv[] = {args[0], args[1]}; // This works
char *argv[] = {args}; // This doesn't
}
The args variable will not be of fixed length so I can't use the first line as it is. I don't want to use malloc or free due to some reasons. Is there any way of initializing this argv array from args without hard coding the number of entries.
The function needs to know the size somehow or it is mission impossible. One possible way is to use pointers to VLA:
int executeCommand(size_t n, char args[n][TOKENSIZE]){
char* argv[n];
for(size_t i=0; i<n; i++)
{
argv[i] = args[i];
}
}
As for you why you can't simply use args instead of copying the array addresses, I have no idea.
A complete hard-copy of the data would look like
char argv[n][TOKENSIZE];
memcpy(argv, args, sizeof(char[n][TOKENSIZE]));
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'm trying to read in two filenames and save them as a global variable in C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char infilename;
char outfilename;
int main(int argc, const char* argv[]){
strcopy(infilename, argv[1]);
return 0;
}
However this does not work. Can someone help me with a really simple problem like this?
You are trying to copy a string (const char *) to a character (char). You need to either declare infilename as a string:
char *infilename;
infilename = malloc(...
or make a static array:
char infilename[NUM_OF_CHARS];
Read up on c strings here.
Also choose your language, if you are really using c++ you need to start using std::string
A better way to do it.
char infilename[50];
char outfilename[50];
int main(int argc, const char* argv[]){
if(argc == 3)
{
strcpy (infilename,argv[1]);
strcpy (outfilename,argv[2]);
}
else
{
//do something else
}
return 0;
}
You need array of char and not only char. A string in C is an array of char. And you must always verify (if(argc == 3) if the user entered the quantity of argument you want, because if it's not the case your applicatin can crash.
That's not going to work.
These:
char infilename;
char outfilename;
declare a variables that store a single char, not an entire string.
You either need to make those char arrays:
char infilename[MAX_PATH];
char outfilename[MAX_PATH];
or pointers that you plan to initialize with malloced memory. You have to pick which one you mean.
P.s. there's no function called strcopy, it's strcpy.
The main problem is that you made your global variables single characters not an array of characters which is needed for a string.
Assuming you don't want to change the contents of the string then the easiest thing is to simply set a global to point to the same string rather than copying it. Because the program will end when main returns there is no worry about the parameters argv going out of scope.
Note you would have to worry about this if you create a new thread and terminate the thread running main without terminating the program.
#include <stdio.h>
#include <stdlib.h>
static char* gInFilenamePtr;
static char* gOutFilenamePtr;
int main(int argc, const char* argv[])
{
if( argc > 2 )
{
gInFilenamePtr = argv[1];
gOutFilenamePtr = argv[2];
}
return 0;
}
This is my main.c
......
int main(int argc, char **argv)
{
init_arg(&argc, &argv);
......
}
This is my init_arg.c
......
void init_arg(int *argc, char ***argv)
{
printf("%s\n", *argv[1]);
......
}
I compiler it with no error and warning.
I run it:
./a.out include
It get Segmentation fault
When I debug it, I found step printf("%s\n", *argv[1]);
get wrong, It show:
print *argv[1]
Cannot access memory at address 0x300402bfd
I want to know, How to print argv[1] in init_arg() function.
You need to add a pair of parentheses around (*argv) to change the order of evaluation. The way you currently have it, the [1] is evaluated first, yielding an invalid pointer, which then gets dereferenced, causing undefined behavior.
printf("%s\n", (*argv)[1]);
Argv is already a pointer. Just pass it like this:
init_arg(&argc, argv);
And init_arg should look like this:
void init_arg(int *argc, char **argv) {
printf("%s\n", argv[1]);
}
I'm assuming that the reason for passing &argc and &argv in the first place is so that you can update them inside init_arg. Here's how I prefer to write such functions, in general:
/*
* init_arg: do something useful with argc and argv, and update argc and argv
* before returning so that the caller can do something else useful that's
* not shared with all the other callers of init_arg().
* (this comment of course needs updating to describe the useful things)
*/
void init_arg(int *argc0, char ***argv0) {
int argc = *argc0;
char **argv = *argv0;
... all the operative code goes here, and then ...
*argc0 = argc;
*argv0 = argv;
}
Of course this means you must not do early returns inside init_arg, so there are some tradeoffs, but it sure is a lot easier to work with the same regular old argc and argv inside init_arg.