賦值運算符「=」只能針對同類型的結構變量。對於結構數組,只能像普通數組那樣,針對元素之間進行逐個域的賦值。
【例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語句)。對於動態內存,不用時也需及時釋放。
其實,這種賦值方式就是鏈表的循環賦值基礎。