大學C語言程序設計
chapter 7 結構體
1. 結構體的認識
結構體概念:可以把各種類型的數據放在一起,形成新的數據類型。
如何定義:關鍵字 struct
格式:
struct 結構名{
數據類型 變量名1;
數據類型 變量名2;
};
如:定義一個學生,他有姓名,年齡,語文成績,數學成績,英語成績
struct student{
char name[20];
int age;
int score1,score2,score3;
};
訪問結構體中的信息,通過 ”.”來訪問
student stu; //定義一個結構體變量 stu
strcpy(stu.name,"helloA"); //字符數組的特殊賦值方式
stu.age=13;
stu.score1=88;
stu.score2=99;
stu.score3=100;
printf("%s %d %d %d\n",stu.name,stu.age,stu.score1,stu.score2,stu.score3);//輸出
結構體的定義形式
//方式 1
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu1,stu2;
//方式 2
student stu3,stu4;
結構體初始化賦值
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu={"helloB", 14,99,100,100};//初始化賦值
結構體數組
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu[N];
或者:student stu[N];
結構體數組初始化賦值
方式一
#include<stdio.h>
#include<string.h>
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu[3]={
{"helloA",13,88,99,100},
{"helloB",14,90,99,100},
{"helloC",15,100,100,100}};
int main(){
for(int i=0; i<3; i++){
printf("%s %d %d %d\n",stu[i].name,stu[i].age,stu[i].score1,stu[i].score2,stu[i].score3);
}
return 0;
}
方式二
#include<stdio.h>
#include<string.h>
struct student{
char name[20];
int age;
int score1,score2,score3;
};
struct student stu[3]={{"helloA",13,88,99,100},{"helloB",14,90,99,100},{"helloC",15,100,100,100}};
int main(){
for(int i=0; i<3; i++){
printf("%s %d %d %d\n",stu[i].name,stu[i].age,stu[i].score1,stu[i].score2,stu[i].score3);
}
return 0;
}
2. 結構體信息輸入輸出
單個結構體信息輸入輸出
#include<stdio.h>
#include<string.h>
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu;
int main(){
char name[20];
scanf("%s %d%d%d%d", name, &stu.age, &stu.score1,&stu.score2,&stu.score3);
strcpy(stu.name, name);
printf("%s %d %d %d %d\n", stu.name,stu.age,stu.score1,stu.score2,stu.score3);
return 0;
}
多個結構體信息輸入輸出
#include<stdio.h>
#include<string.h>
#define N 1000
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu[N];
int main(){
char name[20];
int n; scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%s %d%d%d%d", name, &stu[i].age, &stu[i].score1,&stu[i].score2,&stu[i].score3);
strcpy(stu[i].name, name);
}
for(int i=0; i<n; i++){
printf("%s %d %d %d %d\n", stu[i].name,stu[i].age,stu[i].score1,stu[i].score2,stu[i].score3);
}
return 0;
}
3. 結構體成員函數
注明:在C++中允許結構體包含函數成員,而標准C不支持。
struct student{
char name[20];
int age;
int score1,score2,score3;
int sum(){
return score1+score2+score3; //求得成績總和
}
}stu[N];
printf("sum()=%d\n", stu[i].sum()); //使用方法
4. 結構體排序
【題目描述】
有 N (N<1000)個學生,有它的姓名,學號,以及嵌入式C,微積分,思想品德三門學科的成績,現在想請你來給他們按照一定的規則進行排序。具體排序規則如下:
- 按照總分降序排序
- 如果總分相同,則依次按照嵌入式C,微積分,思想品德三門學科的成績降序排序
- 如果總分以及嵌入式C,微積分,思想品德三門學科的成績都相同,則按照學號升序排序。
輸入格式:輸入 N+1 行,第 1 行表示學生人數;
接下來 N 行,每行數據依次為學生姓名以及嵌入式C,微積分,思想品德三門學科的成績,該生學號就是輸入的第幾名學生。
輸出格式:輸出 N 行,依次為排序后學生的學號,姓名,三門學科總分以及嵌入式C,微積分,思想品德三門學科的成績
輸入樣例:
8
stu[1] 100 200 300
stu[2] 101 201 300
stu[3] 101 201 301
stu[4] 100 200 300
stu[5] 100 201 300
stu[6] 100 200 302
stu[7] 100 201 302
stu[8] 101 200 301
輸出樣例:
3 stu[3] 603 101 201 301
7 stu[7] 603 100 201 302
2 stu[2] 602 101 201 300
8 stu[8] 602 101 200 301
6 stu[6] 602 100 200 302
5 stu[5] 601 100 201 300
1 stu[1] 600 100 200 300
4 stu[4] 600 100 200 300
#include<stdio.h>
#define N 1000
struct student{
char name[20];
int id,score1,score2,score3,sum;//C語言中不支持成員函數的寫法,故而定義sum
}stu[N];
void swap(student &a, student &b){
student temp=a; a=b; b=temp;
}
//使用選擇排序對結構體按照總分,score1,score2,score3依次進行降序排序,id升序排序
void selectSort(student *arr, int l, int r){
for(int i=l; i<=r; i++){
int max_id=i;
for(int j=i+1; j<=r; j++){
if(arr[max_id].sum!=arr[j].sum){
if(arr[max_id].sum<arr[j].sum) max_id=j;
}else if(arr[max_id].score1!=arr[j].score1){
if(arr[max_id].score1<arr[j].score1) max_id=j;
}else if(arr[max_id].score2!=arr[j].score2){
if(arr[max_id].score2<arr[j].score2) max_id=j;
}else if(arr[max_id].score3!=arr[j].score3){
if(arr[max_id].score3<arr[j].score3) max_id=j;
}else{
if(arr[max_id].id>arr[j].id) max_id=j;
}
}
if(max_id!=i) swap(arr[max_id], arr[i]);
}
}
int main(){
freopen("data.in", "r", stdin);
int n; scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%s%d%d%d",&stu[i].name,&stu[i].score1,&stu[i].score2,&stu[i].score3);
stu[i].id=i, stu[i].sum=stu[i].score1+stu[i].score2+stu[i].score3;
}
selectSort(stu, 1, n);
for(int i=1; i<=n; i++){
printf("%d %s %d %d %d %d\n",stu[i].id, stu[i].name, stu[i].sum, stu[i].score1, stu[i].score2, stu[i].score3);
}
return 0;
}
5. 結構體指針
#include<stdio.h>
struct student{
char name[20];
int age;
int score1,score2,score3;
}stu[3]={
{"helloA",13,88,99,100},
{"helloB",14,90,99,100},
{"helloC",15,100,100,100}};
int main(){
struct student *pre=stu;//指向首元素的地址,如果是單個變量,可寫為:pre=&stu;
printf("%s %d %d %d %d\n\n",pre->name,pre->age,pre->score1,pre->score2,pre->score3);
pre = &stu[1];
printf("%s %d %d %d %d\n\n",pre->name,pre->age,pre->score1,pre->score2,pre->score3);
pre = stu+2;
printf("%s %d %d %d %d\n\n",pre->name,pre->age,pre->score1,pre->score2,pre->score3);
for(struct student *pre=stu; pre<stu+3; pre++){
printf("%s %d %d %d %d\n",pre->name,pre->age,pre->score1,pre->score2,pre->score3);
}
return 0;
}
6. 鏈表
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct student{
char name[20];
int age;
struct student *next;//指向結構體的指針變量
};
void main1(){//靜態鏈表
struct student a,b,c, *head, *pre;
strcpy(a.name, "helloA"), a.age=13, a.next=&b;
strcpy(b.name, "helloB"), b.age=14, b.next=&c;
strcpy(c.name, "helloC"), c.age=15, c.next=NULL;
head=&a, pre=head;
do{
printf("%s %d\n", pre->name, pre->age);
pre=pre->next;
}while(pre!=NULL);
}
//動態鏈表
struct student *create(void){
struct student *head, *pre,*pre2;
head=pre=(struct student*)malloc(sizeof(struct student));
head->next=NULL, pre->next=NULL;
while(scanf("%s %d", &pre->name,&pre->age)==2){
pre2 = (struct student*)malloc(sizeof(struct student));
pre2->next = NULL;
pre->next = pre2;
pre=pre2;
}
return head;
}
int main(){
freopen("data.in", "r", stdin);
struct student *pre=create();
while(pre->next!=NULL){
printf("%s %d\n", pre->name,pre->age);
pre=pre->next;
}
return 0;
}
7. 共用體類型
1、什么是共用體類型
用同一段內存來存放不同類型的變量,后面的數據會覆蓋之前的數據,使得不同的數據共享同一段內存的結構被稱為共用體。
共用體中的所有成員共用同一段內存(所有成員的起始地址都是一樣的)
共用體定義一般形式
union 共用體名{
成員列表;
}變量列表;
注:
(1)成員列表為定義該共用體的成員,成員定義與普通變量的方式一樣。
(2)成員列表必須用一對花括號括起。
(3)共用體名可以省略
如:
union Data{ //聲明共用體類型
int i;
char ch;
float f;
}a,b,c; //在聲明類型的同時定義變量
或者:union Data a,b,c;
由於共用體類型變量的所有成員都共用一段內存,所以共用體類型變量所占的字節數等於該共用體類型中占用字節數最多的成員所占的字節數。
也就是說,對於上述共用體有:sizeof(a) <= sizeof(float);
2、共用體變量的引用
注:
(1)不能整體引用共用體變量,只能引用其成員。引用的格式:共用體變量名.成員名
printf("%d %c %f", a.i, a.ch, a.f); //每一瞬時只能存放一個成員
(2)可以對共用體變量初始化,但是初始化列表只能有一個常量。
union Data a = {1};//正確,對第一個成員初始化
union Data a = {.ch='j'};//正確,C99允許對指定成員初始化
(3)共用體中存放的是最后一次賦值的元素。
(4)共用體變量的地址和它 各個成員的地址都是同一地址。
(5)不能對共用體變量名賦值,C99允許同類型的共用體變量互相賦值。
(6) C99允許共用體變量作為函數參數,(以前只能使用指向共用體變量的指針作函數參數)。
(7)共用體可以出現在結構體類型定義中,也可以定義共用體數組。
反之結構體也可以出現在共用體類型定義中,數組也可以作為共用體的成員。
#include<stdio.h>
#define N 1000
struct {
char name[20];
char job;
union{
int clas;
char position[10];
}category;
}per[N];
int main(){
int n; scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%s %c", &per[i].name,&per[i].job);
if(per[i].job=='s'){
scanf("%d", &per[i].category.clas);//是學生,輸入班級
}else if(per[i].job=='t'){
scanf("%s", &per[i].category.position);//是老師,輸入職務
}
}
for(int i=0; i<n; i++){
printf("%s %c ", per[i].name, per[i].job);
if(per[i].job=='s'){
printf("%d\n", per[i].category.clas);//是學生,輸入班級
}else if(per[i].job=='t'){
printf("%s\n", per[i].category.position);//是老師,輸入職務
}
}
return 0;
}
8. 枚舉類型
聲明枚舉類型的一般形式
enum 枚舉名 {枚舉元素列表};
//枚舉類型 WeekDay的聲明 ,{}中的為枚舉元素或枚舉常量
enum WeekDay {Sunday,Monday,Tuesday,Wendnesday,Thursday,Friday,Saturday};
//枚舉變量的定義
enum WeekDay workday,weekend; //定義 workday,weekend為枚舉變量
//也可以不聲明枚舉類型,直接定義枚舉變量
enum {Sunday,Monday,Tuesday,Wendnesday,Thursday,Friday,Saturday} workday,weekend;
每一個枚舉元素都代表一個整數,C語言編譯按定義時的順序默認他們的值為: 0,1,2,3,4,5...
如果有賦值語句:workday=mon; 相當於 workday=1;
但是不能對枚舉元素進行賦值,除非是定義時的人為指定,如:
enum WeekDay {Sunday=7,Monday=1,Tuesday,Wendnesday,Thursday,Friday,Saturday};
指定枚舉常量后,以后的順序會依次+1,所以 Saturday=6
由於指定枚舉類型變量的值是整數,所以C99把枚舉類型也作為整型數據的一種,即用戶自定義的整數類型。
9. typedef聲明新類型名
C語言允許用戶使用 typedef 關鍵字來定義自己習慣的數據類型名稱,來替代系統默認的基本類型名稱、數組類型名稱、指針類型名稱與用戶自定義的結構型名稱、共用型名稱、枚舉型名稱等。一旦用戶在程序中定義了自己的數據類型名稱,就可以在該程序中用自己的數據類型名稱來定義變量的類型、數組的類型、指針變量的類型與函數的類型等。
例如,C 語言在 C99 之前並未提供布爾類型,但我們可以使用 typedef 關鍵字來定義一個簡單的布爾類型,如下面的代碼所示:
// 取別名 bool , 其本質 int
typedef int bool;
// 宏定義,預編譯指令
#define true 1
#define false 0
#define 是在預編譯時處理的,它只能做簡單的字符串替換。
typedef 是在編譯階段處理的,實際上是為特定的類型指定了一個同義字。
typedef 的作用
(1)為基本數據類型定義新的類型名
(2)為自定義數據類型(結構體、共用體和枚舉類型)定義簡潔的類型名稱
(3)為數組定義簡潔的類型名稱
(4)為指針定義簡潔的類型名稱
#include<stdio.h>
#include<limits.h>
#define true 1
#define false 0
#define M 100 // 字符串替換,不開辟內存
const int N = 10; // C語言中表示修飾為只讀變量 C++中表示常量
typedef int bool;
typedef long long ll;
typedef unsigned long long ull;
typedef struct student{
char name[20];
int age;
}Stu;
Stu stu[20]; // 使用新類型定義結構體
int main(){
bool f1=true, f2=false;
printf("%d %d\n", f1, f2);
ll a = LLONG_MAX, b=LLONG_MAX;
ull c = (ull)a+b;
printf("a = %lld\n", a);
printf("b = %lld\n", b);
printf("c = %llu\n", c);
return 0;
}
