La estructura en la matriz generalmente es mejor; deberías usar eso a menos que tengas una razón para usar el otro formulario.
Desde el punto de vista de corrección de código, debe manejar malloc() falla. Si tiene 1000 malloc() s en un bucle, es más probable que cometa un error de programación en su código de manejo de errores. De manera similar, si su estructura de datos es más compleja, es más probable que filtre algo. Entonces, el único malloc() es más fácil.
Desde un punto de vista de la velocidad de asignación, malloc() obviamente toma tiempo para ejecutarse, por lo que un solo malloc() generalmente será más rápido.
Desde el punto de vista del tamaño de la memoria, malloc() suele tener cierta sobrecarga en cada asignación. Y, obviamente, los indicadores son un costo adicional. Por lo tanto, si asigna 1000 estructuras de 16 bytes, puede terminar con 16 bytes por estructura en la sobrecarga de Malloc y un puntero de 8 bytes, con un total de 40.016 bytes. Hacer una sola asignación solo tomará 8.016 bytes.
Desde un punto de vista de velocidad de acceso, es probable que la matriz sea más rápida, especialmente si las estructuras son pequeñas o si lee las estructuras en orden. Si las estructuras son pequeñas, varias de ellas encajarán en una sola línea de caché para que puedan leerse/escribirse como un grupo. Si lee las estructuras en orden, es probable que la CPU detecte el acceso lineal a la gran matriz y la cargue previamente en la memoria caché. Si usa un conjunto de punteros y asignaciones separadas, entonces el diseño de la memoria es más aleatorio y ninguna de estas optimizaciones funcionará. Además, como está accediendo a más datos (los punteros), su algoritmo se eliminará de la memoria caché de datos antes.
Desde el punto de vista de la fragmentación de memoria, depende. Si tiene estructuras lo suficientemente grandes (una fracción significativa de su RAM total), entonces puede entrar en una situación en la que no hay suficiente memoria libre contigua para asignar una única matriz grande, pero hay suficiente para asignar una matriz de punteros y el estructuras individuales (Por ejemplo, si tienes un programa de 32 bits en un sistema operativo que te limita a 2 GB de memoria, y tu asignador de memoria ha asignado algo más a la mitad de la memoria, entonces no puedes hacer una única asignación de 1,5 GB, pero podrías hacerlo 15 asignaciones de 100MB). Este tipo de escenario es raro, porque las personas generalmente no trabajan con datos tan grandes.