¿Cómo creo una matriz de cadenas en C?

Resuelto asked hace 15 años • 0 respuestas

Estoy intentando crear una matriz de cadenas en C. Si uso este código:

char (*a[2])[14];
a[0]="blah";
a[1]="hmm";

gcc me da "advertencia: asignación de un tipo de puntero incompatible". ¿Cuál es la forma correcta de hacer esto?

Editar: Tengo curiosidad por saber por qué esto debería dar una advertencia al compilador, ya que si lo hago printf(a[1]);, imprime correctamente "hmm".

 avatar Jul 07 '09 01:07
Aceptado

Si no desea cambiar las cadenas, simplemente puede hacer

const char *a[2];
a[0] = "blah";
a[1] = "hmm";

Cuando lo hagas así, asignarás una matriz de dos punteros a const char. Estos punteros luego se establecerán en las direcciones de las cadenas estáticas "blah"y "hmm".

Si desea poder cambiar el contenido real de la cadena, debe hacer algo como

char a[2][14];
strcpy(a[0], "blah");
strcpy(a[1], "hmm");

Esto asignará dos matrices consecutivas de 14 chars cada una, después de lo cual se copiará en ellas el contenido de las cadenas estáticas.

Mikael Auno avatar Jul 06 '2009 18:07 Mikael Auno

Hay varias formas de crear una matriz de cadenas en C. Si todas las cadenas van a tener la misma longitud (o al menos tendrán la misma longitud máxima), simplemente declara una matriz bidimensional de caracteres y asigna según sea necesario:

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1];
...
strcpy(strs[0], aString); // where aString is either an array or pointer to char
strcpy(strs[1], "foo");

También puede agregar una lista de inicializadores:

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1] = {"foo", "bar", "bletch", ...};

Esto supone que el tamaño y la cantidad de cadenas en el inicializador coinciden con las dimensiones de su matriz. En este caso, el contenido de cada cadena literal (que es en sí misma una matriz de caracteres terminada en cero) se copia en la memoria asignada a cadenas. El problema de este enfoque es la posibilidad de fragmentación interna; si tiene 99 cadenas de 5 caracteres o menos, pero 1 cadena de 20 caracteres, 99 cadenas tendrán al menos 15 caracteres no utilizados; eso es una pérdida de espacio.

En lugar de utilizar una matriz 2D de caracteres, puede almacenar una matriz 1D de punteros a caracteres:

char *strs[NUMBER_OF_STRINGS];

Tenga en cuenta que en este caso, sólo ha asignado memoria para guardar los punteros a las cadenas; la memoria para las cadenas mismas debe asignarse en otro lugar (ya sea como matrices estáticas o mediante el uso malloc()o calloc()). Puede utilizar la lista de inicializadores como en el ejemplo anterior:

char *strs[NUMBER_OF_STRINGS] = {"foo", "bar", "bletch", ...};

En lugar de copiar el contenido de las constantes de cadena, simplemente almacena los punteros a ellas. Tenga en cuenta que es posible que no se pueda escribir en las constantes de cadena; puedes reasignar el puntero, así:

strs[i] = "bar";
strs[i] = "foo"; 

Pero es posible que no puedas cambiar el contenido de la cadena; es decir,

strs[i] = "bar";
strcpy(strs[i], "foo");

puede que no esté permitido.

Puede utilizar malloc()para asignar dinámicamente el búfer para cada cadena y copiarlo en ese búfer:

strs[i] = malloc(strlen("foo") + 1);
strcpy(strs[i], "foo");

POR CIERTO,

char (*a[2])[14];

Declara a como una matriz de punteros de 2 elementos a matrices de caracteres de 14 elementos.

John Bode avatar Jul 07 '2009 21:07 John Bode

¡Ack! Cadenas constantes:

const char *strings[] = {"one","two","three"};

Si recuerdo correctamente.

Ah, y quieres usar strcpy para la asignación, no el operador =. strcpy_s es más seguro, pero no está ni en los estándares C89 ni en C99.

char arr[MAX_NUMBER_STRINGS][MAX_STRING_SIZE]; 
strcpy(arr[0], "blah");

Actualización: Thomas dice strlcpyque es el camino a seguir.[no portátil]

mpen avatar Jul 06 '2009 18:07 mpen

Aquí tienes algunas de tus opciones:

char a1[][14] = { "blah", "hmm" };
char* a2[] = { "blah", "hmm" };
char (*a3[])[] = { &"blah", &"hmm" };  // only since you brought up the syntax -

printf(a1[0]); // prints blah
printf(a2[0]); // prints blah
printf(*a3[0]); // prints blah

La ventaja a2es que luego puedes hacer lo siguiente con cadenas literales

a2[0] = "hmm";
a2[1] = "blah";

Y para a3usted puede hacer lo siguiente:

a3[0] = &"hmm";
a3[1] = &"blah";

Porque a1tendrá que usar strcpy()(mejor aún strncpy()) incluso cuando asigne cadenas literales. La razón es que a2y a3son matrices de punteros y usted puede hacer que sus elementos (es decir, punteros) apunten a cualquier almacenamiento, mientras que a1es una matriz de 'matriz de caracteres' y, por lo tanto, cada elemento es una matriz que "posee" su propio almacenamiento ( lo que significa que se destruye cuando sale del alcance): solo puedes copiar cosas en su almacenamiento.

Esto también nos lleva a la desventaja de usar a2y a3, dado que apuntan al almacenamiento estático (donde se almacenan los literales de cadena) cuyo contenido no se puede cambiar de manera confiable (es decir, comportamiento indefinido), si desea asignar literales que no son de cadena al elementos de a2o a3- primero tendrá que asignar dinámicamente suficiente memoria y luego hacer que sus elementos apunten a esta memoria, y luego copiar los caracteres en ella - y luego debe asegurarse de desasignar la memoria cuando haya terminado.

Bah, ya extraño C++;)

PD: Avíseme si necesita ejemplos.

Faisal Vali avatar Jul 06 '2009 19:07 Faisal Vali