Cree dinámicamente una matriz de cadenas con malloc

4 minutos de lectura

Estoy tratando de crear una matriz de cadenas en C usando malloc. El número de cadenas que contendrá la matriz puede cambiar en tiempo de ejecución, pero la longitud de las cadenas siempre será consistente.

Intenté esto (ver más abajo), pero tengo problemas, ¡cualquier consejo en la dirección correcta será muy apreciado!

#define ID_LEN 5
char *orderedIds;
int i;
int variableNumberOfElements = 5; /* Hard coded here */

orderedIds = malloc(variableNumberOfElements * (ID_LEN + 1));

En última instancia, quiero poder usar la matriz para hacer esto:

strcpy(orderedIds[0], string1);
strcpy(orderedIds[1], string2);
/* etc */

  • Tenga en cuenta que no debe usar intestá aquí. a) Está firmado (y dudo que desee una cadena de longitud -5), yb) no se garantiza que tenga el tamaño adecuado para contener los valores que necesita que contenga. Utilizar el size_t type para almacenar índices de matrices y tamaños de objetos. Ese es el tipo de argumento para malloc.

    – Chris Lutz

    9 de mayo de 2011 a las 11:16

  • @Chris: dicho esto, se garantiza que será lo suficientemente grande para 5.

    –Steve Jessop

    9 de mayo de 2011 a las 11:37

avatar de usuario
MByD

Debe asignar una matriz de punteros char y luego, para cada puntero, asigne suficiente memoria para la cadena:

char **orderedIds;

orderedIds = malloc(variableNumberOfElements * sizeof(char*));
for (int i = 0; i < variableNumberOfElements; i++)
    orderedIds[i] = malloc((ID_LEN+1) * sizeof(char)); // yeah, I know sizeof(char) is 1, but to make it clear...

Me parece una buena manera. Aunque realiza muchos mallocs, claramente asigna memoria para una cadena específica y puede liberar un bloque de memoria sin liberar toda la “matriz de cadenas”

  • ¿Tiene que usar otro bucle for para liberar la memoria que ha asignado?

    – Minh Tran

    14 de septiembre de 2015 a las 2:30

  • Sí, usar bucles para realizar la misma operación varias veces es una práctica buena y común, que se convierte en una necesidad cuando se realiza un número variable de veces. (Pero cada bucle for también puede implementarse como un bucle while).

    – MByD

    14/09/2015 a las 21:14

char **orderIds;

orderIds = malloc(variableNumberOfElements * sizeof(char*));

for(int i = 0; i < variableNumberOfElements; i++) {
  orderIds[i] = malloc((ID_LEN + 1) * sizeof(char));
  strcpy(orderIds[i], your_string[i]);
}

avatar de usuario
Oliver Charlesworth

Dado que todas sus cadenas tienen una longitud fija (¿presumiblemente en tiempo de compilación?), Puede hacer lo siguiente:

char (*orderedIds)[ID_LEN+1]
    = malloc(variableNumberOfElements * sizeof(*orderedIds));

// Clear-up
free(orderedIds);

Una solución más engorrosa, pero más general, es asignar una matriz de punteros y pseudoinicializarlos para que apunten a elementos de una matriz de respaldo sin formato:

char *raw = malloc(variableNumberOfElements * (ID_LEN + 1));
char **orderedIds = malloc(sizeof(*orderedIds) * variableNumberOfElements);

// Set each pointer to the start of its corresponding section of the raw buffer.
for (i = 0; i < variableNumberOfElements; i++)
{
    orderedIds[i] = &raw[i * (ID_LEN+1)];
}

...

// Clear-up pointer array
free(orderedIds);
// Clear-up raw array
free(raw);

  • ¿Por qué asignarías todo a orderedIds[0]?

    – MByD

    9 de mayo de 2011 a las 11:06

  • @Chris: Sí, de hecho. De hecho, ¡acabo de hacer ese cambio!

    –Oliver Charlesworth

    9 de mayo de 2011 a las 11:08

  • @Oli – Entonces lo vi. Es posible que desee agregar una nota sobre cómo se liberaría correctamente el primero, ya que es bastante poco intuitivo.

    – Chris Lutz

    9 de mayo de 2011 a las 11:10

  • ¿Qué devuelve la llamada “malloc” de la primera opción? ¿Qué tipo de puntero? Si trato de lanzarlo como algo (char*, char**…) obtengo errores

    – Dori

    4 de junio de 2013 a las 6:58

  • No se considera C idiomático emitir el valor de retorno de malloc. Además, estás declarando orderedIds como una matriz en lugar de un puntero, lo que significa que no puede asignarle. Además, eres mallocing un bloque grande para todos los datos de carácter, luego convertirlo en un char ** que es muy diferente.

    – Chris Lutz

    9 de mayo de 2011 a las 11:12

  • Cambiado *orderedIds[] a **orderedIds, aunque creo que el compilador es lo mismo, y el primero es más legible. Con respecto al “bloque grande”, esto es exactamente lo que es. Las matrices son solo bloques de memoria.

    – romano

    9 de mayo de 2011 a las 11:25

  • Te equivocas. Si lo asigna como char[][ID_LEN + 1] no puedes tratarlo como un char **. char ** espera que tenga punteros a datos que están almacenados en otro lugar. No se almacena en la memoria dinámica de la misma manera que una matriz bidimensional se almacena en la pila.

    – Chris Lutz

    9 de mayo de 2011 a las 11:27

¿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