Understanding char **argv

K

kevin.eugene08

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
 
K

kevin.eugene08

Eric --

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
 
B

Ben Bacarisse

"(e-mail address removed)" <[email protected]>
writes:

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

viza

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
 
K

kevin.eugene08

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
 
B

badc0de4

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;
}
 
K

Keith Thompson

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

CBFalconer

.... 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 '*'.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top