¿Cómo creo una matriz de cadenas en C?
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".
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 char
s cada una, después de lo cual se copiará en ellas el contenido de las cadenas estáticas.
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.
¡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 [no portátil]strlcpy
que es el camino a seguir.
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 a2
es que luego puedes hacer lo siguiente con cadenas literales
a2[0] = "hmm";
a2[1] = "blah";
Y para a3
usted puede hacer lo siguiente:
a3[0] = &"hmm";
a3[1] = &"blah";
Porque a1
tendrá que usar strcpy()
(mejor aún strncpy()
) incluso cuando asigne cadenas literales. La razón es que a2
y a3
son matrices de punteros y usted puede hacer que sus elementos (es decir, punteros) apunten a cualquier almacenamiento, mientras que a1
es 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 a2
y 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 a2
o 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.