【例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,92,85,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.8M,89,张一平,2.500000,6.800000M,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