代码:
#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();
}
该计划应该:
答案 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
,为此,您有两种选择:
fflush( stdin );
致电,我个人使用此功能,因为它适用于我,but it might not be working all the time according to this,所以...... while( getchar( ) != '\n' );
还应该丢弃缓冲区内的每个字符,直到换行符,包括新行字符 现在针对嵌套for
循环中的第二个问题; ,您正尝试访问classroom[6].age
和i == 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
丢弃垃圾缓冲输入,但无论如何。
如果您没有明确询问某些特定的内容,那么这就是您所获得的。