C diferencia entre *[] y **

8 minutos de lectura

avatar de usuario
usuario472875

Esta podría ser una pregunta un poco básica, pero ¿cuál es la diferencia entre escribir char * [] y char**? Por ejemplo, en main, puedo tener un char * argv[]. Alternativamente, puedo usar char ** argv. Supongo que tiene que haber algún tipo de diferencia entre las dos notaciones.

  • Todo es azúcar sintáctico.

    –Paul Tomblin

    17 de noviembre de 2010 a las 19:44

  • Claro, pero creo que hay una diferencia en el significado. Por ejemplo, puedo declarar char ** algo. pero no puedo declarar char * algo[].

    – usuario472875

    17 de noviembre de 2010 a las 19:46

  • Ciertamente NO es azúcar sintáctico, para comprender las diferencias sugiero el muy buen libro “Expert C Programming” de Peter van der Linden, tiene una sección completa sobre la diferencia entre los dos.

    – Steabert

    17 de noviembre de 2010 a las 20:11

  • Encontré una explicación similar en esta página: lysator.liu.se/c/c-faq/c-2.html

    – Steabert

    18 de noviembre de 2010 a las 6:34

Dadas las circunstancias, no hay diferencia en absoluto. Si intenta usar un tipo de matriz como parámetro de función, el compilador lo “ajustará” a un tipo de puntero en su lugar (es decir, T a[x] como parámetro de función medio exactamente lo mismo que: T *a).

En las circunstancias adecuadas (es decir, no como un parámetro de función), sin embargo, puede haber una diferencia entre usar notación de matriz y puntero. Uno común está en un extern declaración. Por ejemplo, supongamos que tenemos un archivo que contiene algo como:

char a[20];

y queremos que eso sea visible en otro archivo. Esto funcionará:

extern char a[];

pero esto no:

extern char *a;

Si lo convertimos en una matriz de punteros en su lugar:

char *a[20];

…lo mismo sigue siendo cierto: declarar una matriz externa funciona bien, pero declarar un puntero externo no:

extern char *a[]; // works

extern char **a;   // doesn't work

  • ¿Por qué esta diferencia en el extern ¿conducta?

    – Lazer

    18 de noviembre de 2010 a las 3:25

  • @Lazer: el ajuste de tipo ocurre cuando pasa un argumento a una función, pero aquí no estamos pasando un argumento a una función, por lo que no se realiza ningún ajuste de tipo.

    – Jerry Ataúd

    18 de noviembre de 2010 a las 4:39

  • Hay un caso de esquina para el reclamo en su primer párrafo. Si T es un tipo incompleto entonces T a[x] no está permitido como parámetro, pero T *a es.

    –MM

    9 de marzo de 2015 a las 13:03

avatar de usuario
steve jesop

Depende del contexto.

Como parámetro de función, significan lo mismo (para el compilador), pero al escribirlo char *argv[] podría ayudar a que sea obvio para los programadores que el char** que se pasa apunta al primer elemento de una matriz de char*.

Como declaración de variable, significan cosas diferentes. Uno es un puntero a un puntero, el otro es una matriz de punteros y la matriz tiene un tamaño no especificado. Vos tambien lata hacer:

char * foo[] = {0, 0, 0};

Y obtenga una matriz de 3 punteros nulos. Tres char*s es una cosa completamente diferente de un puntero a un char*.

  • Sí, eso es a lo que yo también me refería. Incluso en un parámetro de función, el decl expresa la semántica, ¿no es así? char* argv[] ?

    –Steve Townsend

    17 de noviembre de 2010 a las 19:54

  • Townsend: Sí, el [] form sugiere fuertemente que se pretende que se pase una matriz. No estoy de acuerdo, sin embargo, en que char** significa que es no destinado a ser utilizado como una matriz, ya que hay muchos programadores de C (incluido yo) que no pueden molestarse con él. char* generalmente no significa “solo un carácter”; se usa comúnmente para cadenas. no veo porque char** debe significar “solo uno char*“. Así que yo diría que char ** significa “verificar los documentos”, mientras que char *[] significa “verificar los documentos” 😉

    –Steve Jessop

    17 de noviembre de 2010 a las 20:04


  • Para char** Estoy de acuerdo en que es específico del contexto. Si ese es un parámetro de función, lo leo como “una cadena que la función puede cambiar”. Dicho esto, soy mayormente C++ en estos días, así que me remito a su experiencia (y los documentos, por supuesto).

    –Steve Townsend

    17 de noviembre de 2010 a las 20:07

  • @Steve: bueno, en estos días soy principalmente Python, al menos cuando me pagan, así que no estoy seguro de poder reclamar prioridad. Supongo que mi punto es simplemente el obvio de que adivinar es un negocio arriesgado.

    –Steve Jessop

    17 de noviembre de 2010 a las 20:11

Puedes usar cdecl.org para convertirlos al inglés:

  • char *argv[] = declarar argv como matriz de puntero a char

  • char **argv = declarar argv como puntero a puntero a char

