Google Groups Home
Help | Sign in
Understanding char **argv
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  13 messages - Collapse all
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
kevin.eugene08@googlemail .com  
View profile
 More options Jul 5, 4:02 pm
Newsgroups: comp.lang.c
From: "kevin.eugen...@googlemail.com" <kevin.eugen...@googlemail.com>
Date: Sat, 5 Jul 2008 13:02:27 -0700 (PDT)
Local: Sat, Jul 5 2008 4:02 pm
Subject: 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


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Richard Heathfield  
View profile
 More options Jul 5, 5:27 pm
Newsgroups: comp.lang.c
From: Richard Heathfield <r...@see.sig.invalid>
Date: Sat, 05 Jul 2008 21:27:02 +0000
Local: Sat, Jul 5 2008 5:27 pm
Subject: Re: Understanding char **argv
kevin.eugen...@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


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Sosman  
View profile
 More options Jul 5, 5:34 pm
Newsgroups: comp.lang.c
From: Eric Sosman <esos...@ieee-dot-org.invalid>
Date: Sat, 05 Jul 2008 17:34:34 -0400
Local: Sat, Jul 5 2008 5:34 pm
Subject: Re: Understanding char **argv

     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
esos...@ieee-dot-org.invalid


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Joe Wright  
View profile
 More options Jul 5, 6:10 pm
Newsgroups: comp.lang.c
From: Joe Wright <joewwri...@comcast.net>
Date: Sat, 05 Jul 2008 18:10:33 -0400
Local: Sat, Jul 5 2008 6:10 pm
Subject: Re: Understanding char **argv

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 ---

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
kevin.eugene08@googlemail .com  
View profile
 More options Jul 5, 6:20 pm
Newsgroups: comp.lang.c
From: "kevin.eugen...@googlemail.com" <kevin.eugen...@googlemail.com>
Date: Sat, 5 Jul 2008 15:20:11 -0700 (PDT)
Local: Sat, Jul 5 2008 6:20 pm
Subject: Re: Understanding char **argv
Eric --

On 5 Jul, 22:34, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:

>         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


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ben Bacarisse  
View profile
 More options Jul 5, 6:32 pm
Newsgroups: comp.lang.c
From: Ben Bacarisse <ben.use...@bsb.me.uk>
Date: Sat, 05 Jul 2008 23:32:50 +0100
Local: Sat, Jul 5 2008 6:32 pm
Subject: Re: Understanding char **argv
"kevin.eugen...@googlemail.com" <kevin.eugen...@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.


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
viza  
View profile
 More options Jul 5, 6:53 pm
Newsgroups: comp.lang.c
From: viza <tom.v...@gm-il.com.obviouschange.invalid>
Date: Sat, 05 Jul 2008 22:53:18 GMT
Local: Sat, Jul 5 2008 6:53 pm
Subject: Re: Understanding char **argv

On Sat, 05 Jul 2008 15:20:11 -0700, kevin.eugen...@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


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
kevin.eugene08@googlemail .com  
View profile
 More options Jul 5, 6:55 pm
Newsgroups: comp.lang.c
From: "kevin.eugen...@googlemail.com" <kevin.eugen...@googlemail.com>
Date: Sat, 5 Jul 2008 15:55:21 -0700 (PDT)
Local: Sat, Jul 5 2008 6:55 pm
Subject: Re: Understanding char **argv
On 5 Jul, 23:32, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:

> 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


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
badc0...@gmail.com  
View profile
 More options Jul 5, 7:36 pm
Newsgroups: comp.lang.c
From: badc0...@gmail.com
Date: Sat, 5 Jul 2008 16:36:11 -0700 (PDT)
Local: Sat, Jul 5 2008 7:36 pm
Subject: Re: Understanding char **argv

kevin.eugen...@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;


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Richard Heathfield  
View profile
 More options Jul 5, 8:04 pm
Newsgroups: comp.lang.c
From: Richard Heathfield <r...@see.sig.invalid>
Date: Sun, 06 Jul 2008 00:04:08 +0000
Local: Sat, Jul 5 2008 8:04 pm
Subject: Re: Understanding char **argv
badc0...@gmail.com said:

> kevin.eugen...@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


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Keith Thompson  
View profile
 More options Jul 5, 9:04 pm
Newsgroups: comp.lang.c
From: Keith Thompson <ks...@mib.org>
Date: Sat, 05 Jul 2008 18:04:09 -0700
Local: Sat, Jul 5 2008 9:04 pm
Subject: Re: Understanding char **argv

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 indistinguishable 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_Keith) ks...@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"


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Joe Wright  
View profile