C++ - char** argv vs char* argv[]


¿Cuál es la diferencia entre char** argv y char* argv[]? en int main(int argc, char** argv) y int main(int argc, char* argv[])?

¿Son lo mismo? Especialmente que la primera parte no tiene [].

Author: Nakilon, 2011-03-04

7 answers

Son totalmente equivalentes. char *argv[] debe leerse como una matriz de punteros a char y un argumento de matriz es degradado a un puntero, por lo que puntero a puntero a char, o char **.

Esto es lo mismo en C.

 47
Author: Fred Foo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:23

Son exactamente lo mismo.

La regla de oro de los arrays para recordar es:

"El nombre de una matriz es un puntero al primer elemento de la matriz."

Así que si declaras lo siguiente:

char text[] = "A string of characters.";

Entonces la variable "text" es un puntero al primer carácter en la matriz de caracteres que acaba de declarar. En otras palabras, "texto"es del tipo char *. Cuando accedes a un elemento de una matriz usando [index ], lo que estás realmente haciendo es agregar un desplazamiento de index al puntero al primer elemento de la matriz, y luego desreferenciar este nuevo puntero. Las siguientes dos líneas inicializarán ambas variables a 't':

char thirdChar = text[3];
char thirdChar2 = *(text+3);

Usar los corchetes es una conveniencia proporcionada por el lenguaje que hace que el código sea mucho más legible. Pero la forma en que esto funciona es muy importante cuando empiezas a pensar en cosas más complejas, como punteros a punteros. char** argv es lo mismo que char* argv[] porque en el segundo caso "el nombre del array es un puntero al primer elemento del array".

A partir de esto también debería ser capaz de ver por qué es que los índices de matriz comienzan desde 0. El puntero al primer elemento es el nombre de la variable de la matriz (regla de oro de nuevo) más un desplazamiento de... nada!

He tenido debates con un amigo mío sobre cuál es mejor usar aquí. Con la notación char* argv[] puede ser más claro para el lector que esto es de hecho una " matriz de punteros a caracteres "a diferencia de la notación char** argv que se puede leer como un "puntero a un puntero a un carácter". Mi opinión es que esta última notación no transmite tanta información al lector.

Es bueno saber que son exactamente iguales, pero para la legibilidad creo que si la intención es una matriz de punteros, entonces la notación char* argv[] transmite esto mucho más claramente.

 18
Author: James Bedford,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-26 20:12:06

Para todos los propósitos prácticos, son lo mismo. Esto se debe al manejo de C/C++de matrices pasadas como argumentos, donde una matriz decae a un puntero.

 3
Author: Erik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-04 09:47:01

Para la primera parte de la pregunta:

  • char * * argv: puntero a un puntero a un char
  • char * argv []: puntero a una matriz

Así que la pregunta es si un puntero a un tipo C y una matriz C [] son las mismas cosas. No son en absoluto en general, PERO son equivalentes cuando se usan en firmas.

En otras palabras, no hay diferencia en su ejemplo, pero es importante tener en cuenta la diferencia entre puntero y matriz de lo contrario.

 3
Author: David Cournapeau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-02 18:24:53

La forma de corchetes solo es útil en declaraciones como:

char *a[] = {"foo", "bar", "baz"};
printf("%d\n", sizeof a / sizeof *a);
// prints 3

Porque conoce en tiempo de compilación el tamaño del array. Cuando pasas una forma de corchete como parámetro a una función (main o alguna otra), el compilador no tiene idea de cuál sería el tamaño de la matriz en tiempo de ejecución, por lo que es exactamente el mismo que char **a. Prefiero char **argv ya que es más claro que sizeof no funcionaría como lo haría en el formulario de declaración de declaración.

 2
Author: Jake,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-29 15:59:41

Hay una diferencia entre TYPE * NAME y TYPE NAME[] tanto en C como en C++. En C++ ambos tipos no son intercambiables. Por ejemplo, la siguiente función es ilegal (obtendrá un error) en C++, pero legal en C (obtendrá una advertencia):

int some (int *a[3]) // a is array of dimension 3 of pointers to int
{
    return sizeof a;
}

int main ()
{
    int x[3][3];
    std::cout << some(x)<< std::endl;
    return 0;
}

Para hacerlo legal, simplemente cambie la firma a int some (int (*a)[3]) (puntero a matriz de 3 ints) o int some (int a[][3]). El número en los últimos corchetes debe ser igual al de un argumento. Convertir de matriz de matrices a una matriz de punteros es ilegal. Convertir de puntero a puntero a matriz de matrices es ilegal también. Pero la conversión de puntero a puntero a una matriz de punteros es legal!

Así que recuerde: Solo lo más cercano a la firma de tipo de desreferencia no importa, otros lo hacen (en el contexto de punteros y matrices, claro).

Consideremos que tenemos un como puntero a puntero a int:

int ** a;
&a     ->     a    ->    *a    ->    **a
(1)          (2)         (3)          (4)
  1. No puede cambiar este valor, el tipo es int ***. Puede tomarse por función como int **b[] o int ***b. Lo mejor es int *** const b.
  2. El tipo es int **. Puede tomarse por función como int *b[] o int ** b. Los corchetes del array declaratin pueden estar vacíos o contener cualquier número.
  3. El tipo es int *. Puede tomarse por función como int b[] o int * b o incluso void * b
  4. debe tomarse como parámetro int. No quiero caer en detalles, como la llamada implícita del constructor.

Respondiendo su pregunta: el tipo real de argumentos en la función principal es char ** argv, por lo que puede ser fácilmente representado como char *argv[] (pero no como char (*argv)[]). También argv el nombre de la función principal puede ser con seguridad cambiado. Puede comprobarlo fácilmente: std::cout << typeid(argv).name(); (PPc = puntero a p. a char)

Por cierto: hay una característica genial, pasando matrices como referencias:

void somef(int (&arr)[3])
{
    printf("%i", (sizeof arr)/(sizeof(int))); // will print 3!
}

Por otra parte puntero a cualquier cosa puede ser aceptado implícitamente (convertido) por la función como puntero vacío. Pero solo un solo puntero (no puntero a puntero, etc.).

Lectura adicional:

  1. Bjarne Stroustrup, C++, capítulo 7.4
  2. C punteros FAQ
 -1
Author: yanpas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-02 18:39:38

Ambos son iguales para su uso, excepto por las siguientes diferencias sutiles:

  • Sizeof dará resultados diferentes para ambos
  • También el segundo no puede ser reasignado a una nueva área de memoria ya que es un array
  • Con el segundo puede usar solo aquellos índices que son valido. No está especificado por C / C++ si intenta usar un índice de matriz más allá longitud de la matriz. Sin embargo, con char * * puede utilizar cualquier índice de 0 a...
  • La segunda forma solo se puede usar como formal parámetros de una función. While first puede usarse incluso para declarar variables dentro de una pila.
 -2
Author: user5858,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-10 04:42:55