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

《C语言解惑》21.1 同类型结构变量之间的整体赋值

关灯直达底部

赋值运算符“=”只能针对同类型的结构变量。对于结构数组,只能像普通数组那样,针对元素之间进行逐个域的赋值。

【例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 学号:11245 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     //12,5,3,4,2,5,4339632     //24336176,4336192,3,4,3,4     //3p1的a=35,b=58。m的a=12,b=15     //44339632,4339632,35,58,35,58     //54339632,4339632,35,58,35,58     //612,15,4336176     //735,58,4339632,4336176     //812,15,4336176,4336192     //93,4,4336192,0     //1035,58     //1112,15     //123,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语句)。对于动态内存,不用时也需及时释放。

其实,这种赋值方式就是链表的循环赋值基础。