讀古今文學網 > C語言解惑 > 21.1 同類型結構變量之間的整體賦值 >

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 
學號: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語句)。對於動態內存,不用時也需及時釋放。

其實,這種賦值方式就是鏈表的循環賦值基礎。