Processing command line arguments

Discussion in 'C Programming' started by Gregor H., Apr 21, 2007.

  1. Gregor H.

    Gregor H. Guest

    In K&R (2nd edition) the authors published the following code for
    dealing with command line arguments (p. 117):

    while (--argc > 0 && (*++argv)[0] == '-')
    while (c = *++argv[0])
    switch (c) {
    case 'x':
    except = 1;
    break;
    case 'n':
    number = 1;
    break;
    default:
    printf("find: illegal option %c\n", c);
    argc = 0;
    found = -1;
    break;
    }

    But this solution raised some criticism:

    "The sample program increments argv[0]. Although argv is
    modifiable, and argv[0][0] is modifiable (if argv[0] is
    not a null pointer), argv[0] is not modifiable. (At least,
    not always.)"

    (Peter Seebacher, http://www.plethora.net/~seebs/c/knr.html)

    "p.117 (§5.10): In the find example, the program increments
    argv[0]. This is not specifically forbidden, but not
    specifically allowed either."

    (Source:
    Errata for The C Programming Language, Second Edition
    http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html)

    Now my question is: would the following (slight modification of the
    original code) be a reasonable (or at least correct) solution?:

    while (--argc > 0 && (*++argv)[0] == '-') {
    char *arg = *argv;
    while (c = *++arg)
    switch (c) {
    case 'x':
    except = 1;
    break;
    case 'n':
    number = 1;
    break;
    default:
    printf("find: illegal option %c\n", c);
    argc = 0;
    found = -1;
    break;
    }
    }


    G.

    --

    E-mail: info<at>simple-line<Punkt>de
     
    Gregor H., Apr 21, 2007
    #1
    1. Advertising

  2. "Gregor H." <nomail@invalid> wrote in message
    news:...
    > In K&R (2nd edition) the authors published the following code for
    > dealing with command line arguments (p. 117):
    >
    > while (--argc > 0 && (*++argv)[0] == '-')
    > while (c = *++argv[0])
    > switch (c) {
    > case 'x':
    > except = 1;
    > break;
    > case 'n':
    > number = 1;
    > break;
    > default:
    > printf("find: illegal option %c\n", c);
    > argc = 0;
    > found = -1;
    > break;
    > }
    >
    > But this solution raised some criticism:
    >
    > "The sample program increments argv[0]. Although argv is
    > modifiable, and argv[0][0] is modifiable (if argv[0] is
    > not a null pointer), argv[0] is not modifiable. (At least,
    > not always.)"
    >
    > (Peter Seebacher, http://www.plethora.net/~seebs/c/knr.html)
    >
    > "p.117 (§5.10): In the find example, the program increments
    > argv[0]. This is not specifically forbidden, but not
    > specifically allowed either."
    >
    > (Source:
    > Errata for The C Programming Language, Second Edition
    > http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html)
    >
    > Now my question is: would the following (slight modification of the
    > original code) be a reasonable (or at least correct) solution?:
    >
    > while (--argc > 0 && (*++argv)[0] == '-') {
    >

    This line is virtually unreadable. I know K and R used the same construct.
    Things have moved on.
    >
    > char *arg = *argv;
    > while (c = *++arg)
    >

    However this is the way round. argv contains a list of strings. Nothing
    conceptually difficult about that, but you can make it look difficult
    because strigns are not atomic objects in C. It is a bad idea to modify the
    strings in place, though I think they are writeable for historical reasons,
    and it is a bad idea and may even be illegal to modify the pointers in the
    argv array.
    However if you take copies then you can do what you want with the copy,
    naturally.
    --
    Free games and programming goodies.
    http://www.personal.leeds.ac.uk/~bgy1mm
     
    Malcolm McLean, Apr 21, 2007
    #2
    1. Advertising

  3. Gregor H. wrote:
    > In K&R (2nd edition) the authors published the following code for
    > dealing with command line arguments (p. 117):
    >
    > while (--argc > 0 && (*++argv)[0] == '-')
    > while (c = *++argv[0])
    > switch (c) {
    > case 'x':
    > except = 1;
    > break;
    > case 'n':
    > number = 1;
    > break;
    > default:
    > printf("find: illegal option %c\n", c);
    > argc = 0;
    > found = -1;
    > break;
    > }
    >
    > But this solution raised some criticism:
    >
    > "The sample program increments argv[0]. Although argv is
    > modifiable, and argv[0][0] is modifiable (if argv[0] is
    > not a null pointer), argv[0] is not modifiable. (At least,
    > not always.)"
    >
    > (Peter Seebacher, http://www.plethora.net/~seebs/c/knr.html)
    >
    > "p.117 (§5.10): In the find example, the program increments
    > argv[0]. This is not specifically forbidden, but not
    > specifically allowed either."
    >
    > (Source:
    > Errata for The C Programming Language, Second Edition
    > http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html)


    The criticisms are incorrect. The standard is poorly worded (and for
    that reason, the issue has come up multiple times), but both the
    intent and the literal wording are that there are no prohibitions
    against modifying argv[0].

    There are arguably stylistic problems, though, so you could use
    something like

    if (argc != 0)
    {
    char **argptr;
    for (argptr = argv + 1; *argptr != NULL; argptr++)
    {
    char *arg = *argptr;
    if (arg[0] != '-')
    break;
    /* ... */
    }
    }

    which not only avoids the unclarity of modifying argv[0], but is also
    easier to comprehend.
     
    =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=, Apr 21, 2007
    #3
  4. Gregor H.

    Guest

    On Apr 21, 10:52 am, "Malcolm McLean" <>
    wrote:
    > "Gregor H." <nomail@invalid> wrote in message


    (Why did you start a new thread to reply to this question?)

    > news:...
    >
    > > In K&R (2nd edition) the authors published the following code for
    > > dealing with command line arguments (p. 117):

    >
    > > while (--argc > 0 && (*++argv)[0] == '-')
    > > while (c = *++argv[0])
    > > switch (c) {
    > > case 'x':
    > > except = 1;
    > > break;
    > > case 'n':
    > > number = 1;
    > > break;
    > > default:
    > > printf("find: illegal option %c\n", c);
    > > argc = 0;
    > > found = -1;
    > > break;
    > > }

    >
    > > But this solution raised some criticism:

    >
    > > "The sample program incrementsargv[0]. Althoughargvis
    > > modifiable, andargv[0][0] is modifiable (ifargv[0] is
    > > not a null pointer),argv[0] is not modifiable. (At least,
    > > not always.)"

    >
    > > (Peter Seebacher,http://www.plethora.net/~seebs/c/knr.html)

    >
    > > "p.117 (§5.10): In the find example, the program increments
    > >argv[0]. This is not specifically forbidden, but not
    > > specifically allowed either."

    >
    > > (Source:
    > > Errata for The C Programming Language, Second Edition
    > >http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html)

    >
    > > Now my question is: would the following (slight modification of the
    > > original code) be a reasonable (or at least correct) solution?:

    >
    > > while (--argc > 0 && (*++argv)[0] == '-') {

    >
    > This line is virtually unreadable. I know K and R used the same construct.
    > Things have moved on.


    Say what? It's terse, clear, and correct - what more can you ask for
    in a line of code?

    > > char *arg = *argv;
    > > while (c = *++arg)

    >
    > However this is the way round.argvcontains a list of strings. Nothing
    > conceptually difficult about that, but you can make it look difficult
    > because strigns are not atomic objects in C. It is a bad idea to modify the
    > strings in place, though I think they are writeable for historical reasons,
    > and it is a bad idea and may even be illegal to modify the pointers in theargvarray.
    > However if you take copies then you can do what you want with the copy,
    > naturally.
    > --
    > Free games and programming goodies.http://www.personal.leeds.ac.uk/~bgy1mm
     
    , Apr 21, 2007
    #4
  5. Gregor H.

    Gregor H. Guest

    On 21 Apr 2007 11:43:00 -0700, wrote:

    >>>
    >>> while (--argc > 0 && (*++argv)[0] == '-') { ... }
    >>>

    >> This line is virtually unreadable. I know K and R used the same construct.
    >> Things have moved on.
    >>

    > Say what? It's terse, clear, and correct - what more can you ask for
    > in a line of code?
    >

    Agree with you. But maybe he would prefer the variant

    while (--argc > 0 && **++argv == '-') { ... }

    This way we do not mix pointer notation with index notation. Maybe
    this is a "better" solution. Actually, I use _this variant_ in my
    improved code. So *my* version actually is:

    while (--argc > 0 && **++argv == '-') {
    char *arg = *argv;
    while (c = *++arg)
    switch (c) {
    case 'x':
    except = 1;
    break;
    case 'n':
    number = 1;
    break;
    default:
    printf("find: illegal option %c\n", c);
    ...
    break;
    }
    }


    G.

    --

    E-mail: info<at>simple-line<Punkt>de
     
    Gregor H., Apr 21, 2007
    #5
  6. Gregor H.

    Guest

    On Apr 21, 11:07 pm, Gregor H. <nomail@invalid> wrote:
    > On 21 Apr 2007 11:43:00 -0700, wrote:
    >
    >
    >
    > >>> while (--argc > 0 && (*++argv)[0] == '-') { ... }

    >
    > >> This line is virtually unreadable. I know K and R used the same construct.
    > >> Things have moved on.

    >
    > > Say what? It's terse, clear, and correct - what more can you ask for
    > > in a line of code?

    >
    > Agree with you. But maybe he would prefer the variant
    >
    > while (--argc > 0 && **++argv == '-') { ... }
    >
    > This way we do not mix pointer notation with index notation. Maybe
    > this is a "better" solution.


    Good point - you save a few characters doing it this way too :)

    >Actually, I use _this variant_ in my
    > improved code. So *my* version actually is:
    >
    > while (--argc > 0 && **++argv == '-') {
    > char *arg = *argv;
    > while (c = *++arg)
    > switch (c) {
    > case 'x':
    > except = 1;
    > break;
    > case 'n':
    > number = 1;
    > break;
    > default:
    > printf("find: illegal option %c\n", c);
    > ...
    > break;
    > }
    >
    > }
    >
    > G.
    >
    > --
    >
    > E-mail: info<at>simple-line<Punkt>de
     
    , Apr 22, 2007
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. hal styli
    Replies:
    6
    Views:
    409
  2. Replies:
    4
    Views:
    1,767
    Terry Hancock
    Apr 23, 2005
  3. News
    Replies:
    8
    Views:
    339
    James Kanze
    Sep 17, 2007
  4. Replies:
    6
    Views:
    142
  5. miracle_ks
    Replies:
    2
    Views:
    116
    Joe Smith
    Sep 27, 2004
Loading...

Share This Page