首页 » C语言解惑 » C语言解惑全文在线阅读

《C语言解惑》9.1 结构定义和赋值错误

关灯直达底部

【例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