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