Given the following code, my program compiles and runs successfully when I pass arguments into a function that takes a triple char pointer:
char *first[] = { "man", "1", "man", NULL };
char *second[] = { "cat", NULL };
char *third[] = { "wc", NULL };
char *fourth[] = { "cat", "-e", NULL };
char **arguments[] = { first, second, third, fourth, NULL };
I am trying to change arguments to support a variable number of string arrays. For now, I have changed arguments to a triple char pointer with a hard-coded size of 7, and each element has the same hard-coded value:
int count = 7;
int s = sizeof(char **);
char ***arguments = malloc(s * count);
for (size_t i = 0; i < count; i ) {
arguments[i] = { "cat", "file.txt", NULL };
}
However, when I attempt to pass arguments into a function that takes a triple char pointer, this time the program fails to compile. I get the error message
error: expected expression before ‘{’ token
48 | arguments[i] = { "cat", "file.txt", NULL };
With the opening curly bracket before "cat"
highlighted in red. At first, I thought the error occurred because I was trying to treat a pointer like an array, but pointer arithmetic isn't working either. I get the same error when I replace the line inside the for loop with
*(arguments i) = { "cat", "file.txt", NULL };
Could someone please tell me the right way to do this? I have successfully iterated through pointers before, but never anything this complicated. For context, this is part of a larger project to build a shell program that takes piped commands. I found a resource online for how to pipe multiple hard-coded commands, but I am trying to do what I have just explained so that I can make it take user input.
CodePudding user response:
It depends what you mean by variable number of arguments.
If you want to construct an array of pointers to arrays of strings and initialize that to variable contents coming from a file, the user or some other dynamic source, you should use malloc
and possibly realloc
for all of these arrays and handle their lifetimes explicitly.
If you want to construct an array of command locally from a list of initializers known at compile time, but not necessarily fixed, you can use compound literals as shown below, but make sure you use the array and its elements only within the scope of the definition:
int main() {
char **arguments[] = {
(char *[]){ "man", "1", "man", NULL },
(char *[]){ "cat", NULL },
(char *[]){ "wc", NULL },
(char *[]){ "cat", "-e", NULL },
#ifdef BSD
(char *[]){ "ifconfig", NULL },
#endif
};
size_t n = sizeof(arguments) / sizeof(arguments[0]);
for (size_t i = 0; i < n; i ) {
run_command(arguments[i]);
}
return 0;
}
For a simpler and more portable approach without C99 specific constructions, you can use a 2D array:
int main() {
char *arguments[][4] = {
{ "man", "1", "man", NULL },
{ "cat", NULL },
{ "wc", NULL },
{ "cat", "-e", NULL },
#ifdef BSD
{ "ifconfig", NULL },
#endif
};
size_t n = sizeof(arguments) / sizeof(arguments[0]);
for (size_t i = 0; i < n; i ) {
run_command(arguments[i]);
}
return 0;
}
Note that string literals should be used to initialize const char *
objects, the C compiler let's you use them to initialize char *
objects as a sloppy compatibility trick that is disabled at recommend warning levels -Wall -Wextra
or -Weverything
.
CodePudding user response:
You cant do it this way as it is not an initialization.
You can use compound literals.
arguments[i] = (char *[]){"cat", "file.txt", NULL};
But they will stop to exist if you go out of the current scope and you store a reference to it.
Better:
arguments[i] = malloc(sizeof((char *[]){"cat", "file.txt", NULL}));
// ---- or
//arguments[i] = malloc(sizeof((char *[3]){}));
memcpy(arguments[i], (char *[]){"cat", "file.txt", NULL}, sizeof((char *[3]){}));