¿Qué significa int argc, char * argv []?

508

En muchos IDE y compiladores de C ++, cuando genera la función principal para usted, se ve así:

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

Cuando codifico C ++ sin un IDE, solo con un compilador de línea de comandos, escribo:

int main()

sin ningún parámetro ¿Qué significa esto y es vital para mi programa?

Greg Treleaven
fuente
47
Si su programa va a ignorar los argumentos de la línea de comando, entonces lo que escriba está bien. Si su programa necesita procesar argumentos de línea de comando, entonces el IDE lo está haciendo bien.
Jonathan Leffler
30
Un consejo para los hackers: intenta declarar int main(int argc, char* argv[], char* envp[])e imprimir el último argumento. ;)
ulidtko
77
@ulidtko no es bueno que estés enseñando a los novatos a introducir vulnerabilidad en sus programas;)
Gab 是 好人
13
@Gab, ¿cómo la impresión simple de variables de entorno genera vulnerabilidad? Simplemente no pase las cadenas contaminadas al pie de la letra a las system()llamadas, consultas de base de datos, etc. Como es habitual con la entrada del usuario.
ulidtko
2
@ulidtko Interesante ... ¿Puede explicar por qué no tiene que pasar cadenas contaminadas, consultas de db, etc. mientras usa el char **envpargumento?
Maestro James

Respuestas:

651

argvy argccómo se pasan los argumentos de la línea de comandos main()en C y C ++.

argcserá el número de cadenas señaladas por argv. Esto (en la práctica) será 1 más el número de argumentos, ya que prácticamente todas las implementaciones antepondrán el nombre del programa a la matriz.

Las variables se denominan argc( recuento de argumentos ) y argv( vector de argumentos ) por convención, pero se les puede dar cualquier identificador válido: int main(int num_args, char** arg_strings)es igualmente válido.

También se pueden omitir por completo, produciendo int main(), si no tiene la intención de procesar argumentos de línea de comandos.

Prueba el siguiente programa:

#include <iostream>

int main(int argc, char** argv) {
    std::cout << "Have " << argc << " arguments:" << std::endl;
    for (int i = 0; i < argc; ++i) {
        std::cout << argv[i] << std::endl;
    }
}

Ejecutarlo con ./test a1 b2 c3generará

Have 4 arguments:
./test
a1
b2
c3
meagar
fuente
8
argcpuede ser 0, en cuyo caso argvpuede ser NULL. Está permitido por el estándar AFAIK. Nunca he oído hablar de un sistema que haga esto en la práctica, pero ciertamente podría existir y no violaría ningún estándar.
Chuck
77
@Chuck: Dado que "El valor de argv[argc]será 0" (C ++ 03 §3.6.1 / 2), argvno puede ser nulo.
James McNellis
20
@Chuck: C (al menos C99) tiene el mismo requisito.
James McNellis
2
Pensé que debería agregar, esto es lo mismo en la mayoría de los sistemas, aunque a veces se abstraen. Por ejemplo, en Pascal / Delphi / Lazarus, obtienes; ParamStr y ParamCount (si la memoria me sirve bien). Mi punto es que cuando (si alguna vez) escribe aplicaciones nativas en otros idiomas / versiones, hay una buena posibilidad de que lo anterior esté definido para que lo use, y funcionan perfectamente de la misma manera (lista de conteo / cadena) en todos los sistemas que admiten ellos.
Christian
8
@ EmilVikström No, ese es un error grave que probablemente resulte en una falla predeterminada. *NULLdefinitivamente no es igual a NULL.
Meagar
52

argces la cantidad de argumentos que se pasan a su programa desde la línea de comandos y argves la matriz de argumentos.

Puede recorrer los argumentos sabiendo el número de ellos como:

for(int i = 0; i < argc; i++)
{
    // argv[i] is the argument at index i
}
John Boker
fuente
19

Supongamos que ejecuta su programa de esta manera (usando la shsintaxis):

myprog arg1 arg2 'arg 3'

Si declaró su main como int main(int argc, char *argv[]), entonces (en la mayoría de los entornos), main()se le llamará como si así:

p = { "myprog", "arg1", "arg2", "arg 3", NULL };
exit(main(4, p));

Sin embargo, si declaró su principal como int main(), se llamará algo así como

exit(main());

y no se pasan los argumentos.

Dos cosas adicionales a tener en cuenta:

  1. Estas son las dos únicas firmas obligatorias estándar para main. Si una plataforma en particular acepta argumentos adicionales o un tipo de retorno diferente, entonces esa es una extensión y no se debe confiar en un programa portátil.
  2. *argv[]y **argvson exactamente equivalentes, por lo que puedes escribir int main(int argc, char *argv[])como int main(int argc, char **argv).
