赋值运算符“=”只能针对同类型的结构变量。对于结构数组,只能像普通数组那样,针对元素之间进行逐个域的赋值。
【例21.1】同类型结构变量之间的相互赋值示例。
#include <stdio.h>
void disp
(STUDNT
);
typedef struct student {
char name[10]
;
int studnem
;
}STUDNT
;
struct NUM {
int a
;
int b
;
}m={2
,5}
,n={3
,4}
,d
;
int main
()
{
STUDNT b[3]
,c
;
STUDNT a[3]={{\"Wangping0\"
,1123}
,
{\"WangPing1\"
,1124}
,{\"Wangping2\"
,1125}}
;
disp
(a
);
b[1]=a[1]
; b[2]=a[2]
; b[0]=a[0]
;
disp
(b
);
c=a[1]
;
printf
(\"
姓名:%s
学号:%dn\"
,c.name
,c.studnem
);
d=n
; d.a+=m.a
; d.b+=m.b
;
printf
(\"%d %dn\"
,d.a
,d.b
);
return 0
;
}
void disp
(STUDNT a
)
{
int i
;
char st[8]={\"
姓名:\"
,\"
学号:\"}
;
for
(i=0
;i<3
;i++
)
printf
(\"%s%s %s%dn\"
,st[0]
,a[i].name
,st[1]
,a[i].studnem
);
}
【解释】对于同类型的结构变量,可以直接使用赋值运算符“=”,如
d=n
;
但对结构数组必须逐个赋值,赋值的顺序没有关系,如
b[2]=a[2]
; b[0]=a[0]
; b[1]=a[1]
;
下面是使用for语句按顺序赋值
for
(i=0
;i<3
;i++
)
b[i]=a[i]
;
结构数组的各个元素可以单独作为变量参与运算,如
b[0].studnum=a[2].studnum
;
同类型的结构变量可以如普通变量一样进行操作,例如:
d.a+=m.a
; d.b+=m.b
;
注意:一定要避免犯“b=a;”的错误。
程序运行结果如下。
姓名:Wangping0
学号:1123
姓名:WangPing1
学号:1124
姓名:Wangping2
学号:1125
姓名:Wangping0
学号:1123
姓名:WangPing1
学号:1124
姓名:Wangping2
学号:1125
姓名:WangPing1
学号:1124
5 9
【例21.2】结构指针赋值示例。
本例设计一个结构,这个结构还具有一个指向自身的指针。
struct NUM {
int a
;
int b
;
struct NUM *next
;
}m={2
,5}
,n={3
,4}
,d
;
初始化变量m和n时,没有给它们的指针赋初值,没有初始化变量d,所以也没有给变量d的指针next、域a和b赋初始值。程序先演示结构指针变量,再演示next指针概念。为了方便讲解,将输出编号,然后结合输出讲解。
源程序如下。
#include <stdio.h>
#include <stdlib.h>
struct NUM {
int a
;
int b
;
struct NUM *next
;
}m={2
,5}
,n={3
,4}
,d
;
int main
()
{
struct NUM *p1
,*p2
,*p
;
p=
(struct NUM *
)malloc
(sizeof
(struct NUM
));
printf
(\"p=%un\"
,p
);
//
演示指针变量和结构变量的赋值
p1=&m
; //
初始化指针p1
p2=&n
; //
初始化指针p2
d=m
;
//
结构变量之间使用赋值运算符进行整体赋值
printf
(\"%d
,%d
,%d
,%d
,%d
,%d
,%un\"
,m.a
,m.b
,n.a
,n.b
,d.a
,d.b
,&d
);
*p1=*p2
; //
演示p1
≠p2
printf
(\"%u
,%u
,%d
,%d
,%d
,%dn\"
,p1
,p2
,p1->a
,p1->b
,p2->a
,p2->b
);
p1=&d
;
p1->a=35
;p1->b=58
; m.a=12
;m.b=15
;
printf
(\"
改变p1
的域值为:a=%d
,b=%dn\"
,p1->a
,p1->b
);
p2=p1
; //
演示p1=p2
且*p1=*p2
,p2
指向的是d
printf
(\"%u
,%u
,%d
,%d
,%d
,%dn\"
,p1
,p2
,p1->a
,p1->b
,p2->a
,p2->b
);
p=p2
; //
演示链表概念,p
具有节点d
printf
(\"%u
,%u
,%d
,%d
,%d
,%dn\"
,p
,p2
,p->a
,p->b
,p2->a
,p2->b
);
//
让d
的next
指向m
节点,m
作为第2
个节点
d.next=&m
;
printf
(\"%d
,%d
,%un\"
,d.next->a
,d.next->b
,d.next
);
//m
的next
指向n
,n
作为第3
个节点
m.next=&n
;
//n
的next
设置为NULL
,作为结束标志
n.next=NULL
;
{
int i=0
;
for
(i=0
;i<3
;i++
,p
){
printf
(\"%d
,%d
,%u
,%un\"
,p->a
,p->b
,p
,p->next
);
p=p->next
;
}
}
//
使p
指向起点,用NULL
判别,输出链表内容
p=&d
;
while
(p
!=NULL
)
{
printf
(\"%d
,%dn\"
,p->a
,p->b
);
p=p->next
;
}
return 0
;
}
程序运行结果如下。
p=4398640 //1
2
,5
,3
,4
,2
,5
,4339632 //2
4336176
,4336192
,3
,4
,3
,4 //3
p1
的a=35
,b=58
。m
的a=12
,b=15 //4
4339632
,4339632
,35
,58
,35
,58 //5
4339632
,4339632
,35
,58
,35
,58 //6
12
,15
,4336176 //7
35
,58
,4339632
,4336176 //8
12
,15
,4336176
,4336192 //9
3
,4
,4336192
,0 //10
35
,58 //11
12
,15 //12
3
,4 //13
【解释】前两行的输出,只是作为以后对比的依据,其中也演示整体赋值(d=m)。注意第2行输出d的地址是4339632。
第3行的输出演示了指针变量“*p1=*p2”的赋值效果。这里表示p1的a和b变为p2的a和b,但指针p1并没有放弃自己指向的地址(p1≠p2),所以输出的地址不同。
执行“p1=&d;”,然后演示使用指针改变d的a和b的值,直接改变m的值。输出第4行只是验证修改信息正确,d将作为第1节点,注意两个变量a和b的值。
第5行的输出验证“p2=p1;”的效果。p2=p1表示指针p2放弃了原来指向的地址,与p1指向同一个对象,这就理所当然地使*p2=*p1自然成立。因为不是字符串,所以存储内容也相同。注意和第2行的输出比较,这里指向的地址是结构变量d的存储首地址。
执行“p=p2;”,使d作为第1个节点。第6行的输出与第5行的完全一样。
执行“d.next=&m;”,得到2个节点。第7行的输出是第2个节点信息。
执行“m.next=&n;”,得到3个节点。执行“n.next=NULL;”,作为结束标志。
第8-10行的输出演示了链表关系。每一行均显示节点数据、节点存储首地址和指向下一个节点的地址(next)。
第11-13行演示使用while循环语句输出链表信息的方法。
【例21.3】结构数组和指针赋值示例。
#include <stdio.h>
#include <string.h>
void disp
(STUDNT
);
typedef struct student {
char name[10]
;
int studnem
;
}STUDNT
;
int main
()
{
STUDNT b[3]
,c[3]={\"we\"}
,*pc1
,*pc3
,*pc3=c
;
STUDNT a[3]={{\"Wangping0\"
,1123}
,
{\"WangPing1\"
,1124}
,{\"Wangping2\"
,1125}}
;
pc1=a
; pc2=b
;
pc2=pc1
; //
演示 pc2=pc1
;
disp
(pc2
); //
第1
组输出
*pc3=*pc1
; //
演示 *pc3=*pc1
;
disp
(pc3
); //
第2
组输出
*
(pc3+1
)=a[2]
; //
演示数组元素整体赋值方法
*
(pc3+2
)=*
(pc3
);
disp
(pc3
); //
第3
组输出
pc3[0]=a[2]
;
pc3[1]=pc2[0]
;
pc3[2]=a[1]
;
disp
(pc3
); //
第4
组输出
strcpy
(pc3->name
,a[0].name
);
pc3->studnem=a[0].studnem
;
strcpy
((pc3+1
)->name
,a[1].name
);
(pc3+1
)->studnem=a[1].studnem
;
strcpy
((pc3+2
)->name
,a[2].name
);
(pc3+2
)->studnem=a[2].studnem
;
disp
(pc3
); //
第5
组输出
return 0
;
}
void disp
(STUDNT a
)
{
int i
;
char st[8]={\"
姓名:\"
,\"
学号:\"}
;
for
(i=0
;i<3
;i++
)
printf
(\"%s%s %s%dn\"
,st[0]
,a[i].name
,st[1]
,a[i].studnem
);
}
运行结果如下。
姓名:Wangping0
学号:1123 //
第1
组输出
姓名:WangPing1
学号:1124
姓名:Wangping2
学号:1125
姓名:Wangping0
学号:1123 //
第2
组输出
姓名:
学号:0
姓名:
学号:0
姓名:Wangping0
学号:1123 //
第3
组输出
姓名:Wangping2
学号:1125
姓名:Wangping0
学号:1123
姓名:Wangping2
学号:1125 //
第4
组输出
姓名:Wangping0
学号:1123
姓名:WangPing1
学号:1124
姓名:Wangping0
学号:1123 //
第5
组输出
姓名:WangPing1
学号:1124
姓名:Wangping2
学号:1125
第1组演示“pc2=pc1;”,它们是等效的。
第2组演示“*pc3=*pc1;”,只是将数组的第1个元素整体赋值。其他元素均为0值。
第3组演示使用相同方式给其他元素整体赋值,而第4组则使用指针下标整体赋值。
第5组则使用指针地址偏移值寻找对数组元素具体的域名进行定位。因为name是字符串,所以需要调用库函数strcpy赋值。
由这三个典型的例子可见,需要根据实际情况选择最佳方案。在不需要改变地址的情况下,应尽量使用偏移量定位。在需要移动地址时,如链表,要注意它移动的位置以及是否需要恢复原来的指向(如例21.2的while语句)。对于动态内存,不用时也需及时释放。
其实,这种赋值方式就是链表的循环赋值基础。