Pass arguments into C program from command line

143,349

Solution 1

You could use getopt.

 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>

 int
 main (int argc, char **argv)
 {
   int bflag = 0;
   int sflag = 0;
   int index;
   int c;

   opterr = 0;

   while ((c = getopt (argc, argv, "bs")) != -1)
     switch (c)
       {
       case 'b':
         bflag = 1;
         break;
       case 's':
         sflag = 1;
         break;
       case '?':
         if (isprint (optopt))
           fprintf (stderr, "Unknown option `-%c'.\n", optopt);
         else
           fprintf (stderr,
                    "Unknown option character `\\x%x'.\n",
                    optopt);
         return 1;
       default:
         abort ();
       }

   printf ("bflag = %d, sflag = %d\n", bflag, sflag);

   for (index = optind; index < argc; index++)
     printf ("Non-option argument %s\n", argv[index]);
   return 0;
 }

Solution 2

In C, this is done using arguments passed to your main() function:

int main(int argc, char *argv[])
{
    int i = 0;
    for (i = 0; i < argc; i++) {
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    return 0;
}

More information can be found online such as this Arguments to main article.

Solution 3

Consider using getopt_long(). It allows both short and long options in any combination.

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

/* Flag set by `--verbose'. */
static int verbose_flag;

int
main (int argc, char *argv[])
{
  while (1)
    {
      static struct option long_options[] =
    {
      /* This option set a flag. */
      {"verbose", no_argument,       &verbose_flag, 1},
      /* These options don't set a flag.
         We distinguish them by their indices. */
      {"blip",    no_argument,       0, 'b'},
      {"slip",    no_argument,       0, 's'},
      {0,         0,                 0,  0}
    };
      /* getopt_long stores the option index here. */
      int option_index = 0;

      int c = getopt_long (argc, argv, "bs",
               long_options, &option_index);

      /* Detect the end of the options. */
      if (c == -1)
    break;

      switch (c)
    {
    case 0:
      /* If this option set a flag, do nothing else now. */
      if (long_options[option_index].flag != 0)
        break;
      printf ("option %s", long_options[option_index].name);
      if (optarg)
        printf (" with arg %s", optarg);
      printf ("\n");
      break;
    case 'b':
      puts ("option -b\n");
      break;
    case 's':
      puts ("option -s\n");
      break;
    case '?':
      /* getopt_long already printed an error message. */
      break;

    default:
      abort ();
    }
    }

  if (verbose_flag)
    puts ("verbose flag is set");

  /* Print any remaining command line arguments (not options). */
  if (optind < argc)
    {
      printf ("non-option ARGV-elements: ");
      while (optind < argc)
    printf ("%s ", argv[optind++]);
      putchar ('\n');
    }

  return 0;
}

Related:

Solution 4

Take a look at the getopt library; it's pretty much the gold standard for this sort of thing.

Solution 5

Instead of getopt(), you may also consider using argp_parse() (an alternative interface to the same library).

From libc manual:

getopt is more standard (the short-option only version of it is a part of the POSIX standard), but using argp_parse is often easier, both for very simple and very complex option structures, because it does more of the dirty work for you.

But I was always happy with the standard getopt.

N.B. GNU getopt with getopt_long is GNU LGPL.

Share:
143,349
BlackCow
Author by

BlackCow

Updated on April 28, 2020

Comments

  • BlackCow
    BlackCow about 4 years

    So I'm in Linux and I want to have a program accept arguments when you execute it from the command line.

    For example,

    ./myprogram 42 -b -s

    So then the program would store that number 42 as an int and execute certain parts of code depending on what arguments it gets like -b or -s.

  • OscarRyz
    OscarRyz over 15 years
    Shouldn't He/She understand "main arguments passing" first? ;)
  • Jonathan Leffler
    Jonathan Leffler over 15 years
    It will work on Linux because the getopt() function is GNU getopt() and you don't normally set POSIXLY_CORRECT in the environment, and GNU getopt() then processes option arguments before 'file' arguments, even when they follow a file argument as in the example. On POSIX platforms, it won't work....
  • Jonathan Leffler
    Jonathan Leffler over 15 years
    ....because the 42 will stop the -b and -s options from being interpreted as options. Of course, the design of the command line is bad too. I'll note that in the comments to the question.
  • Jonathan Leffler
    Jonathan Leffler over 15 years
    Sorry - that's not a dreadfully good x-ref. There's a bug in the statement that "The declaration of the argv argument is often a novice programmer's first encounter with pointers to arrays of pointers and can prove intimidating" (argv is an array of pointers, not a pointer to an array of pointers).
  • Jonathan Leffler
    Jonathan Leffler over 15 years
    Additionally, the next page shows an ad hoc option parser instead of using the standard getopt() or getopt_long() parsers - which is simply bad advice. No - it is not a good reference.
  • jfs
    jfs over 15 years
    @Jonathan: The question does have the tag linux. Therefore GNU getopt() example is appropriate here.
  • dmckee --- ex-moderator kitten
    dmckee --- ex-moderator kitten over 15 years
    "getopt is GNU LGPL": That depends on the getopt. It has been implemented several times. The one in Mac OS X is BSD licensed.
  • Jonathan Leffler
    Jonathan Leffler over 15 years
    @J F Sebastian - yes, it does have a Linux tag; that's why it has an upvote from me. The structure of a command line and arguments ordering should not rely on that quirk; well, I still have to work across other platforms, and GNU getopt is not standard on other platforms (for all it is available).
  • Jonathan Leffler
    Jonathan Leffler over 15 years
    ...continued...As ever, if you do something consciously, knowing what is happening, it is usually OK. If you are unaware of it, you get nasty surprises sooner or later.
  • Jonathan Leffler
    Jonathan Leffler over 15 years
    And AT&T released one in the mid-80s into the public domain, or something very close to the public domain. D McKee's point is very valid - GNU getopt() [and getopt_long()] are LGPL (or, older versions are GPL); not all versions of getopt() are GPL or LGPL.
  • Shannon Nelson
    Shannon Nelson over 15 years
    In C, a reference to an array is an address, just like a pointer is an address. Thus, argv can be referred to as both "an array" and "a pointer to an array". This is one of the beautiful simplicities of C as well as one of the points of confusions.