Toby Speight
fuente
2
Si estamos siendo técnicos, basic.start.main/2permite explícitamente versiones adicionales definidas por la implementación de main(), siempre que la implementación proporcione las dos versiones predefinidas. Entonces, no son exactamente no conformes. El más común es envp, que es tan bien conocido tanto en C y C ++ que es literalmente la primera entrada en la sección J.5 (Extensiones comunes) de la norma C .
Justin Time - Restablece a Mónica el
1
Gracias por la buena pedantería @Justin. Respuesta actualizada para ser más correcta.
Toby Speight el
No tengo idea: le sugiero que cree un ejemplo reproducible mínimo y lo pregunte (suponiendo que el proceso no sea suficiente para ayudarlo a responderlo usted mismo).
Toby Speight
9

Los parámetros para mainrepresentar los parámetros de línea de comando proporcionados al programa cuando se inició. El argcparámetro representa el número de argumentos de la línea de comandos y char *argv[]es una matriz de cadenas (punteros de caracteres) que representan los argumentos individuales proporcionados en la línea de comandos.

BlueMonkMN
fuente
2
Argv [] siempre tiene argv [arg] como puntero nulo. y Argv [0] es siempre el (ruta completa) / ejecutableName como una cadena terminada en
nulo
3
@ user3629249: No necesariamente; argv[0]es lo que el programa que lanzó el programa C le dio argv[0]. En el caso de Bash, a menudo es (tal vez siempre) la ruta del ejecutable, pero Bash no es el único programa que ejecuta otros programas. Es permissisble, aunque excéntrico, a utilizar: char *args[] = { "cat", "/dev/null", "/etc/passwd", 0 }; execv("/bin/ls", args);. En muchos sistemas, el valor visto por el programa como argv[0]será cat, aunque el ejecutable sea /bin/ls.
Jonathan Leffler
7

La mainfunción puede tener dos parámetros, argcy argv. argces un intparámetro entero ( ), y es el número de argumentos pasados ​​al programa.

El nombre del programa es siempre el primer argumento, por lo que habrá al menos un argumento para un programa y el valor mínimo de argcserá uno. Pero si un programa tiene dos argumentos, el valor de argcserá tres.

El parámetro argvapunta a una matriz de cadenas y se denomina vector de argumento . Es una matriz de cadena unidimensional de argumentos de función.

Moshtagh
fuente
5
int main();

Esta es una simple declaración. No puede tomar ningún argumento de línea de comando.

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

Esta declaración se usa cuando su programa debe tomar argumentos de línea de comandos. Cuando se ejecuta así:

myprogram arg1 arg2 arg3

argc, o Argument Count, se establecerá en 4 (cuatro argumentos), y argv, o Argument Vectors, se completará con punteros de cadena a "myprogram", "arg1", "arg2" y "arg3". ¡La invocación del programa ( myprogram) está incluida en los argumentos!

Alternativamente, podría usar:

int main(int argc, char** argv);

Esto también es válido.

Hay otro parámetro que puede agregar:

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

El envpparámetro también contiene variables de entorno. Cada entrada sigue este formato:

VARIABLENAME=VariableValue

Me gusta esto:

SHELL=/bin/bash    

La lista de variables de entorno está terminada en nulo.

IMPORTANTE: ¡NO use ninguno argvo envpvalores directamente en las llamadas a system()! Este es un gran agujero de seguridad, ya que los usuarios malintencionados pueden configurar variables de entorno para los comandos de la línea de comandos y (potencialmente) causar daños masivos. En general, simplemente no lo use system(). Casi siempre hay una mejor solución implementada a través de las bibliotecas C.

adrian
fuente
3

El primer parámetro es el número de argumentos proporcionados y el segundo parámetro es una lista de cadenas que representan esos argumentos.

Nick Gerakines
fuente
77
la primera entrada en argv [0] es el nombre del programa, no un argumento
user3629249
@ user3629249 Nombre del programa con la ruta del programa. ;)
Maestro James
1

Ambos

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

son definiciones legales del punto de entrada para un programa C o C ++. Las preguntas frecuentes de Stroustrup: Estilo y técnica de C ++ detallan algunas de las variaciones que son posibles o legales para su función principal.

Chris Becke
fuente
44
Es posible que desee anular ... int main()==> int main(void)... para compatibilidad y legibilidad. No sé si todas las versiones anteriores de C permiten que las funciones nulas tengan una lista de parámetros vacía en la declaración.
dylnmc
1
@dylnmc esto no proporciona ninguna ganancia de legibilidad, y es exactamente equivalente en todas las versiones de C ++. Solo en C esto tiene una diferencia, pero solo en las declaraciones, no en la definición.
Ruslan
@Ruslan Lo siento, publiqué esto cuando estaba aprendiendo C, y podría haber leído que en las primeras versiones de C voides obligatorio. No me cites sobre eso, y ahora sé que es un comentario un poco tonto. Sin embargo, no puede doler.
dylnmc
¿Qué pasa si argc <3 devuelve un error? ¿Qué podría salir mal?
AVI