Vamos por partes.
Disclaimer ando algo oxidado de C, pero tengo que ponerme asi que me viene bien de ejercicio.
No hace falta castear el resultado de malloc a nada, un puntero de void es un tipo que es valido para todas las expresiones que aceptan un puntero, podríamos ponerlo como:
double *a = malloc(sizeof(double) * n * n/np);
double *b = malloc(sizeof(double) * n * n);
Cuidado con el n/np, en este caso no creo importe, pero ten en cuenta la precedencia de los operadores, sobretodo con divisiones y multiplicaciones juntas, si no estás seguro del orden de las operaciones usa parentesis para garantizar que se ejecutan en el orden que tu quieres.
a y b no son matrices, solo tienen una dimension, si tienen el tamaño de una matriz pero son solo arrays, puedes aceder a todas las posiciones si tienes cuidado con los indices, como por ejemplo:
/* Inicialización a 0 de toda la matriz b */
int i = 0, j = 0;
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
b[i + j] = 0;
}
}
No se si lo de meterlo en una dimension es intencional, pero por si acaso tienes algún problema con eso tenlo en cuenta. Si quisieras hacer matrices de verdad (array de arrays) la cosa es bastante distinta.
Finalmente para responder a tu pregunta:
/* matriz c que puede albergar a y b stackeadas horizontalmente */
double *c = malloc(sizeof(double) * n * (n + n/np));
Te recomiendo que consideres la primera dimension las filas y la segunda las columnas, a la hora de printear es la manera más "natural" de la que salen los arrays.