【例9.1】找出这个程序中的错误。
#include <stdio.h> void disp (struct LIST ); int main () { struct LIST{ int a ,b ; }d={3 ,9} ,e={2 ,8} ; LIST f={5 ,6} ; printf (\"%d ,%dn\" , f.a ,f.b ); disp (d ); disp (e ); return 0 ; } // 将结构作为参数,以传数值的方式传递这个参数 void disp (struct LIST s ) { printf (\"%d ,%dn\" , s.a ,s.b ); }
【解答】把结构定义在主程序中,被调函数disp无法使用结构变量作为参数。结构跟数组不一样,数组可以定义在主函数里,但结构不行。如果将结构定义在主函数里,结构具有封装的特性,就只能被主函数自己使用。
这种定义结构变量的方法也不对,在C++语言中可以不重写结构关键字struct,在C语言中必须重写struct。下面是改正后的程序。
#include <stdio.h> void disp (struct LIST ); struct LIST{ int a ,b ; }d={3 ,9} ,e={2 ,8} ; int main () { struct LIST f={5 ,6} ; disp (d ); disp (e ); printf (\"%d ,%dn\" , f.a ,f.b ); return 0 ; } void disp (struct LIST s ) { printf (\"%d ,%dn\" , s.a ,s.b ); }
运行结果如下。
3 ,9 2 ,8 5 ,6
【例9.2】这个程序有时对,但大部分时间出错。开始以为是读d.name少“&”符号,但加上还是如此。请分析错在哪里。
#include <stdio.h> void disp (struct LIST ); struct LIST{ char name[10] ; char sex ; // 回答m 或者f int a ; }d ; int main () { printf (\" 输入:\" ); scanf (\"%s%c%d\" ,d.name ,&d.sex ,&d.a ); disp (d ); return 0 ; } void disp (struct LIST s ) { printf (\"%s ,%c ,%dn\" , s.name ,s.sex ,s.a ); }
【解答】字符数组使用与不使用“&”是一样的,因为字符数组的名字就是存储它的首地址,语法上都是正确的,问题出在读字符变量sex上。这里使用的是男性的第1个字母m(male)和女性的第1个字母f(female)。这条语句很难正常,完全是因为无法保证输入不产生干扰。读入是不分顺序的,可以将最难处理的放在最后,即改为
scanf (\"%s%d%c\" ,d.name ,&d.a ,&d.sex );
不过要注意,输入数字和字母之间不能有空格。例如,下面是一个运行示范。
输入: 王传义 70m 王传义,m ,70
注意不要使用那些提示符号,例如,想使用
scanf (\"%s ,%d ,%c\" ,d.name ,&d.a ,&d.sex );
的格式,使用输入“王传义,70,m”的方式解决来这个问题,也是徒劳的。
可以使用每次提示的方法,在scanf中增加空格来解决字符输入问题。例如:
#include <stdio.h> void disp (struct LIST ); struct LIST{ char name[10] ; char sex ; // 回答m 或者f 男 male 女 female int a ; }d ; int main () { printf (\" 输入姓名:\" ); scanf (\"%s\" ,d.name ); printf (\" 输入年龄:\" ); scanf (\"%d\" ,&d.a ); printf (\" 输入性别m/f :\" ); scanf (\" %c\" ,&d.sex ); // 注意留空格的方式 disp (d ); return 0 ; } void disp (struct LIST s ) { printf (\"%s ,%c ,%dn\" , s.name ,s.sex ,s.a ); }
运行示例如下。
输入姓名:王传义 输入年龄:70 输入性别m/f :m 王传义,m ,70
还有一种方法是在scanf之前使用一条“getchar();”语句。一般情况下,这种方法很有效,但有时也会失效,不如留空格的方法可靠。
还有的程序员干脆把性别也定义为字符串,其实有时也一样会碰到这种问题,一般是在发现出现这种问题时,再采取增加一条“getchar();”语句的方法来解决。即使改用gets函数,有时也会碰到这类问题。
结论:给结构变量的字符域赋值时,一定要多次验证并且要特别小心地验证。
【例9.3】这个程序中的赋值语句有错误,请分析错在哪里。
#include <stdio.h> void disp (struct LIST ); struct LIST{ int a ,b ; } ; int main () { int i ; struct LIST s[3] ,t ; printf (\" 输入:\" ); scanf (\"%d%d\" ,&t.a ,&t.b ); printf (\" 输入:\" ); scanf (\"%d%d\" ,s[0].a ,s[0].b ); for (i=0 ;i<3 ;i++ ) { s[i].a=s[0].a+t.a +i ; s[i].b=s[0].b+t.b +i ; } return 0 ; } void disp (struct LIST s ) { int i ; for (i=0 ;i<3 ;i++ ) { printf (\"%d ,%dn\" , s[i].a ,s[i].b ); } }
【解答】结构变量的赋值是正确的,结构数组不对。改为
scanf (\"%d%d\" ,&s[0].a , &s[0].b );
即可。结构数组与普通的数组一样,下标从0开始,为各个元素赋值需要使用地址符。
【例9.4】分析下面为结构变量赋值的程序是否能正常工作,并给出读入数据的等效语句。
#include <stdio.h> struct List{ char c ; int num ; char name[12] ; float fnum[2] ; }a ; void disp (void ); int main ( ) {disp (); return 0 ;} void disp ( ) { printf (\" 输入一个字符:\" ); scanf (\"%c\" ,&a.c ); printf (\" 输入一个整数:\" ); scanf (\"%d\" ,&a.num ); printf (\" 输入一个字符串:\" ); scanf (\"%s\" ,a.name ); { int i=0 ; printf (\" 输入两个浮点数:\" ); for (i=0 ;i<2 ;i++ ) scanf (\"%f\" ,(a.fnum+i )); } printf (\"%c ,%d ,%s ,%f ,%fn\" , a.c ,a.num ,a.name ,a.fnum[0] ,a.fnum[1] ); printf (\"%c ,%d ,%s ,%f ,%fn\" , a.c ,a.num ,&a.name[4] ,* (a.fnum ),* (a.fnum+1 )); }
【解答】这个程序巧妙地错开字符和数值,而且把字符放在第一个读取,所以避免了键盘抖动带来的干扰,确保程序能正常工作。读字符串name的等效语句为
scanf (\"%s\" ,&a.name );
读实数的数据是赋给数组,所以等效语句为
scanf (\"%f\" ,&a.fnum[i] );
注意不能使用“a.fnum[i]”的方式,对数值数组的元素赋值必须使用地址。
运行示例如下:
输入一个字符: M 输入一个整数: 89 输入一个字符串: 张一平 输入两个浮点数: 2.5 6.8 M ,89 ,张一平,2.500000 ,6.800000 M ,89 ,平,2.500000 ,6.800000
printf用数组首地址的方式输出其值,第1个元素为*(a.fnum),第2个为*(a.fnum+1)。&a.name[4]是“平”的存储地址,所以输出“平”。
【例9.5】这个程序编译无误,运行出错,是何原因?
#include <stdio.h> struct List{ char *name ; int num ; }a ; void disp (void ); int main ( ){ disp (); return 0 ;} void disp ( ) { printf (\" 输入姓名:\" ); scanf (\"%s\" ,a.name ); printf (\" 输入编号:\" ); scanf (\"%d\" ,&a.num ); printf (\"%s ,%dn\" , a.name ,a.num ); }
【解答】注意程序中结构指针变量没有赋初值。a.num的含义是这个结构的指针变量的值,不是地址。这个程序中使用语句
scanf (\"%s\" ,a.name );
给结构a的字符串数组a.name赋值,显然本例不能用此语句给结构的指针变量赋值。因此程序中使用了没有初始化的指针变量,运行出错。
由此看来,结构的指针变量和字符数组的表达形式一样,所以只好用中间转换的办法给指针变量赋值。一种是将输入读入一个字符串中,然后赋给指针变量。另一种是定义一个指针变量并为它申请内存,将输入存入这块内存,然后赋给结构的指针变量。下面分别给出这两种方法的完整程序。
// 将输入读入一个字符串中,然后赋给指针变量的程序清单 #include <stdio.h> struct List{ char *name ; int num ; }a ; void disp (void ); int main ( ) { disp (); return 0 ; } void disp ( ) { char c[12] ; printf (\" 输入姓名:\" ); scanf (\"%s\" ,c ); // 注意字符串中不能有空格 a.name=c ; printf (\" 输入编号:\" ); scanf (\"%d\" ,&a.num ); printf (\"%s ,%dn\" , a.name ,a.num ); } // 使用动态内存的方法的程序清单 #include <stdio.h> #include <stdlib.h> #include <string.h> struct List{ char *name ; int num ; }a ; void disp (void ); int main ( ) { disp (); return 0 ; } void disp ( ) { char *p= (char * )malloc (12 ); printf (\" 输入姓名:\" ); scanf (\"%s\" ,p ); a.name=p ; printf (\" 输入编号:\" ); scanf (\"%d\" ,&a.num ); printf (\"%s ,%dn\" , a.name ,a.num ); }
两个程序等价,运行结果一样。下面给出一个运行示范。
输入姓名: 张一平 输入编号: 2856 张一平,2856