You should modify the struct to add the number of courses present in the allocated structure:
typedef struct School {
    char *name;
    int ncourses;
    char *courses[]; //Flexible Array Member
} School;
Say you have 2 schools, one with 3 courses, one with 2.  You would allocate the structures this way:
School *mc = malloc(offsetof(struct School, courses) + 3 * sizeof(char *));
mc->name = strdup("Math College");
mc->ncourses = 3;
mc->courses[0] = strdup("Math 101");
mc->courses[1] = strdup("Math 102");
mc->courses[2] = strdup("Math 103");
School *ps = malloc(offsetof(struct School, courses) + 2 * sizeof(char *));
ps->name = strdup("Psycho School");
ps->ncourses = 2;
ps->courses[0] = strdup("Psycho 101");
ps->courses[1] = strdup("Unknown 404");
As you can see, elements of the variable array are accessed like any other array elements.  The malloc call allocates the appropriate size in bytes for the struct members and the array elements (here char * pointers), that are located at the end of the structure.
You could use a generic function to allocate and initialize such structures:
School create_school(const char *school_name, int ncourses, char *courses[]) {
    School *sp = malloc(offsetof(struct School, courses) + ncourses * sizeof(char *));
    sp->name = strdup(school_name);
    sp->ncourses = ncourses;
    for (int i = 0; i < ncourses; i++) {
        sp->courses[i] = strdup(courses[i]);
    }
    return sp;
}
     
    
coursesallocated for the structure or make thecoursesarray end with aNULLpointer.malloc(sizeof(School) + n * sizeof(char*))NULL, it is a matter of convention: either you know how many elements are allocated for the array and you give this information to all users of the structure, or you add a finalNULLelement when you allocate the array and users will look for theNULLelement.