-
結構體類型
鎖定
- 中文名
- 結構體類型
- 外文名
- structNode
結構體類型概述
在C語言中,結構體(struct)指的是一種數據結構,是C語言中聚合數據類型(aggregate data type)的一類。結構體可以被聲明為變量、指針或數組等,用以實現較複雜的數據結構。結構體同時也是一些元素的集合,這些元素稱為結構體的成員(member),且這些成員可以為不同的類型,成員一般用名字訪問。
[1]
C++提供了許多種基本的數據類型(如int、float、double、char等)供用户使用。但是由於程序需要處理的問題往往比較複雜,而且呈多樣化,已有的數據類型顯得不能滿足使用要求。因此C++允許用户根據需要自己聲明一些類型,用户可以自己聲明的類型還有結構體類型(structure)、共用體類型(union)、枚舉類型(enumeration)、類類型(class )等,這些統稱為用户自定義類型(user-defined type,UDT)。
[1]
在一個組合項中包含若干個類型不同(當然也可以相同)的數據項。C和C++允許用户自己指定這樣一種數據類型,它稱為結構體。它相當於其他高級語言中的記錄(record)。例如,可以通過下面的聲明來建立數據類型。
[1]
struct Student//聲明一個結構體類型Student
{
int num;//包括一個整型變量num
char name[20];//包括一個字符數組name,可以容納20個字符
char sex;//包括一個字符變量sex
int age;//包括一個整型變量age
float score;//包括一個單精度型變量
char addr[30];//包括一個字符數組addr,可以容納30個字符
這樣,程序設計者就聲明瞭一個新的結構體類型Student(struct是聲明結構體類型時所必須使用的關鍵字,不能省略),它向編譯系統聲明: 這是一種結構體類型,它包括num, name, sex, age, score, addr等不同類型的數據項。應當説明Student是一個類型名,它和系統提供的標準類型(如int、char、float、double 一樣,都可以用來定義變量,只不過結構體類型需要事先由用户自己聲明而已。
[1]
聲明一個結構體類型的一般形式為
struct 結構體類型名{成員表列};
結構體類型名用來作結構體類型的標誌。上面的聲明中Student就是結構體類型名。大括號內是該結構體中的全部成員(member),由它們組成一個特定的結構體。上例中的num,name,sex,score等都是結構體中的成員。在聲明一個結構體類型時必須對各成員都進行類型聲明即類型名成員名;每一個成員也稱為結構體中的一個域(field)。成員表列又稱為域表。
[1]
成員名的定名規則與變量名的定名規則相同
在C語言中,結構體的成員只能是數據(如上面例子中所表示的那樣)。
結構體類型定義
結構體類型定義
struct Student student1, student2;
以上定義了student1和student2為結構體類型struct Student的變量,即它們具有struct Student類型的結構。在定義了結構體變量後,系統會為之分配內存單元。例如student1和student2在內存中各佔63個字節
[1]
(4+20+1+4+4+30=63)。
但是這裏需要注意:名義上計算大小為63,根據不同編譯器,內存存儲會有所不同,在存儲該結構體時會按照內存對齊進行相關處理,系統默認對齊係數為4(即按int類型對齊,粗略認識可以認為每相鄰兩個數據成員存儲是大小是4的整數倍,請參考下面對比結構體),詳情請參考內存對齊,因此該結構體實際大小為:68,具體計算如下:
[1]
{
int num;//整型,4個字節
char name[20];//字符數組20個字節,4的整數倍,取20字節
char sex;//字符類型,一個字節,往下不能湊齊4個字節,因此取4個字節
int age;//以下同理 4個字節
float score;//4個字節
char addr[30];//字符數組30個字節,取4整數倍,因此為32
}
對比結構體:1
{
int num;//整型,4個字節
int age;//以下同理 4個字節
float score;//4個字節
char addr[30];//字符數組30個字節,取4整數倍,因此為32
}
對比結構體:2{
int num;//整型,4個字節
char name[20];//字符數組19個字節,往下能取4的整數倍,取20字節
char sex;//字符類型,一個字節,往下能湊上一個字符數據字節,單任不能湊齊4個字節,因此取4個字節
char test;//新增加的數據類型,已往上存放,為了表示存在這個數據,這裏給個0
int age;//以下同理 4個字節
float score;//4個字節
char addr[30];//字符數組30個字節,取4整數倍,因此為32
}
(2) 在聲明類型的同時定義變量
例如:
struct Student//聲明結構體類型Student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
這種形式的定義的一般形式為
struct 結構體名
{
成員表列
其一般形式為
struct//注意沒有結構體類型名
{
成員表列
這種方法雖然合法,但很少使用。提倡先定義類型後定義變量的第(1)種方法。
在程序比較簡單,結構體類型只在本文件中使用的情況下,也可以用第(2)種方法。
關於結構體類型,有幾點要説明:
(3) 對結構體中的成員(即“域”),可以單獨使用,它的作用與地位相當於普通變量。
如
struct Date //聲明一個結構體類型Date
{
int month;
int day;
int year;
};
struct Student
//聲明一個結構體類型Student
{
int num;
char name[20];
char sex;
int age;
Date birthday;
char addr[30];
}student1,student2;
//定義student1和student2為結構體類型Student的變量Student的結構。
(5) 結構體中的成員名可以與程序中的變量名相同,但二者沒有關係。
結構體類型初始化
和其他類型變量一樣,對結構體變量可以在定義時指定初始值。如
struct Student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}student1={10001,"Zhang Xin",'M',19,90.5,"Shanghai"};
結構體類型變量
在定義了結構體變量以後,當然可以引用這個變量。
(1) 可以將一個結構體變量的值賦給另一個具有相同結構的結構體變量。
如上面的student1和student2都是student類型的變量,可以這樣賦值:
(2) 可以引用一個結構體變量中的一個成員的值。
例如, student1.num表示結構體變量student1中的成員的值,如果student1的值如圖7.2所示,
則student1.num的值為10001。
引用結構體變量中成員的一般方式為
結構體變量名.成員名
例如可以這樣對變量的成員賦值:
(3) 如果成員本身也是一個結構體類型,則要用若干個成員運算符,一級一級地找到最低一級的成員。
例如,對上面定義的結構體變量student1, 可以這樣訪問各成員:
student1.num (引用結構體變量student1中的num成員)
如果想引用student1變量中的birthday成員中的month成員,不能寫成student1.month,
必須逐級引用,即
student1.birthday.month=12;
(4) 不能將一個結構體變量作為一個整體進行輸入和輸出。
cin>>student1;
(5) 對結構體變量的成員可以像普通變量一樣進行各種運算(根據其類型決定可以進行的運算種類)。例如
student2.score=student1.score;
sum=student1.score+student2.score;
student1.age++;
++student1.age;
(6) 可以引用結構體變量成員的地址,也可以引用結構體變量的地址。如
cout<<&student1;//輸出student1的首地址
cout<<&student1.age;//輸出student1.age的地址
例 引用結構體變量中的成員。
#include <iostream>
using namespace std;
struct Date//聲明結構體類型Date
{int month;
int day;
int year;
};
{int num;
char sex;
Date birthday;//聲明birthday為Date類型的成員
float score;
}student1,student2={10002,″Wang Li″,′f′,5,23,1982,89.5};
//定義Student 類型的變量student1,student2,並對student2初始化
int main( )
{ student1=student2;//將student2各成員的值賦予student1的相應成員
cout<<student1.num<<endl;//輸出student1中的num成員的值
cout<<student1.sex<<endl;//輸出student1中的sex成員的值cout<<student1.birthday.month<<′/′<<student1.birthday.day<<′/′ <<student1.birthday.year<<endl;//輸出student1中的birthday各成員的值
cout<<student1.score<<endl;
return 0; }
運行結果如下:
結構體類型數組
結構體類型定義
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
Student stu[3];//定義Student類型的數組stu
也可以直接定義一個結構體數組,如
struct Student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu[3];
或
struct
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
結構體數組的初始化與其他類型的數組一樣,對結構體數組可以初始化。如
struct Student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu[3]={
{10101,″Li Lin″, ′M′, 18,87.5, ″103 Beijing Road″},
{10102,″Zhang Fun″,′M′,19,99, ″130 Shanghai Road″},
定義數組stu時,也可以不指定元素個數,即寫成以下形式:
stu[ ]={{…},{…},{…}};
Student stu[ ]={{…},{…},{…}};//已事先聲明瞭結構體類型Student
結構體類型應用舉例
下面舉一個簡單的例子來説明結構體數組的定義和引用。
例7.2對候選人得票的統計程序。設有3個候選人,最終只能有1人當選為領導。今有10個人參加投票,從鍵盤先後輸入這10個人所投的候選人的名字,要求最後輸出這3個候選人的得票結果。可以定義一個候選人結構體數組,包括3個元素,在每個元素中存放有關的數據。
[1]
程序如下:
#include <iostream>
struct Person//聲明結構體類型Person
{
char name[20];
int count;
}Person leader[3]={″Li″,0,″Zhang″,0,″Fun″,0};
//定義Person類型的數組,內容為3個候選人的姓名和當前的得票數
int main( )
{
int i,j;
char leader_name[20];
//leader_name為投票人所選的人的姓名
for(i=0;i<10;i++) {cin>>leader_name;
//先後輸入10張票上所寫的姓名
for(j=0;j<3;j++)//將票上姓名與3個候選人的姓名比較
if(strcmp(leader_name,leader[j].name)==0) leader[j].count++;
//如果與某一候選人的姓名相同,就給他加一票
}
cout<<endl;
for(i=0;i<3;i++)//輸出3個候選人的姓名與最後得票數
{cout<<leader[i].name<<″:″<<leader[i].count<<endl;}
return 0;
}
運行情況如下:
Zhang↙ (每次輸入一個候選人的姓名)
Li↙
Fun↙
Li↙
Zhang↙
Li↙
Zhang↙
Li↙
Fun↙
Wang↙
Li:4 (輸出3個候選人的姓名與最後得票數)
Zhang:3
#include <iostream>
#include <string>
using namespace std;
struct Person
{
string name;//成員name為字符串變量
int count;
};
int main( )
{
Person leader[3]={″Li″,0,″Zhang″,0,″Fun″,0};
int i,j;
string leader_name;// leader_name為字符串變量
for(i=0;i<10;i++)
{
cin>>leader_name;
for(j=0;j<3;j++)
if(leader_name==leader[j].name) leader[j].count++
//用“==”進行比較
}
cout<<endl;
for(i=0;i<3;i++)
{cout<<leader[i].name<<″:″<<leader[i].count<<endl;}
return 0;
結構體類型指針
一個結構體變量的指針就是該變量所佔據的內存段的起始地址。可以設一個指針變量,用來指向一個結構體變量,此時該指針變量的值是結構體變量的起始地址。
結構體類型類型一
例 指向結構體變量的指針的應用。
#include <iostream>
#include <string>
using namespace std;
int main( )
{
struct Student
//聲明結構體類型student
{ int num;
char sex;
float score;
Student stu;
//定義Student類型的變量stu
Student *p=&stu;
//定義p為指向Student類型數據的指針變量並指向stu
stu.num=10301;
//對string變量可以直接賦值
stu.sex=′f′;
stu.score=89.5;
cout<<stu. num<<″ ″<<″ ″<<stu.sex<<″ ″<<
stu.score<<endl;
cout<<p -> num<<″ ″<<(*p).name<<″ ″<<(*p).sex<<″ ″<<
(*p).score<<endl;
return 0;
程序運行結果如下:
10301 Wang Fun f 89.5 (通過結構體變量名引用成員)
10301 Wang Fun f 89.5 (通過指針引用結構體變量中的成員)
兩個cout語句輸出的結果是相同的。
為了使用方便和使之直觀,C++提供了指向結構體變量的運算符->,
p->num 和(*p).num等價。
同樣,p->name等價於(*p).name。
也就是説,以下3種形式等價:
① 結構體變量.成員名。如stu.num。
② (*p).成員名。如(*p).num。
③ p->成員名。如p->num。
“->”稱為指向運算符。
請分析以下幾種運算:
p->n 得到p指向的結構體變量中的成員n的值。
p->n++ 得到p指向的結構體變量中的成員n的值,用完該值後使它加1。
結構體類型類型二
鏈表中的每一個元素稱為“結點”,每個結點都應包括兩個部分:
一是用户需要用的實際數據,
二是下一個結點的地址。
例如,可以設計這樣一個結構體類型:
struct Student
{
int num;
float score;
Student *next;//next指向Student結構體變量
};
其中成員num和score是用户需要用到的數據,相當於圖7.8結點中的A,B,C,D。next是指針類型的成員,它指向Student類型數據(就是next所在的結構體類型)。用這種方法就可以建立鏈表。
每一個結點都屬於Student類型,在它的成員next中存放下一個結點的地址,程序設計者不必知道各結點的具體地址,只要保證能將下一個結點的地址放到前一結點的成員next中即可。
下面通過一個例子來説明如何建立和輸出一個簡單鏈表。
#define NULL 0
#include <iostream>
struct Student
{
long num;
float score;
struct Student *next;
};
int main( )
{
Student a,b,c,*head,*p;
a. num=31001;
a.score=89.5;//對結點a的num和score成員賦值
b. num=31003;
b.score=90;//對結點b的num和score成員賦值
c. num=31007;
c.score=85;//對結點c的num和score成員賦值
head=&a;//將結點a的起始地址賦給頭指針head
a.next=&b; //將結點b的起始地址賦給a結點的next成員
b.next=&c; //將結點c的起始地址賦給b結點的next成員
c.next=NULL; //結點的next成員不存放其他結點地址
p=head; //使p指針指向a結點
do
{
cout<<p->num<<″ ″<<p->score<<endl; //輸出p指向的結點的數據
p=p->next; //使p指向下一個結點
} while (p!=NULL); //輸出完c結點後p的值為NULL
return 0;
請讀者考慮:
①各個結點是怎樣構成鏈表的。
②p起什麼作用?
本例是比較簡單的,所有結點(結構體變量)都是在程序中定義的,不是臨時開闢的,也不能用完後釋放,這種鏈表稱為靜態鏈表。對各結點既可以通過上一個結點的next指針去訪問,也可以直接通過結構體變量名a,b,c去訪問。
動態鏈表則是指各結點是可以隨時插入和刪除的,這些結點並沒有變量名,只能先找到上一個結點,才能根據它提供的下一結點的地址找到下一個結點。只有提供第一個結點的地址,即頭指針head,才能訪問整個鏈表。如同一條鐵鏈一樣,一環扣一環,中間是不能斷開的。
[1]
結構體類型函數參數
將一個結構體變量中的數據傳遞給另一個函數,有下列3種方法:
(1) 用結構體變量名作參數。一般較少用這種方法。
(3) 用結構體變量的引用變量作函數參數。
下面通過一個簡單的例子來説明,並對它們進行比較。
結構體類型方法一
用結構體變量作函數參數
#include <iostream>
#include <string>
using namespace std;
{ int num;
float score[3];
};
int main( )
{
void print(Student);//函數聲明,形參類型為結構體Student
Student stu;//定義結構體變量
stu.num=12345;//以下5行對結構體變量各成員賦值
stu.score[0]=67.5;
stu.score[1]=89;
stu.score[2]=78.5;
print(stu);//調用print函數,輸出stu各成員的值
return 0;
}
void print(Student st)
{
cout<<st.num<<″ ″<<″ ″<<st.score[0]
<<″ ″ <<st.score[1]<<″ ″<<st.score[2]<<endl;
}
運行結果為
結構體類型方法二
用指向結構體變量的指針作實參
#include <iostream>
#include <string>
using namespace std;
struct Student
{
int num; string name;//用string類型定義字符串變量
float score[3];
}stu={12345,″Li Fung″,67.5,89,78.5};//定義結構體student變量stu並賦初值
int main( )
{
Student *pt=&stu;//定義基類型為Student的指針變量pt,並指向stu
return 0;
}
void print(Student *p)
{
cout<<p->num<<″ ″<<p->name<<″ ″<<p->score[0]<<″ ″ <<
p->score[1]<<″ ″<<p->score[2]<<endl;
結構體類型方法三
用結構體變量的引用作函數參數
#include <iostream>
#include <string>
using namespace std;
struct Student
{
int num;
string name;
float score[3];
}stu={12345,″Li Li″,67.5,89,78.5};
void main( )
{
void print(Student &);
print(stu);
//實參為結構體Student變量
}
void print(Student &stud)
{
cout<<stud.num<<″ ″<<″ ″<<stud.score[0]
<<″ ″ <<stud.score[1]<<″ ″<<stud.score[2]<<endl;
引用變量主要用作函數參數,它可以提高效率,而且保持程序良好的可讀性。在本例中用了string方法定義字符串變量,在某些C++系統中不能運行這些程序,讀者可以修改程序,使之能在自己所用的系統中運行。
[1]
結構體類型分配
在軟件開發過程中,常常需要動態地分配和撤銷內存空間,例如對動態鏈表中結點的插入與刪除。
sizeof
C++提供了較簡便而功能較強的運算符new和delete來取代malloc和free函數。
注意: new和delete是運算符,不是函數,因此執行效率高。
new運算符的例子:
new int(100);//開闢一個存放整數的空間,並指定該整數的初值為100,返回一個指向該存儲空間的地址
new char[10];//開闢一個存放字符數組(包括10個元素)的空間,返回首元素的地址
new運算符使用的一般格式為
new 類型 [初值]
delete運算符使用的一般格式為
delete [ ] 指針變量
例如要撤銷上面用new開闢的存放單精度數的空間(上面第5個例子),應該用
delete p;
#include <iostream>
#include <string>
using namespace std;
struct Student //聲明結構體類型Student
{ string name;
int num;
char sex;
};
int main( )
p=new Student; //用new運算符開闢一個存放Student型數據的空間
p->name=″Wang Fun″; //向結構體變量的成員賦值
p->num=10123;
p->sex='m';
cout<<p->name<<endl<<p->num
<<endl<<p->sex<<endl;//輸出各成員的值
delete p;//撤銷該空間
return 0;
運行結果為
Wang Fun 10123 m
在動態分配/撤銷空間時,往往將這兩個運算符和結構體結合使用,是很有效的。可以看到: