目錄
結構體與共用體
1、結構體(struct)
? ? ? ? (1) 格式與用法
????????(2) 結構體允許嵌套
?(3) 結構體成員初始化
? ? ? ? (4) 指針替換變量
????????(5) 求結構體在內存空間所占字節
2、共用體(union)
????????(1) 格式與概念
????????(2) 應用
3、枚舉類型(enum)
? ? ? ? (1) 格式與概念
? ? ? ? ?(2) 應用
4、typedef 類型
結構體與共用體
1、結構體(struct)
? ? ? ? (1) 格式與用法
? ? ? ? ? ? ? ? 其中,標識符首字母必須大寫(規定),最后一行的花括號后必須加分號“;”。用來定義新的數據類型,存放在聲明部分中。
例如,創建一個 struct Student 數據類型:
struct Student
{int id;char name[20];float score;
};
????????對新的數據類型定義變量的方法:
????????a.? 在末行花括號( } )與分號( ;)中間寫入所需變量的個數及名稱,此時變量為全局變量,存放在靜態區;
????????b. 在主函數中輸入創建數據類型名,在其后輸入變量名來定義變量,此時變量為局部變量,存放在棧區。例如:
? ? ? ? ? ? ? ? ? ? ??? ?
注意:
????????在主函數 main 中,成員類型與 struct 中的成員類型一致。
????????“ .?”為結構體成員運算符,是一級運算符,自左至右。
????????例如:使用創建的 struct Student 數據類型定義變量 s ,定義類型成員內容,完成?“1,zhangsan,97.500000” 的輸出效果
int main(void)
{struct Student s;s.id = 1;strcpy(s.name, "zahngsan");//【1】s.score = 97.5;printf("%d,%s,%f\n", s.id,s.name,s.score);return 0;
}
值得注意的是代碼中的【1】位置,不能寫為“ s.name = "zhangsan" ”,數組不能直接進行賦值。
????????(2) 結構體允許嵌套
創建一個?struct Date 數據類型,結構體成員信息如下:
struct Date
{int year;int month;int day;
};
????????使用 struct Student 與 struct Date 兩種數據類型,完成" 1, zhangsan, 97.500000, 2002-3-12?"的輸出效果
struct Student
{int id;char name[20];float score;struct Date birthday;
};int main(void)
{struct Student s;s.id = 1;strcpy(s.name, "zhangsan");s.score = 97.5;s.birthday.year = 2002;s.birthday.month = 3;s.birthday.day = 12;printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score, s.birthday.year, s.birthday.month, s.birthday.day);return 0;
}
?(3) 結構體成員初始化
? ? ? ? a. 全初始化:結構體初始化與結構體成員聲明順序一致,例如:
struct Student s ={1, "zhangsan", 97.5, {2002,3,12}};
? ? ? ? b. 部分初始化:只對部分成員信息做初始化,要修改的內容之間用逗號隔開
int main(void)
{struct Student s = {.id = 1,.score = 97.5,.birthday = {.year = 2002,.month = 3,}};printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score, s.birthday.year, s.birthday.month, s.birthday.day);return 0;
}
? ? ? ? (4) 指針替換變量
????????通過指針可以對成員進行修改,效率更高,否則只是值傳遞
struct Student *p;
p = &s;
p->id += 10;
printf("%d %f\n", p->id, p->name);
//p->name 也可寫為 (*p).id
//推薦 p->name
????????(5) 求結構體在內存空間所占字節
? ? ? ? 內存對齊:數據總線以數據類型的整數倍都數據(整除)。
? ? ? ? 1、默認按照CPU位數對其(8)字節,最終大小必須是8的整數倍;
? ? ? ? 2、在結構體成員中找到最長成員,最終按照該成員長度對其;
? ? ? ? 3、按照結構體聲明的順序,依次將成員保存到結構體內存中,保存的偏移量 / sizeof(成員類型)。
例如:struct Dome 中的成員數據類型依次為 char(黃)、int(藍)、short(橙),存儲如下,又因為要被最長的整除(int 的4個字節),所有該類型的 sizeof 為12。
????????(6) 應用
????????對于 struct Student 中的成員信息
struct Student
{int id;char name[20];float score;
};
? ? ? ? eg1.?單項輸出(printStudent),全部輸出(printStudents)
void printStudent(struct Student *p)
{printf("%d, %s, %f\n", p->id, p->name, p->score);
}void printStudents(struct Student a[], int len)
{int i;for(i = 0;i < len;++i){printStudent(a + i);}
}
? ? ? ? eg2. 交換(swap),逆序(reverseStudents)
void swap(struct Student *a, struct Student *b)
{struct Student t;t = *a;*a = *b;*b = t;
}void revserseStudents(struct Student *a, int len)
{int i;for(i = 0;i < len / 2;++i){swap(a + i, a + len - i - 1);}
}
? ? ? ? eg3. 采用回調函數按名字長度(namecmp)、按成績(scoreStudent)進行排序(sortStudent)
int namecmp(struct Student *p1, struct Student *p2)
{return strcmp(p1->name, p2->name);
}int scorecmp(struct Student *p1, struct Student *p2)
{if(p1->score > p2->score){return 1;}else if(p1->score == p2->score){return 0;}else{return -1;}
}void sortStudent(struct Student *a, int len, int (*pfn)(struct Student *, struct Student *))
{int i, j;for(i = 0;i < len - 1;++i){for(j = i + 1;j < len;++j){if(pfn(a + i, a + j) > 0){swap(a + i, a + j);}}}
}
????????在主函數中的書寫格式
int main(void)
{struct Student a[3] = {{1, "zhangsan", 97.5},{2, "lisi", 98},{3, "wanghu", 95}};int len = sizeof(a) / sizeof(*a);sortStudent(a, len, namecmp);printStudents(a, len);return 0;
}
* 結構體之間不能進行比較排序,但結構體成員之間可以進行比較排序。?
2、共用體(union)
????????(1) 格式與概念
? ? ? ??其中,共用體名滿足標識符要求,且首字母要大寫,共用體成員的內存公用,該類型代碼存放在聲明中,
????????創建 union Demo 數據類型,說明共用體成員的內存是共用的
union Demo
{int i;short s;char c;
};
int main(void)
{ union Demo d;d.i = 1000;d.s = 100;d.c = 10;printf("%u\n", sizeof(d));//輸出結果為 4printf("%d\n", d.i);//輸出結果為 10return 0;
}
?????????說明:內存共用并且會進行覆蓋,i 為int型占4個字節,short占2個字節,char占1個字節,相當于int 先占了第一二三四個格子,short 占第一二個格子,char占第一個格子,覆蓋到最后只剩 char 的一個格子,輸出。?
? ? ? ? 可以運用指針作為類型變量
int main(void)
{union Demo *p;p = &d;printf("%p %p %p\n", &d.i, &d.s, &d.c); return 0;
}
????????(2) 應用
????????用來判斷程序大小端存取
union Demo
{int i;char c;
};int main(void)
{union Demo d;d.i = 1;if(d.c == 1){puts("little");}else{puts("big");}return 0;
}
3、枚舉類型(enum)
? ? ? ? (1) 格式與概念
????????枚舉類型(enum),用來自定義一個數據類型,并將常參放入其中。
? ? ? ? 一般格式為:
? ? ? ?
? ? ? ? 其中,標識符首字母依舊要大寫,該類型的所有可能取值稱為“枚舉類型常量”,各取值之間用逗號“,”隔開,最后一個取值后面不需要加任何東西,花括號后的分號“;”不能省略。也可以對其輸出變量(eg1. 中的 w )進行偏移(加法)。例如:
????????創建 enum Week 類型,并將 Week 的所有可能放入其中,并對?w 的后一項進行輸出(可以用 “%d” 進行輸出),輸出的值為變量 w 在枚舉常量的位置,也可以對常量進行賦值,但不能重復(例如下圖 Tue=7)
enum Week
{Sun, Mon, Tue = 7, Wes, Thu, Fri, Sat
};int main(void)
{enum Week w;w = Sun;printf("%d\n", w + 1);//輸出為 Monreturn 0;
}
? ? ? ? ?(2) 應用
????????該類型可以做 switch 函數后面的表達式,例如:(可自行補充其他 case 情況)
enum Week
{Sun, Mon, Tue, Wes, Thu, Fri, Sat
};int main(void)
{enum Week w;switch(w){case Sun:puts("lol");break;case Mon:case Tue:puts("study");break;default:break;}return 0;
}
4、typedef 類型
? ? ? ? 將已有類型的類型名換個名字,在全局區起名,將變量名變為類型的類型名。在全局區起名。可以在數據類型(int、char、short等后加,也可以在struct、union、enum后加),類型名可以是一個標識符,也可以是一個數組,例如:
typedef int INT;
typedef int ARRAY[10];int main(void)
{int i;ARRAY a;printf("%lu\n", sizeof(a));return 0;
}
????????也可以運用指針作為類型名,例如:
typedef struct Demo
{int i;short s;char c;
}Demo, *PDEMO;int main(void)
{Demo d;PDEMO p;p = &d;return 0;
}
【END】
、