En primer lugar, K & R tienen una errata en este fragmento en particular:
117 (§5.10): En el encontrar ejemplo, los incrementos de programa argv[0]
. Esto no está específicamente prohibido, pero tampoco está específicamente permitido.
Ahora para la explicación.
Digamos que su programa se llama prog
, y lo ejecuta con: prog -ab -c Hello World
. Desea poder analizar los argumentos para decir que se especificaron las opciones a
, b
y c
, y Hello
y World
son los argumentos que no tienen opción.
argv
es del tipo char **
— recuerde que un parámetro de matriz en una función es lo mismo que un puntero. En la invocación del programa, las cosas se ven de esta manera:
+---+ +---+---+---+---+---+
argv ---------->| 0 |-------->| p | r | o | g | 0 |
+---+ +---+---+---+---+---+
| 1 |-------->| - | a | b | 0 |
+---+ +---+---+---+---+
| 2 |-------->| - | c | 0 |
+---+ +---+---+---+---+---+---+
| 3 |-------->| H | e | l | l | o | 0 |
+---+ +---+---+---+---+---+---+
| 4 |-------->| W | o | r | l | d | 0 |
+---+ +---+---+---+---+---+---+
| 5 |-------->NULL
+---+
Aquí, argc
es 5, y es argv[argc]
NULL
. Al principio, argv[0]
es un char *
que contiene la cadena "prog"
.
En (*++argv)[0]
, debido a los paréntesis, argv
se incrementa primero y luego se quita la referencia. El efecto del incremento es mover esa flecha argv ---------->
"un bloque hacia abajo", para apuntar al 1
. El efecto de la desreferenciación es obtener un puntero al primer argumento de línea de comando, -ab
. Finalmente, tomamos el primer caracter ([0]
en (*++argv)[0]
) de esta cadena, y lo probamos para ver si es '-'
, porque eso denota el inicio de una opción.
Para la segunda construcción, realmente queremos caminar por la cuerda apuntada por el puntero actual argv[0]
. Por lo tanto, tenemos que tratar argv[0]
como un puntero, ignorar su primer carácter (es decir '-'
como acabamos de prueba), y mirar a los otros personajes:
++(argv[0])
incrementará argv[0]
, para obtener un puntero a la primera no -
personaje, y quitarle la referencia nos dará el valor de ese personaje. Entonces obtenemos *++(argv[0])
.Pero como en C, []
se une más estrictamente que ++
, podemos deshacernos de los paréntesis y obtener nuestra expresión como *++argv[0]
. Queremos seguir procesando este personaje hasta que sea 0
(el último cuadro de caracteres en cada una de las filas de la imagen de arriba).
La expresión
asigna a c
el valor de la opción actual, y tiene el valor c
. while(c)
es una abreviatura de while(c != 0)
, por lo que la línea while(c = *++argv[0])
básicamente asigna el valor de la opción actual a c
y lo prueba para ver si hemos llegado al final del argumento actual de la línea de comandos.
Al final de este bucle, argv apuntará al primer argumento no es una opción:
+---+ +---+---+---+---+---+
| 0 |-------->| p | r | o | g | 0 |
+---+ +---+---+---+---+---+
| 1 |-------->| - | a | b | 0 |
+---+ +---+---+---+---+
| 2 |-------->| - | c | 0 |
+---+ +---+---+---+---+---+---+
argv ---------->| 3 |-------->| H | e | l | l | o | 0 |
+---+ +---+---+---+---+---+---+
| 4 |-------->| W | o | r | l | d | 0 |
+---+ +---+---+---+---+---+---+
| 5 |-------->NULL
+---+
¿Esto ayuda?
También estoy interesado en una cosa: while (c = * ++ argv [0]) esta expresión. ¿Significa esto realmente: while (c = * ++ argv [0]! = 0), quiero decir que * ++ argv [0] devuelve un puntero nulo a c si no ha encontrado un carácter? – Tool
sí - responde a continuación. –
Como mencioné en mi respuesta, vea la entrada de erratas de K & R en este código: http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html –