制作初学C程序,根据年龄对学生进行阅读和排序

时间:2014-03-01 21:34:44

标签: c arrays sorting data-structures

代码:

    #include <stdio.h>

    typedef struct person {
        int age ;
        char name[40];
    }person;

    void perm ( person * A , person * B ){
        person temp ;
        temp = *A ;
        *A = *B ;
        *B = temp ;
    }

    void main () {
        person classroom[6];
        int i , j ;
        // reading students name and ages
        for ( i=0 ; i<6 ; i++ ){
            printf("Enter name :");
            fgets (classroom[i].name, 40, stdin);
            printf("Enter age : ");
            scanf("%d",&classroom[i].age);
        }
        // sorting them
        for ( i=0 ; i<6 ; i++ ){
            for ( j=0 ; j<6-i ; j++ ){
                if ( classroom[j].age > classroom[j+1].age ){
                    perm (&classroom[j],&classroom[j+1]);
                }
            }
        }
        // printing them sorted
        printf("\n After sorting accoring to ages :");
        for ( i=0 ; i<6 ; i++ ){
            printf(" %s \n",classroom[i].name[40]);
        }
        // finished
        getchar();
        getchar();

    }   

该计划应该:

  1. 定义学生类型“人”。
  2. 定义两人互换程序“void perm(person * A,person * B);”。
  3. 宣布一系列名为“教室”的人。
  4. 填写数组名称和年龄。
  5. 使用冒泡排序算法排序。
  6. 排序后显示数组。

2 个答案:

答案 0 :(得分:0)

我做了一个快速检查,我注意到该代码中至少有3个主要错误:

1)当您查找学生姓名时,您将遇到麻烦,因为在扫描文件中未正确处理'\ n',为了正确处理您需要使用'\ n',例如您可以添加在scanf之后直接使用getc(),就像我在下面的代码片段中所做的那样:

 for ( i=0 ; i<6 ; i++ ){
        printf("Enter name :");
        fgets (classroom[i].name, 40, stdin);
        printf("Enter age : ");
        scanf("%d",&classroom[i].age);
       /* Add this one will catch the \n for you making the code working better */
        getc(stdin); /* <<<<< ADD THIS LINE */ 
}

2)这里有一个缓冲区溢出:

 for ( j=0 ; j<6-i ; j++ ){
            if ( classroom[j].age > classroom[j+1].age ){
                perm (&classroom[j],&classroom[j+1]);
            }
   }

当i = 0时,j = 5 =&gt;教室[j + 1] ==&gt;教室[6]和索引6它在界限之外。你需要将你的循环设置为最大值

for ( j=0 ; j<5-i ; j++ ){
     if ( classroom[j].age > classroom[j+1].age ){
         perm (&classroom[j],&classroom[j+1]);
     }
}

3)打印结果时,指向超出字符串末尾的位置。此外,你没有指向一个字符串,但是你试图让第一个字符超出你为该名称保留的空格,因为你错过了符号'&amp;',而不是:

printf(" %s \n",classroom[i].name[40]);

您必须使用以下内容:

printf(" %s \n", &classroom[i].name[0]);

答案 1 :(得分:0)

好的,这个问题应该纠正成一个正确的问题,以便它可能会成为一个合适的Stack Overflow条目。有了这段代码,你就会有四个问题:

  

1 - 为什么我先被提示输入第二(及后续)学生的Age而未先输入他/她Name?<登记/>    2 - 为什么我使用此代码遇到访问冲突(或分段错误,无论如何)?
   3 - 为什么我仍然遇到访问冲突?
   4 - 为什么名称显示为双换行符?

对于第一个问题, stdin是缓冲输入。我可能会错过缓冲的真正定义,但是你和我应该知道的是当你输入:

20*pressTheEnterKey*

您在stdin缓冲区内推送以下内容:

'2' '0' '\n'

前两个字符由您调用的scanf获取并使用,因为它们对%d类型说明符很有价值。但是,新行字符\n仍然存在。

随着fgets的下一次调用,您要求stdin中的字符流,直到您点击已经提供的新行字符。 fgets将新行存储在classroom[i].name中并继续。

你不会想要的,对吧?

为防止这种情况发生,您必须放弃\n,为此,您有两种选择:

现在针对嵌套for循环中的第二个问题; ,您正尝试访问classroom[6].agei == 0的内存位置j == 5 }。该位置超出person classroom[6];涵盖的限制:从classroom[0]classroom[5]

修复这很简单,只需将内部for条件更改为:

for ( ... ; j < 5 - i ; ... ) { ... }

对于您的第三个问题; 这次您尝试访问超出任何classroom[i].name[40]范围的内存位置i。此外,即使不是,classroom[i].name[n]也会指向每个n: 0 <= n <= 39的字符,而这不是你用{打印出一个字符串(一个字符数组)%s的方式。 {1}}。

使用字符串上第一个字符的地址(字符数组)打印字符串。在这种情况下,这将是printf的地址,可以用以下两种方式编写:

  • classroom[i].name[0]
  • &classroom[i].name[0],不是更好吗?

现在,最后一个问题...... 还记得上面对classroom[i].name所说的内容吗?

  

fgets将新行存储在fgets中并继续。

classroom[i].name存储字符,通常直到命中换行符,并包括换行符。这就是你获得双重换行的原因。摆脱这种情况的简单方法是取出上一个fgets中的\n。我个人宁愿使用printf或将字符逐个字符存储到scanf_s,然后使用getchar丢弃垃圾缓冲输入,但无论如何。

如果您没有明确询问某些特定的内容,那么这就是您所获得的。