According to the standard (C17 draft, 7.22.3.2), calloc
void *calloc(size_t nmemb, size_t size);
"allocates space for an array of nmemb objects, each of whose size is size" (and initializes all bits to zero).
For calloced arrays of T, I have only ever seen code like this:
T *p = calloc(nmemb, sizeof(T));
T *p;
p = calloc(nmemb, sizeof(T));
But given that calloc allocates space for an array, the following ought to be fine too:
T (*arrp)[nmemb] = calloc(nmemb, sizeof(T));
T (*arrp)[nmemb];
arrp = calloc(nmemb, sizeof(T));
(Here, the top version of each pair is technically speaking an initialization, not an assignment.)
What type can the result of calloc be assigned to, a pointer to an array (type T (*)[]), a pointer to the type contained within the array (type T *), or either?
The following code
#include <stdio.h>
#include <stdlib.h>
int main(void) {
    int (*iarrp)[5];
    int *ip;
    float (*farrp)[1];
    float *fp;
    int i;
    iarrp = calloc(5, sizeof(int));
    for (i = 0; i < 5; ++i)
        (*iarrp)[i] = -i;
    ip = calloc(5, sizeof(int));
    for (i = 0; i < 5; ++i)
        ip[i] = i + 100;
    for (i = 0; i < 5; ++i)
        printf("%d: %d, %d\n", i, (*iarrp)[i], ip[i]);
    farrp = calloc(1, sizeof(float));
    (*farrp)[0] = 5.5;
    fp = calloc(1, sizeof(float));
    *fp = 6.6;
    printf("%.2f, %.2f\n", (*farrp)[0], *fp);
    free(iarrp);
    free(ip);
    free(farrp);
    free(fp);
    return 0;
}
compiles just fine for me with GCC (gcc -std=c17 -pedantic -Wall -Wextra) and with MSVC (cl /std:c17 /Wall), with the output being as expected:
0: 0, 100
1: -1, 101
2: -2, 102
3: -3, 103
4: -4, 104
5.50, 6.60
The background for asking this question is this: For an array arr of type T[], of the following three expressions
- arr; type:- T[](before decay),- T *(after decay)
- &arr[0]; type:- T *- this is what arrdecays to
 
- this is what 
- &arr; type:- T (*)[]- the &prevents decay
 
- the 
the first two produce the same value. The third expression can theoretically have a value different from the first two expressions, though I understand that this is uncommon. The standard only guarantees that (void *)&arr == (void *)&arr[0] holds true.
 
     
    