Understanding char **argv

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • kevin.eugene08@googlemail.com

    Understanding char **argv

    Hello all,

    Forgive the somewhat simple question I am sure this will be, but I am
    having some problem understanding what: char **argv looks like. For
    instance, i know through trial and error that if I do this:

    #include <stdio.h>

    int main(int argc, char *argv[])
    {
    int l;
    for( l=0; l<argc; l++ )
    {
    printf("Pointer : %p\tValue: %s\n", argv++, *argv);
    }

    return 0;
    }

    And i invoke the above as:

    ../foo one two three

    Then I will see:


    0x10202 foo
    0x10204 one
    0x10208 two
    ox1020c three

    Listed, but I would have expected to have needed to write:

    *(*(argv))

    So as to dereference what the pointer that *argv pointed to. Or have
    I missed the point?

    Thanks.

    Kevin
  • Richard Heathfield

    #2
    Re: Understanding char **argv

    kevin.eugene08@ googlemail.com said:
    Hello all,
    >
    Forgive the somewhat simple question I am sure this will be, but I am
    having some problem understanding what: char **argv looks like.
    argv is a pointer to the first element in an array of pointers to char,
    where each pointer in the array points to the first character in a string.
    For
    instance, i know through trial and error that if I do this:
    >
    #include <stdio.h>
    >
    int main(int argc, char *argv[])
    {
    int l;
    for( l=0; l<argc; l++ )
    {
    printf("Pointer : %p\tValue: %s\n", argv++, *argv);
    Replace that line with these two:

    printf("Pointer : %p\tValue: %s\n", (void *)argv, *argv);
    ++argv;

    <snip>
    Listed, but I would have expected to have needed to write:
    >
    *(*(argv))
    That's equivalent to **argv, and each iteration through the loop would give
    you the first character of the relevant string for that iteration:

    printf("Pointer : %p\tValue: %s\tFirst: %c\n",
    (void *)argv,
    *argv,
    **argv);
    ++argv;

    --
    Richard Heathfield <http://www.cpax.org.uk >
    Email: -http://www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999

    Comment

    • Eric Sosman

      #3
      Re: Understanding char **argv

      kevin.eugene08@ googlemail.com wrote:
      Hello all,
      >
      Forgive the somewhat simple question I am sure this will be, but I am
      having some problem understanding what: char **argv looks like. For
      instance, i know through trial and error that if I do this:
      >
      #include <stdio.h>
      >
      int main(int argc, char *argv[])
      {
      int l;
      for( l=0; l<argc; l++ )
      {
      printf("Pointer : %p\tValue: %s\n", argv++, *argv);
      }
      >
      return 0;
      }
      >
      And i invoke the above as:
      >
      ./foo one two three
      >
      Then I will see:
      >
      >
      0x10202 foo
      0x10204 one
      0x10208 two
      ox1020c three
      >
      Listed, but I would have expected to have needed to write:
      >
      *(*(argv))
      >
      So as to dereference what the pointer that *argv pointed to. Or have
      I missed the point?
      Peel the onion one layer at a time.

      `argv' is a pointer to a pointer to a char, which I'll
      write as "pointer to [pointer to char]" for emphasis.

      Applying `*' to a pointer accesses the thing the pointer
      points to. So `*argv' is a "[pointer to char]", the thing
      that `argv' itself points at.

      Now we apply `*' again, this time to the "[pointer to
      char]" we got from the first step. `**argv' (which is the
      same a `*(*argv))') is therefore a char, the first char of
      one of the argument strings.

      Another thing you can do to gain facility in understanding
      multiple levels of pointers is to draw a picture:

      char** char*'s char's

      argv ---argv[0] ---{ 'f', 'o', 'o', '\0' }
      argv[1] ---{ 'o', 'n', 'e', '\0' }
      argv[2] ---{ 't', 'w', 'o', '\0' }
      argv[3] ---{ 't', 'h', 'r', 'e', 'e', '\0' }
      argv[4] == NULL

      --
      Eric Sosman
      esosman@ieee-dot-org.invalid

      Comment

      • Joe Wright

        #4
        Re: Understanding char **argv

        kevin.eugene08@ googlemail.com wrote:
        Hello all,
        >
        Forgive the somewhat simple question I am sure this will be, but I am
        having some problem understanding what: char **argv looks like. For
        instance, i know through trial and error that if I do this:
        >
        #include <stdio.h>
        >
        int main(int argc, char *argv[])
        {
        int l;
        for( l=0; l<argc; l++ )
        {
        printf("Pointer : %p\tValue: %s\n", argv++, *argv);
        }
        >
        return 0;
        }
        >
        And i invoke the above as:
        >
        ./foo one two three
        >
        Then I will see:
        >
        >
        0x10202 foo
        0x10204 one
        0x10208 two
        ox1020c three
        >
        Listed, but I would have expected to have needed to write:
        >
        *(*(argv))
        >
        So as to dereference what the pointer that *argv pointed to. Or have
        I missed the point?
        Maybe two points.

        1. The parens are not needed. 'char **argv' is what it is, a pointer to
        a pointer to char.

        2. In your printf statement above you have both argv++ and *argv.
        Because we have no way to know which expression might be evaluated
        first, this is classic Undefined Behavior.

        #include <stdio.h>

        int main(int argc, char **argv)
        {
        int l;
        for (l = 0; l < argc; l++) {
        printf("Pointer : %p\tValue: %s\n", argv, *argv);
        argv++;
        }
        return 0;
        }

        ...is the way I would do it.
        --
        Joe Wright
        "Everything should be made as simple as possible, but not simpler."
        --- Albert Einstein ---

        Comment

        • kevin.eugene08@googlemail.com

          #5
          Re: Understanding char **argv

          Eric --

          On 5 Jul, 22:34, Eric Sosman <esos...@ieee-dot-org.invalidwrot e:
          char** char*'s char's
          >
          argv ---argv[0] ---{ 'f', 'o', 'o', '\0' }
          argv[1] ---{ 'o', 'n', 'e', '\0' }
          argv[2] ---{ 't', 'w', 'o', '\0' }
          argv[3] ---{ 't', 'h', 'r', 'e', 'e', '\0' }
          argv[4] == NULL
          If *only* one of the books I've been reading had this in it, I
          wouldn't be as confused -- thank you very much for that, and to the
          others in this thread who've replied.

          I suppose understand conceptually how type_t **foo works -- i do have
          to ask *why* the command-line options to a program is in the form:

          char **foo

          As opposed to a singular array of chars, i,e,:

          char foo[SOME_MAX_VALUE]

          My guess is: char **foo defers the decision to decide how big the
          array might be at runtime, but I could be wrong.

          Thanks once again for everyone's patience -- I know this is heavy
          going.

          Kevin

          Comment

          • Ben Bacarisse

            #6
            Re: Understanding char **argv

            "kevin.eugene08 @googlemail.com " <kevin.eugene08 @googlemail.com >
            writes:

            <snip>
            I suppose understand conceptually how type_t **foo works -- i do have
            to ask *why* the command-line options to a program is in the form:
            >
            char **foo
            >
            As opposed to a singular array of chars, i,e,:
            >
            char foo[SOME_MAX_VALUE]
            >
            My guess is: char **foo defers the decision to decide how big the
            array might be at runtime, but I could be wrong.
            I doubt it. The best argument is that it is the "right thing to do".
            Imagine your version. Every program would have to decide itself how
            to parse the command into parts. A program that operates on files can
            just run through the elements of argv doing its job on each one. If
            it got one long string, how does it decide what is a file name?

            --
            Ben.

            Comment

            • viza

              #7
              Re: Understanding char **argv

              On Sat, 05 Jul 2008 15:20:11 -0700, kevin.eugene08@ googlemail.com wrote:
              I suppose understand conceptually how type_t **foo works -- i do have to
              ask *why* the command-line options to a program is in the form:
              >
              char **foo
              >
              As opposed to a singular array of chars, i,e,:
              >
              char foo[SOME_MAX_VALUE]
              >
              My guess is: char **foo defers the decision to decide how big the array
              might be at runtime, but I could be wrong.
              That is two separate questions.

              q1) why is it char* and not char[SOME_MAX_VALUE] ?

              a1) It allows implementors to only use the minimum required or to use
              some maximum value if they prefer. The downside is that the user
              programmer cannot rely on being able to write past the end of the string,
              but that's not a problem because he can define his own MAX_VALUE and
              create his own automatic array if he needs it.

              q2) Why is it char** and not char* ?

              a2) Because that would greatly limit the power of shells, and it would
              require every application to perform its own command line interpreting
              (eg: working out that 'some string' is one argument without the quotes).

              As an aside, on many implementations there is no specific limit on the
              length of any one argument, but the total of all of them is limited.
              Here IIRC that limit is 32kiB.

              HTH
              viza

              Comment

              • kevin.eugene08@googlemail.com

                #8
                Re: Understanding char **argv

                On 5 Jul, 23:32, Ben Bacarisse <ben.use...@bsb .me.ukwrote:
                I doubt it. The best argument is that it is the "right thing to do".
                Imagine your version. Every program would have to decide itself how
                to parse the command into parts. A program that operates on files can
                just run through the elements of argv doing its job on each one. If
                it got one long string, how does it decide what is a file name?
                But if it were just an array holding type_t:

                type_t foo[BAR];

                Then BAR could still be evaluated at run-time -- much like argc is to
                main() surely? So again: Why the need for multiple indirection -- I
                am not saying you're wrong, I am just curious why we have it for
                command-line options in this case, and perhaps where other use of:
                type_t **foo come into play.

                Thanks!

                Kevin

                Comment

                • badc0de4@gmail.com

                  #9
                  Re: Understanding char **argv

                  kevin.eugene08@ googlemail.com wrote:
                  So again: Why the need for multiple indirection
                  [...] I am just curious why we have it for
                  command-line options in this case [...]
                  Because there is no "string" type in C.
                  If C had a string type (which I'll call 'tstring'),
                  main could probably be declared as

                  int main(int argc, tstring argv[])

                  where argv is an array of tstring.

                  But ... strings in C are represented by char *.

                  =============
                  #include <stdio.h>
                  typedef char * tstring;
                  int main(int argc, tstring argv[]) {
                  int n;
                  for (n=0; n<argc; n++) {
                  printf("arg %d is \"%s\".\n", n, argv[n]);
                  }
                  return 0;
                  }

                  Comment

                  • Richard Heathfield

                    #10
                    Re: Understanding char **argv

                    badc0de4@gmail. com said:
                    kevin.eugene08@ googlemail.com wrote:
                    >So again: Why the need for multiple indirection
                    >[...] I am just curious why we have it for
                    >command-line options in this case [...]
                    >
                    Because there is no "string" type in C.
                    If C had a string type (which I'll call 'tstring'),
                    main could probably be declared as
                    >
                    int main(int argc, tstring argv[])
                    So far, so good.
                    >
                    where argv is an array of tstring.
                    No, it would be a pointer to the first element in such an array.
                    >
                    But ... strings in C are represented by char *.
                    No, they are represented by a contiguous sequence of characters terminated
                    by the first null character. They can be pointed to by char *, in the
                    sense that a char * can point at their first member.

                    --
                    Richard Heathfield <http://www.cpax.org.uk >
                    Email: -http://www. +rjh@
                    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
                    "Usenet is a strange place" - dmr 29 July 1999

                    Comment

                    • Keith Thompson

                      #11
                      Re: Understanding char **argv

                      "kevin.eugene08 @googlemail.com " <kevin.eugene08 @googlemail.com writes:
                      Forgive the somewhat simple question I am sure this will be, but I am
                      having some problem understanding what: char **argv looks like. For
                      instance, i know through trial and error that if I do this:
                      >
                      #include <stdio.h>
                      >
                      int main(int argc, char *argv[])
                      {
                      int l;
                      for( l=0; l<argc; l++ )
                      {
                      printf("Pointer : %p\tValue: %s\n", argv++, *argv);
                      }
                      >
                      return 0;
                      }
                      >
                      And i invoke the above as:
                      >
                      ./foo one two three
                      >
                      Then I will see:
                      >
                      >
                      0x10202 foo
                      0x10204 one
                      0x10208 two
                      ox1020c three
                      >
                      Listed, but I would have expected to have needed to write:
                      >
                      *(*(argv))
                      >
                      So as to dereference what the pointer that *argv pointed to. Or have
                      I missed the point?
                      argv is of type char**, so *argv is of type char*.

                      printf() with the "%s" format expects an argument of type char*,
                      which must point to the first character of a string. printf itself
                      will dereference this char* pointer to extract and print the
                      characters of the string.

                      Incidentally, "%p" is the correct format for printing a pointer
                      value, but it expects an argument of type void*. If you want to
                      print a pointer of some other type, you should cast it to void*.

                      Finally, some style points (oh, here goes Keith with his "style
                      points" again).

                      "l" isn't a great name for a variable; it looks too much like the
                      digit 1 (and can be indistinguishab le in some fonts).

                      Some would argue that modifying a function argument is poor style.
                      I don't agree, but modifying argv while leaving argc alone is odd.
                      An idiom I've seen for traversing command-line arguments is to
                      increment argv while decrementing argc. Or you can just use an
                      integer to loop through the arguments, leaving argc and argv alone.
                      (If you're concerned that indexing will be slower than stepping
                      through with a pointer, don't be; the difference will be minimal,
                      and a good optimizing compiler will likely generate the same code
                      either way.)

                      Of course none of this is a big deal for a program this small, but
                      small programs are where you should start to develop good habits.

                      --
                      Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                      Nokia
                      "We must do something. This is something. Therefore, we must do this."
                      -- Antony Jay and Jonathan Lynn, "Yes Minister"

                      Comment

                      • Joe Wright

                        #12
                        Re: Understanding char **argv

                        Richard Heathfield wrote:
                        badc0de4@gmail. com said:
                        >
                        >kevin.eugene08@ googlemail.com wrote:
                        >>So again: Why the need for multiple indirection
                        >>[...] I am just curious why we have it for
                        >>command-line options in this case [...]
                        >Because there is no "string" type in C.
                        >If C had a string type (which I'll call 'tstring'),
                        >main could probably be declared as
                        >>
                        > int main(int argc, tstring argv[])
                        >
                        So far, so good.
                        >
                        >where argv is an array of tstring.
                        >
                        No, it would be a pointer to the first element in such an array.
                        >
                        >But ... strings in C are represented by char *.
                        >
                        No, they are represented by a contiguous sequence of characters terminated
                        by the first null character. They can be pointed to by char *, in the
                        sense that a char * can point at their first member.
                        >
                        No, a string IS a contiguous sequence (an array) of characters
                        terminated by (and including) the first null character. A string is
                        referred to by the address (of type char*) of its first member.

                        --
                        Joe Wright
                        "Everything should be made as simple as possible, but not simpler."
                        --- Albert Einstein ---

                        Comment

                        • CBFalconer

                          #13
                          Re: Understanding char **argv

                          "kevin.eugene08 @googlemail.com " wrote:
                          >
                          .... snip ...
                          >
                          I suppose understand conceptually how type_t **foo works -- i do have
                          to ask *why* the command-line options to a program is in the form:
                          >
                          char **foo
                          >
                          As opposed to a singular array of chars, i,e,:
                          >
                          char foo[SOME_MAX_VALUE]
                          Because those don't have the same meaning. However you can freely
                          replace "char **argv" with "char *argv[]" in the parameter list.
                          Note the added '*'.

                          --
                          [mail]: Chuck F (cbfalconer at maineline dot net)
                          [page]: <http://cbfalconer.home .att.net>
                          Try the download section.


                          Comment

                          Working...