Creo que esto es un poco más que azúcar sintáctico, también ofrece una forma de expresar información semántica sobre el contrato (voluntario) implícito en cada tipo de declaración.

Con char*[] usted está diciendo que esto está destinado a ser utilizado como una matriz.

Con char**está diciendo que PUEDE usar esto como una matriz, pero esa no es la forma en que debe usarse.

Como se mencionó en las otras respuestas, char*[] declara una matriz de punteros a char, char** declara un puntero a un puntero a char (que se puede usar como matriz).

Una diferencia es que la matriz es constante, mientras que el puntero no lo es.

Ejemplo:

int main()
{
    char** ppc = NULL;
    char* apc[] = {NULL};
    ppc++;
    apc++; /* this won't compile*/
    return 0;
}

  • En realidad, el puntero se puede declarar como constante y aún así no será lo mismo que una matriz. Sin embargo, puede ver la diferencia entre los dos a partir de los errores: Aumento a declarado como char * const a obtendrá un error de “incremento de valor de solo lectura”, mientras aumenta b declarado como char b[1] producirá un “valor l requerido como operando de incremento”.

    – Steabert

    18 de noviembre de 2010 a las 6:31

  • La matriz tampoco es constante. (De hecho, las matrices constantes son imposibles en C; las matrices declaradas const son en realidad matrices no constantes con const elementos). La razón apc++ no compila es porque el ++ El operador se define como solo aplicable a punteros y nocomplex tipos numéricos y las matrices no son punteros.

    –MM

    9 de marzo de 2015 a las 13:09


avatar de usuario
Juan Bode

Esta De Verdad depende del contexto donde ocurren las declaraciones.

Fuera de la definición de un parámetro de función, la declaración

T a[];

declara a como un desconocidomatriz de tamaño de T; el tipo de matriz es incompletoasí que a menos a es definido en otro lugar (ya sea en esta unidad de traducción o en otra unidad de traducción que se vincule), entonces no se le reserva almacenamiento (y usted probablemente obtiene un error de “referencia indefinida” si intenta vincular, aunque creo que el comportamiento predeterminado de gcc es definir la matriz con 1 elemento). No se puede utilizar como operando de la sizeof operador. Eso lata ser utilizado como un operando de la & operador.

Por ejemplo:

/** 
 * module1.c
 */
extern char *a[]; /* non-defining declaration of a */

void foo()
{
  size_t i = 0;
  for (i = 0; a[i] != NULL; i++)
    printf("a[%lu] = %s\n", (unsigned long) i, a[i++]);
}

module1.c utiliza un no definitorio declaración de a introducir el nombre para que pueda ser utilizado en la función foo, pero dado que no se especifica el tamaño, no se reserva ningún almacenamiento en esta unidad de traducción. Lo más importante es la expresión a no es un tipo de puntero; es un tipo de matriz incompleta. Se convertirá en un tipo de puntero en la llamada a printf por las reglas habituales.

/**
 * module2.c
 */
char *a[] = {"foo", "bar", "bletch", "blurga", NULL}; /* defining declaration of a */

int main(void)
{
  void foo();

  foo();
  return 0;
}

module2.c contiene un definiendo declaración para a (el tamaño de la matriz se calcula a partir de la cantidad de elementos en el inicializador), lo que hace que se asigne almacenamiento para la matriz.

Nota de estilo: nunca escriba código como este.

En el contexto de una declaración de parámetro de función, T a[] es sinónimo de T *a; en ambos casos, a es un tipo de puntero. Esto es solamente true en el contexto de una declaración de parámetro de función.

  • En realidad, el puntero se puede declarar como constante y aún así no será lo mismo que una matriz. Sin embargo, puede ver la diferencia entre los dos a partir de los errores: Aumento a declarado como char * const a obtendrá un error de “incremento de valor de solo lectura”, mientras aumenta b declarado como char b[1] producirá un “valor l requerido como operando de incremento”.

    – Steabert

    18 de noviembre de 2010 a las 6:31

  • La matriz tampoco es constante. (De hecho, las matrices constantes son imposibles en C; las matrices declaradas const son en realidad matrices no constantes con const elementos). La razón apc++ no compila es porque el ++ El operador se define como solo aplicable a punteros y nocomplex tipos numéricos y las matrices no son punteros.

    –MM

    9 de marzo de 2015 a las 13:09


avatar de usuario
slezica

Como dijo Paul en el comentario anterior, es azúcar sintáctico. Tanto char* como char[] son del mismo tipo de datos. En la memoria, ambos contendrán la dirección de un char.

La notación de matriz/índice es equivalente a la notación de puntero, tanto en la declaración como en el acceso, pero a veces es mucho más intuitiva. Si está creando una matriz de punteros char, es posible que desee escribirlo de una forma u otra para aclarar su intención.

Editar: no consideró el caso que Jerry mencionó en la otra respuesta. Mira eso.

  • No son del mismo tipo en general. char *[] simplemente se descompone a char ** en declaraciones de funciones, ya que no puede pasar una matriz real.

    – Mateo Flaschen

    17 de noviembre de 2010 a las 20:33


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad