Weird pointer arithmetic on argv - How can it work??

J

jerry

I need to modify the code of a command-line tool. The source code
starts out like this:

int main(int argc, char *argv[])
{
int ch, A, B ;

while ((ch = getopt(argc, argv, "AB")) != -1)
switch (ch) {
case 'A':
A = 1;
break;
case 'B':
B = 1 ;
break;
}
argc -= optind;
argv += optind;

What in heaven's name is that last line doing? It seems to be doing
pointer arithmetic, incrementing argv by the current value of optind
(which is an integer, the "ind"ex of the current argument). But I
thought you can only do pointer arithmetic when the size of each array
element is a constant known by the compiler, and of course a char* does
not have a constant size. How can this even compile? (It does).

Furthermore, I want to rewrite this with argv assigned in the code
instead of being a command-line argument, but when I write:

char* argv[4] ;
argv += optind ;

the compiler complains, rightfully so I would say, "incompatible types
in assignment" on that second line. Why does it work for them, but it
doesn't work for me?

Thanks!

Jerry Krinock
 
G

Gordon Burditt

I need to modify the code of a command-line tool. The source code
starts out like this:

int main(int argc, char *argv[])
char *argv[] in this context (function parameter) really means the
same as char **argv.
{
int ch, A, B ;

while ((ch = getopt(argc, argv, "AB")) != -1)
switch (ch) {
case 'A':
A = 1;
break;
case 'B':
B = 1 ;
break;
}
argc -= optind;
argv += optind;

What in heaven's name is that last line doing? It seems to be doing
pointer arithmetic, incrementing argv by the current value of optind
(which is an integer, the "ind"ex of the current argument).

Correct. It's skipping over the flag arguments. argv is a
pointer-to-pointer, and you're advancing it by optind pointers.
Knowing the way the non-standard function getopt() is supposed to
work, it won't go out of range of the array.

But I
thought you can only do pointer arithmetic when the size of each array
element is a constant known by the compiler, and of course a char* does
not have a constant size.

Of course a (char *) *DOES* have a constant size (it's often 32 or
64 bits). argv is an array of pointers, and char * pointers have
a constant size. The strings pointed at do not have constant size,
but they aren't *in* the array.
How can this even compile? (It does).
Furthermore, I want to rewrite this with argv assigned in the code
instead of being a command-line argument, but when I write:

char* argv[4] ;
argv += optind ;

argv has char ** type. You can only declare it as char *argv[] if
it's a function parameter, which is equivalent to char ** (when it's
a function parameter). You cannot increment an array name, which is
a problem if you declare it as char *argv[] as a local variable.

char *av[4];
char **argv = av;
/* somehow you initialize av here */
argv += optind;
 
K

Keith Thompson

I need to modify the code of a command-line tool. The source code
starts out like this:

int main(int argc, char *argv[])
{
int ch, A, B ;

while ((ch = getopt(argc, argv, "AB")) != -1)
switch (ch) {
case 'A':
A = 1;
break;
case 'B':
B = 1 ;
break;
}
argc -= optind;
argv += optind;

What in heaven's name is that last line doing? It seems to be doing
pointer arithmetic, incrementing argv by the current value of optind
(which is an integer, the "ind"ex of the current argument). But I
thought you can only do pointer arithmetic when the size of each array
element is a constant known by the compiler, and of course a char* does
not have a constant size. How can this even compile? (It does).

A char* does have a constant size.

C doesn't actually have array parameters. In a parameter list,
"char *argv[]" really means "char **argv", so argv is a pointer to
pointer to char. (Presumably the pointer-to-char that argv points
to is the first element of an array of pointers-to-char.)

C allows the "[]" syntax here for "convenience, but in my opinion it
just causes confusion.

I suggest reading section 6 of the comp.lang.c FAQ,
Furthermore, I want to rewrite this with argv assigned in the code
instead of being a command-line argument, but when I write:

char* argv[4] ;
argv += optind ;

the compiler complains, rightfully so I would say, "incompatible types
in assignment" on that second line. Why does it work for them, but it
doesn't work for me?

Outside a parameter list, "char *argv[4];" really does declare an
array, not a pointer.
 
C

Chris Johnson

I need to modify the code of a command-line tool. The source code
starts out like this:

int main(int argc, char *argv[])
{
int ch, A, B ;

while ((ch = getopt(argc, argv, "AB")) != -1)
switch (ch) {
case 'A':
A = 1;
break;
case 'B':
B = 1 ;
break;
}
argc -= optind;
argv += optind;

What in heaven's name is that last line doing? It seems to be doing
pointer arithmetic, incrementing argv by the current value of optind
(which is an integer, the "ind"ex of the current argument).

That's precisely what it's doing.
But I
thought you can only do pointer arithmetic when the size of each array
element is a constant known by the compiler, and of course a char* does
not have a constant size.

On my machine, sizeof(char *) returns 4. I suspect a 64 bit machine
would return 8. While the array it points to may not have a size known
at compile time, the pointer itself has a set size. Remember: a
pointer's just an integer.
How can this even compile? (It does).

Furthermore, I want to rewrite this with argv assigned in the code
instead of being a command-line argument, but when I write:

Well that's what argv is. I suggest you pick a new name for your array,
for the sake of anybody that might maintain your program.
char* argv[4] ;
argv += optind ;

the compiler complains, rightfully so I would say, "incompatible types
in assignment" on that second line. Why does it work for them, but it
doesn't work for me?

char* argv[4] is an array of four char pointers. You can't perform
pointer arithmetic on an array.
As to why it works for them, it's because as a parameter, a[] is
equivalent to *a. (You can't pass actual arrays in C.)
 
C

CBFalconer

I need to modify the code of a command-line tool. The source code
starts out like this:

int main(int argc, char *argv[])
{
int ch, A, B ;

while ((ch = getopt(argc, argv, "AB")) != -1)
switch (ch) {
case 'A':
A = 1;
break;
case 'B':
B = 1 ;
break;
}
argc -= optind;
argv += optind;

What in heaven's name is that last line doing? ...

Who knows. getopt() is not a standard C routine, and you failed to
show its source. You also failed to declare optind.
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top