基里连科的回答应该可以解决您当前的问题,但是该程序的几乎每一行都存在从微不足道到严重的错误。根据您更大的目标,您可能不需要修复所有这些问题,但无论如何我都会将它们全部写下来,以说明冰山的大小。
void main() {
int main(void). 是int绝对要求。()在 C(不是 C++)中,为函数参数列表编写意味着参数是未指定的,而不是没有参数;从技术上讲,您可以在这里摆脱它,因为这是一个函数定义,但它的风格很糟糕。
函数定义的左大括号总是单独一行,即使所有其他左大括号都被拥抱。
    int num = 0,i=0;
间距不一致。初始化是不必要的。
    printf("Number of students:");
fputs("Number of students", stdout);当您不使用printf的格式化功能时,一些样式指南更喜欢。但是有些编译器可以为你做转换,这没什么大不了的。
    scanf("%d", &num);
永远不要使用scanf, fscanf, orsscanf,因为:
- 数值溢出会触发未定义的行为。允许 C 运行时仅仅因为某人输入了太多数字而使您的程序崩溃。
 
- 一些格式说明符(特别是
%s,您稍后将在此程序中使用!)是不安全的,其方式与不安全完全相同gets,即它们会愉快地写入提供的缓冲区的末尾并让您的程序崩溃(这个特定的程序看起来不安全- 对我很敏感,但应该总是像一个人的程序那样编码至少有点危险)。 
- 它们使正确处理格式错误的输入变得极其困难。
 
从用户那里读取单个非负数的正确方法是这样的:
unsigned long getul(void)
{
    char buf[80], *endp;
    unsigned long val;
    for (;;) {
        fgets(buf, 80, stdin);
        val = strtoul(buf, &endp, 10);
        if (endp != buf && *endp == '\n')
            return val;
        if (buf[strlen(buf)] != '\n')
            while (getchar() != '\n')
                /* discard */;
        fprintf(stderr, "*** Enter one nonnegative integer, smaller than %lu.\n",
                ULONG_MAX);
    }
}
您可以在这里使用固定大小的缓冲区,因为没有人的 ULONG_MAX 大到无法容纳 80 个字符。
    students = (student*)malloc(num*sizeof(student));
您应该calloc在此处使用,这样当您将结构写入磁盘时,它们不会充满垃圾。(或者按照 Alexandros 的建议编写自定义序列化程序,这也可以避免这个问题。)
    for(i=0;i<num;++i){
首选样式是for (i = 0; i < num; i++) {. 除了间距之外,使用i++代替++iso 可以i在所有三个表达式中出现在相同的位置;这使它更容易阅读。
        student* ptr = students+i*sizeof(student);
student* ptr = students + i;如其他地方所讨论的。
        printf("Name:");
        scanf("%s", ptr->cStdName);
请参阅上面的评论。您需要另一个辅助函数,如下所示:
void getstr(char *buf, size_t len)
{
    size_t n;
    for (;;) {
        fgets(buf, len, stdin);
        n = strlen(buf);
        if (n < len && buf[n] == '\n') {
            memset(buf+n, 0, len-n);
            return;
        }
        while (getchar() != '\n')
            /* discard */;
        fprintf(stderr, "*** Enter no more than %lu characters.",
                (unsigned long)(len-1));
    }
}
...
        scanf("%f", &ptr->dStdAvg);
在这里你需要另一个辅助函数。和除了它使用getf的完全一样,当然错误信息也有一点不同。getulstrtod
    f = fopen("bin.bin","wb");
这不是一个非常通用的文件名吗?用户可能应该有一种方法来指定它。
    fwrite(&num,sizeof(int),1,f);
您的文件格式需要一个幻数。
    fwrite(students,sizeof(student),num,f);
您正在以 CPU-endian 顺序将二进制数据写入磁盘。对于此应用程序来说,这可能不是问题,但请注意,您可能会遇到跨平台兼容性问题。(就个人而言,对于您正在做的事情,我会使用诸如 JSON 之类的文本序列化,或诸如 sqlite 之类的简单无守护进程数据库。)有关此文件格式的更多潜在问题,请参阅 Alexandros 的回答。
写入磁盘上的文件时很少出现问题,而且这不是那种输出通过管道传输到某处的程序,但是,我仍然要提到它fwrite并不能保证写入您提供的所有数据。从技术上讲,您必须fwrite像这样调用循环:
size_t r, n = sizeof(student) * num;
char *p = (char *)students;
while (n > 0) {
    r = fwrite(p, 1, n, f);
    if (r == 0) break;  /* write error */
    n -= r;
    p += r;
}
为此,您必须自己进行乘法运算并将第二个参数的 1 传递给fwrite; 否则,简短的写入可能会在“数据元素”的中间结束,您无法知道这已经发生了。
    fclose(f);
在关闭文件之前检查写入错误。
if (ferror(f) || fclose(f)) {
    perror("bin.bin");
    return 1; /* unsuccessful exit */
}
...
    system("pause");
只是return 0。使您按键退出的程序对批处理不友好。