0

My question is based of a previous question asking how C optget works with multiple values: C getopt multiple value

In my case, I have only one argument -i, which is optional. Users must use this syntax:

/a.out -i file1 -i file2 -i file3

If users do not provide the -i flag, the program runs fine. Users may provide an unlimited number of files as optional arguments, e.g.

/a.out -i file1 -i file2 -i file3 -i file4 -i file5 ...

I begin with this getopt() while statement in main():

char *input;  // ?? Now syntactically correct, but uninitialized?

while ((opt = getopt(argc, argv, "i:"))!= -1){
    case 'i':
        if (optarg == NULL){
            input = NULL;
            } 
        else{
            strcpy(input, optarg);
            break;
  ...
}

I then would pass these optional arguments to a function:

function1(char *required_arg, ...)

In the case of the above, it would be:

function1(required_arg, file1, file2, file3, file4, file5)

At the moment, I am defining input to be the "file". My question is, how do I keep track of an arbitrary number of optional arguments to later pass into a function? The above code is wrong, as I'm redefining input for each -i argument passed.

What data structure does one use?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
ShanZhengYang
  • 16,511
  • 49
  • 132
  • 234
  • You can pass an array of arguments (You can store them in an array) – user2736738 Dec 02 '17 at 16:47
  • @coderredoc How would I calculate the length of arguments passed through `i`? That is, in the above, there are 5 files – ShanZhengYang Dec 02 '17 at 17:03
  • Correct me if I am wrong - You want to get the name of the files that you got from the options `-i file1 -i file2` and then you want to pass them to other method. Now your question is how you pass them to other method? – user2736738 Dec 02 '17 at 17:11
  • @coderredoc Yes. Perhaps I've misunderstood how `optget()` works above, but I would think I would need to save each of these strings (e.g by appending to an array), and then iterate through this array, feeding the strings into `function1`. – ShanZhengYang Dec 02 '17 at 17:14
  • There may be other ways - but storing it in array is one of those. Again if you store it in an array - why can't you pass the whole array to the method `function1`? And now if the method only takes single string at a time - then why can't you pass the arguments one-by-one when you get the options one by one in `while` loop? – user2736738 Dec 02 '17 at 17:19
  • "Again if you store it in an array - why can't you pass the whole array to the method function1?" I guess I could. "And now if the method only takes single string at a time - then why can't you pass the arguments one-by-one when you get the options one by one in while loop?" This I don't understand how I would do – ShanZhengYang Dec 02 '17 at 17:23
  • `optarg` contains those filenames on every iteration. That's why you copy them in `input`. Now if you pass `input` to the method `function1()` then that will be the passing of single filename to the method. That way on the fly, you will parse the options and pass them to the `function1`. – user2736738 Dec 02 '17 at 17:27
  • I don't understand---the function must contains all files passed at once, i.e. `function1(required, file1)` `function1(required, file2)` would be wrong. It may be better to see code to understand what you mean... – ShanZhengYang Dec 02 '17 at 17:31
  • I mentioned that - *if the method only takes single string at a time* - which it doesn't. So passing an array of arguments would be good. – user2736738 Dec 02 '17 at 17:32
  • @coderredoc I'm still unsure an array is best. I would have to set a fixed size of the array for an arbitrary number of arguments, which maybe 0. – ShanZhengYang Dec 02 '17 at 17:49
  • @coderredoc "You can store them in an array". Can you have a dynamically growing empty array in C, whereby you initialize the array with `malloc()`, then find the size of the `file1` with `realloc()` and `strlen()`? I would prefer not to set the size of the array first – ShanZhengYang Dec 02 '17 at 18:07
  • Yes you can have that. You can initially have certain number of elements and then when you run out of memory then you reallocate and work with it. – user2736738 Dec 02 '17 at 18:08
  • @coderredoc Do you have an example of how this would be done for strings which may be NULL (as this is optional)? I'm also not clear how one parses these values from the array into `function1()` such that they are comma separated – ShanZhengYang Dec 02 '17 at 18:16
  • If ithe string is empty just by pass it. And also you are getting it wrong. You will pass array of file names not comma seperated values. – user2736738 Dec 02 '17 at 18:17
  • "You will pass array of file names not comma seperated values." How would the function parse these? – ShanZhengYang Dec 02 '17 at 18:27
  • By looping in the array. Don't need to parse these. You are already providing an array of strings (null terminated characters). `for( i = 0; i < count; i++) { //files[i] will contain the i-th file name}`. – user2736738 Dec 02 '17 at 18:29
  • @coderredoc I'm sorry---I still don't quite understand how that simultaneously passes these file names in the function – ShanZhengYang Dec 02 '17 at 18:31
  • Check the answer..hope you will get some help. – user2736738 Dec 02 '17 at 19:01

1 Answers1

2

The solution that is being suggested by me was to pass the file names in an array. This solution assumed a maximum file count of 10 and maximum file name length to be 30. But on similar note we can provide the chance of dynamic allocation allowing any number of files.

#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define MAXLEN 30
#define MAXFILECOUNT 10
void print(int fileCount, char files[][MAXLEN+1]){
    for(int i = 0; i < fileCount; i++){
        printf("%s \n",files[i]);
    }
}
int main(int argc, char **argv)
{
    int opt;
    char fileName[MAXFILECOUNT][MAXLEN+1];
    int count = 0;

    while ((opt = getopt(argc, argv, "i:")) != -1)
    {
        switch (opt)
        {
        case 'i':
            snprintf(fileName[count++],MAXLEN,"%s",optarg);
            break;
        }
    }
    print(count,fileName);
    return 0;
}

Call the program like

./a.out -i file1 -i file2
user2736738
  • 30,591
  • 5
  • 42
  • 56
  • Thank you for the help. The above makes sense to me. However, I'm still not understanding how the function `function1()` would take the file names in the array, and work with them. If the function call is `function1(required_arg, file1, file2, file3)`, then `function1()` must be written such that it grabs these file names and does something with them. Does my question make sense? – ShanZhengYang Dec 02 '17 at 19:42
  • 1
    @ShanZhengYang: You can't sensibly write a function to take a variable length argument list and then call it easily with a number of arguments that varies at run-time. Think about `printf()`; you always fix the number of arguments that will be passed in the call at compile-time, and you can't change the number at run-time. Similarly with `execl()` and `execlp()`; you can't change the number of arguments in the variable list at run-time (specifically, you can't have it grow to an indefinite size; there are ways to work with a maximum size or smaller). _[…continued…]_ – Jonathan Leffler Dec 02 '17 at 20:09
  • 1
    _[…continuation…]_ If you want an indefinite number of arguments at run-time, then you use an array and a length (for example, `qsort()`), or an array and sentinel (for example, `execvp()` — typically, for arrays of strings or any other array of pointers, the sentinel is a null pointer). This is what is being suggested. – Jonathan Leffler Dec 02 '17 at 20:11
  • @JonathanLeffler There may be some confusion RE: "you can't change the number at run-time" Don't mean to suggest doing this above. I think I'm asking something more simple, i.e. how the function would "unpack" these array values. I suppose iteration like `print()` above would be the correct method. – ShanZhengYang Dec 02 '17 at 20:14
  • @ShanZhengYang: Yes, inside the called function, you'd iterate over the array elements. – Jonathan Leffler Dec 02 '17 at 20:16