Style vs function? in arrays

M

mdh

I guess pointers just take time!!!

This is exercise 5-13, peripherally.


The function accepts a command line argument of -n.

So, given

int main ( int argc, char *argv[])

.......


if ( argc == 2 && (*++argv)[0]=='-')
n= atoi(argv[0]+1);

......

May I ask this?


1) in a given function ( ? scope ?) once one has advanced the pointer
( to argv..in this case) is that where the pointer will remain
pointing at? and until when?

2) In the case above, where Tondo and Gimpel use indices as well as
pointer incrementation, is there a good reason for this or is this
just a matter of style? ie why not use ( instead of (*++argv)[0])
argv[1][0]? ( if that indeed is equivalent?)

3) I have until now not seen the construct "atoi(argv[0]+1". Does this
mean get the pointer at index argv[1] ( which I believe is an pointer
to char array, then add 1 to that pointer? ( not argv)?

Thanks in advance.
 
R

Richard Heathfield

mdh said:
The function accepts a command line argument of -n.

So, given

int main ( int argc, char *argv[])
......
if ( argc == 2 && (*++argv)[0]=='-')
n= atoi(argv[0]+1);

In general, avoid atoi, which is not robust in the face of ill-formed
input. strtol is far superior.
1) in a given function ( ? scope ?) once one has advanced the pointer
( to argv..in this case) is that where the pointer will remain
pointing at? and until when?

argv has type char **, and it's initially pointing at the first element
in an array of char *, each of which contains the address of the first
character in a string. When you do ++argv, you're moving it to point to
the /second/ element in that array of char *.

Let's look at it in terms of what might actually happen inside a real
(and very very simple) machine. Somewhere in memory, you have something
like this:

+--------+--------+--------+
addr + 0x3000 | 0x3002 | 0x3004 |
+--------+--------+--------+
val + 0x4200 | 0x4280 | 0x0000 |
+--------+--------+--------+

and, elsewhere, you have something like:

+--------+--------+--------+--------+--------+--------+
addr + 0x4200 | 0x4201 | 0x4202 | 0x4203 | 0x4204 | 0x4205 |
+--------+--------+--------+--------+--------+--------+
val + 'E' | 'x' | '5' | '1' | '3' | '\0' |
+--------+--------+--------+--------+--------+--------+

and...

+--------+--------+--------+
addr + 0x4280 | 0x4281 | 0x4282 |
+--------+--------+--------+
val + '-' | '6' | '\0' |
+--------+--------+--------+


argv starts off with the value 0x3000 (in our example, anyway!). As you
can see from the first array diagram, *argv is 0x4200. But then we add
1 to argv using ++argv. This means "move argv along by one OBJECT". So
we do that, moving argv's value from 0x3000 to the next slot in the
array, which is 0x3002. Then we deref it, which gives us the value
0x4280 (the value stored at address 0x3002). Finally, we come to [0].

Bear in mind that A and *(A + I) are synonymous in C. So what we have
finally arrived at is *(0x4280 + 0) which is *0x4280 which is... check
the diagram... '-'.

So (*++argv)[0] ends up meaning this: "move argv along a bit, then find
the first character in what has now become the string that argv is
pointing to".

Better:

myarg = argv[1];

if(myarg[0] == '-')
{
n = strtol(myarg + 1, &e, 10);

where e is a char *. (Look up strtol.)
2) In the case above, where Tondo and Gimpel use indices as well as
pointer incrementation, is there a good reason for this or is this
just a matter of style? ie why not use ( instead of (*++argv)[0])
argv[1][0]? ( if that indeed is equivalent?)

It's nearly equivalent. ++argv has the side effect of adding 1 to argv,
which affects all the indices in subsequent lines.

I can't comment on T&G's code, since I have never seen it.
3) I have until now not seen the construct "atoi(argv[0]+1". Does this
mean get the pointer at index argv[1] ( which I believe is an pointer
to char array, then add 1 to that pointer? ( not argv)?

To understand atoi(argv[0] + 1), start with argv[0] and be sure you know
what it points to. If argv's value has been modified prior to this
point, that is important (and, in your example, it has been).

Once you know that it points to the first character in a string, you can
see that argv[0] + 1 will point to the second character in that string.
So for example, if argv[0] --> "-42987", then argv[0] + 1 --> "42987",
argv[0] + 2 --> "2987", argv[0] + 3 --> "987", etc.
 
M

mdh

Richard,
Thank you for that very detailed response.
In general, avoid atoi,........... strtol is far superior.

Thanks...I don't think that has been covered yet...but will look it
up.

To understand atoi(argv[0] + 1), start with argv[0] and be sure you know
what it points to. If argv's value has been modified prior to this
point, that is important (and, in your example, it has been).

I see.....
Once you know that it points to the first character in a string, you can
see that argv[0] + 1 will point to the second character in that string.
So for example, if argv[0] --> "-42987", then argv[0] + 1 --> "42987",
argv[0] + 2 --> "2987", argv[0] + 3 --> "987", etc.


Richard, if argv ( as described above) now points to the first element
of argv and argv[0] points to the first character of the first
element, then why does argv[1] not point to the second character of
the first element of argv? ( I know it does not, as I have tried this
and it crashes)
 
R

Richard Heathfield

mdh said:

Richard, if argv ( as described above) now points to the first element
of argv

Stop right there. You are overloading the meaning of argv, using it to
mean both the second parameter of main *and* the array to whose first
element that parameter initially points. Normally that doesn't matter
very much, because it's pretty obvious what you mean, but when you
modify the parameter (++argv or whatever) it no longer points to that
first element of the array of command line strings, and so it's unwise
to confuse the issue by using the same name to refer to both.
and argv[0] points to the first character of the first
element,
Right.

then why does argv[1] not point to the second character of
the first element of argv?

Because it points to the first character of the second element. But
argv[0] + 1 does point to the second character of the first element.

X[Y] + Z does not mean the same as X[Y + Z].
 
M

mdh

mdh said:

<snip>
then why does argv[1] not point to the second character of
the first element of argv?

Because it points to the first character of the second element. But
argv[0] + 1 does point to the second character of the first element.


Ok...I think I get it. Argv always refers to the array of char *.
It's the [whatever] that points to the actual character.

Thank you Richard....I am sure that soon this will feel like "old
hat". Right now...the hat seems to fit awkwardly. :)
 
R

Richard Heathfield

mdh said:

Ok...I think I get it. Argv always refers to the array of char *.
It's the [whatever] that points to the actual character.

If in doubt, never use more than one * or [] (except in declarations!).
So for example, to do what you originally wanted, don't write this:

int n = strtol((*++argv)[0], &e, 10);

Write this instead:

char *firstrealarg = argv[1];
int n = strtol(firstrealarg, &e, 10);

Isn't that a lot easier to understand?
Thank you Richard....I am sure that soon this will feel like "old
hat". Right now...the hat seems to fit awkwardly. :)

The trick is to start with the bowl shape on the top. Get that right
first, and fit a brim later on.
 
M

mdh

If in doubt, never use more than one * or [] (except in declarations!).
Write this instead:

char *firstrealarg = argv[1];
int n = strtol(firstrealarg, &e, 10);

Isn't that a lot easier to understand?

Point taken...thanks.


Time to get some sleep.... :)

thanks for your help. ( as always)
 

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
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top