一.結構體:
1.類型定義:
struct 結構體名 {數據類型1 成員變量1;數據類型2 成員變量2;數據類型3 成員變量3;...
};struct student {char name[32];char sex;int age;int score;
};
2.結構體變量定義:
????????存儲類型 數據類型 變量名;
3.結構體元素初始化:
1.全部初始化:? ? ??
struct student stu = {"zhangsan", 'm', 18, 90};
2.局部初始化:
struct student stu = {.name = {"zhangsan"}, //沒有給定初值的元素都被賦值為0.score = 90,
};
4.結構體成員訪問:
????????. :結構體變量類型訪問成員變量 .
? ??? -> :結構體指針類型訪問成員變量 ->
????????結構體訪問成員變量最終的類型由成員變量的類型決定。
例:
#include <stdio.h>struct datetime {struct date {int year;int mon;int day;}d;struct time {int hour;int min;int sec;}t;
};struct student {char name[32];char sex;int age;int score;
};int main(void)
{struct datetime dt = {{2025, 7, 29}, {15, 9, 30},};struct datetime dt1 = {.t = {.hour = 15,.min = 10,},};struct student stu = {"zhangsan", 'm', 19, 100};struct student s = {.name = "lisi",.score = 80,};struct student *pstu = NULL;struct datetime *pdt = NULL;printf("%04d-%02d-%02d\n", dt.d.year, dt.d.mon, dt.d.day); // 輸出dt的日期和時間printf("%02d:%02d:%02d\n", dt.t.hour, dt.t.min, dt.t.sec);printf("%04d-%02d-%02d\n", dt1.d.year, dt1.d.mon, dt1.d.day); // 輸出dt1的日期和時間printf("%02d:%02d:%02d\n", dt1.t.hour, dt1.t.min, dt1.t.sec);printf("姓名:%s\n", stu.name); // 輸出stu的信息printf("性別:%c\n", stu.sex);printf("年齡:%d\n", stu.age);printf("成績:%d\n", stu.score);pstu = &s;printf("姓名:%s\n", pstu->name); // 通過指針輸出s的信息printf("性別:%c\n", pstu->sex);printf("年齡:%d\n", pstu->age);printf("成績:%d\n", pstu->score);pdt = &dt;printf("%04d-%02d-%02d %02d:%02d:%02d\n", pdt->d.year, pdt->d.mon, pdt->d.day, pdt->t.hour, pdt->t.min, pdt->t.sec); // 通過指針輸出dt的完整信息return 0;
}
從終端接收:
#include <stdio.h>
#include <string.h>struct student
{char name[32];char sex;int age;int score;
};int main(void)
{ struct student s;struct student *pstu = NULL;char str[32] = {0};char tmpsex = 0;int tmpage = 0;int tmpscore = 0;pstu = &s;gets(pstu->name);scanf(" %c", &pstu->sex);scanf("%d", &pstu->age);scanf("%d", &pstu->score);printf("姓名:%s\n", s.name);printf("性別:%c\n", s.sex);printf("年齡:%d\n", s.age);printf("成績:%d\n", s.score);return 0;
}
5.結構體的存儲:
內存對齊:????????
struct student {char name[32];char sex;int age;int score; //32(name) + 1(sex) + 3(填充) + 4(age) + 4(score) = 44 字節
};
????????結構體成員必須存放在內存地址為自身類型長度整數倍的內存單元中,
????????結構體的大小必須為自身最大類型長度的整數倍。
6.結構體傳參:
1.傳值:
void fun(struct student tmp);
2.傳地址:
void fun(struct student *ptmp);
#include <stdio.h>
#include <string.h>struct student {char name[32];char sex;int age;int score;
}; struct student GetStuInfo(void)
{struct student tmp;gets(tmp.name);scanf(" %c", &tmp.sex);scanf("%d", &tmp.age);scanf("%d", &tmp.score);return tmp;
}int PutStuInfo(struct student tmp)
{ printf("姓名:%s\n", tmp.name);printf("性別:%c\n", tmp.sex);printf("年齡:%d\n", tmp.age);printf("成績:%d\n", tmp.score);return 0;
}void GetStuInfoByPoint(struct student *pstu)
{gets(pstu->name);scanf(" %c", &pstu->sex);scanf("%d", &pstu->age); scanf("%d", &pstu->score);return;
}void PutStuInfoByPoint(struct student *pstu)
{printf("姓名:%s\n", pstu->name);printf("性別:%c\n", pstu->sex);printf("年齡:%d\n", pstu->age);printf("成績:%d\n", pstu->score);return;
}int main(void)
{struct student ret;memset(&ret, 0, sizeof(ret)); //初始化,內存置位GetStuInfoByPoint(&ret);PutStuInfoByPoint(&ret);#if 0ret = GetStuInfo();PutStuInfo(ret);
#endifreturn 0;
}
????????傳地址更好,因為實參將8字節拷貝給形參,避免結構體大空間的拷貝。
7.結構體數組:
????????格式:數據類型 數組名[元素個數];
8.結構體數組初始化:
struct student s[3] = {{"zhangsan", 'm', 19, 100},{"lisi", 'f', 18, 90},{"wanger", 'm', 19, 60},
};struct student s[3] = {[1] = {.name = "zhangsan",.score = 90,},
};
9.結構體數組傳參:
int fun(struct student *pstu, int len);
二.共用體:
1.共用體也稱為聯合體:
????????共用體每個成員變量的空間共享的,
????????結構體每個成員變量的空間是獨立的,
????????多用于函數傳參使用。
2.數據類型定義:
union 共用體名 {數據類型1 成員變量1;數據類型2 成員變量2;數據類型3 成員變量3;...
};
3.使用共用體判斷內存大小端:
????????內存低地址存放低數據位,內存高地址存放高數據位,內存小端,
????????內存低地址存放高數據位,內存高地址存放低數據位,內存大端。
#include <stdio.h>union s {char a;int b;
};int main(void)
{union s s1;s1.b = 1;if(s1.a){printf("小端存儲\n");}else {printf("大端存儲\n");}#if 0int Num = 0;char *p = NULL;Num = 0x11223344;p = (char *)&Num;if (0x11 == *p){printf("大端存儲\n");}else if (0x44 == *p){printf("小端存儲\n");}
#endifreturn 0;
}
三.枚舉:
1. 枚舉定義一些枚舉常量。
2.定義形式:
enum 枚舉類型 {常量1,常量2,常量3,...
};
3.特性:
????????枚舉常量均為int類型,且第一個枚舉常量的值默認為0,后續枚舉常量的值總是前一個常量的
值+1,
????????枚舉常量可以在定義時被賦值。
例:
#include <stdio.h>enum weekday {MONDAY = 1,TUESDAY,WEDNESDAY,THURDAY,FRIDAY,SATURSDAY,SUNDAY,
};int main(void)
{enum weekday day;printf("請輸入今天是周幾:\n");scanf("%d", (int *)&day);switch (day){case MONDAY:printf("尾號1和6限行\n");break;case TUESDAY:printf("尾號2和7限行\n");break;case WEDNESDAY:printf("尾號3和8限行\n");break;case THURDAY:printf("尾號4和9限行\n");break;case FRIDAY:printf("尾號5和0限行\n");break;case SATURSDAY:case SUNDAY:printf("不限行\n");}return 0;
}
四.練習:
1.計算并顯示一個給定日期在當年是第幾天,以及該年還剩余多少天:
#include <stdio.h>struct date {int year;int mon;int day;
};int GetDate(struct date *pday)
{scanf("%d-%d-%d", &pday->year, &pday->mon, &pday->day);return 0;
}int IsLeepYear(int tmpyear)
{if (((0 == tmpyear % 4) && (tmpyear % 100 != 0)) || (0 == tmpyear % 400)){return 1;}return 0;
}int GetDayOfYear(struct date *pday)
{int i = 0;int sum = 0;for (i = 1; i < pday->mon; i++){switch (i){case 1:case 3:case 5:case 7:case 8:case 10:case 12:sum += 31;break;case 4:case 6:case 9:case 11:sum += 30;break;case 2: sum += (IsLeepYear(pday->year) ? 29 : 28);}}sum += pday->day;return sum;
}int GetLeftDayOfYear(struct date *pday)
{int total = 0;if (IsLeepYear(pday->year)){total = 366;}else {total = 365;}return total - GetDayOfYear(pday);
}int main(void)
{struct date day;int cnt = 0;GetDate(&day);cnt = GetDayOfYear(&day);printf("%04d-%02d-%02d為該年的第%d天\n", day.year, day.mon, day.day, cnt);cnt = GetLeftDayOfYear(&day);printf("該年剩余%d天\n", cnt);return 0;
}
2.單詞順序反轉,并保持內部的順序不變(不使用逆序算法):
#include <stdio.h>
#include <string.h>int strswap(char *phead, char *ptail)
{char tmp = 0;while (phead < ptail){tmp = *phead;*phead = *ptail;*ptail = tmp;phead++;ptail--;}return 0;
}int wordswap(char *pstr)
{char *pstart = NULL;char *pend = NULL;//先對整體交換strswap(pstr, pstr+strlen(pstr)-1);pstart = pstr;while (1){pend = strchr(pstart, ' '); //使用strchr找到下一個空格if (pend != NULL){strswap(pstart, pend-1); //如果找到了空格,就反轉這個單詞}else {strswap(pstart, pstart + strlen(pstart) - 1);break;}pstart = pend + 1;}#if 0pstart = pstr;pend = pstart;while (*pend != '\0'){pend = pstart;while (*pend != '\0' && *pend != ' '){pend++;}strswap(pstart, pend-1);pstart = pend + 1; //合法但危險}
#endifreturn 0;
}int main(void)
{char str[256] = {0};gets(str);wordswap(str);printf("str = %s\n", str);return 0;
}
3.學生信息錄入 + 輸出:
#include <stdio.h>struct student {char name[32];char sex;int age;int score;
};int GetAllStuInfo(struct student *pstu, int len)
{int i = 0;int n = 0;printf("請輸入學生個數:\n");scanf("%d", &n);getchar(); // 讀取掉輸入個數后的回車,避免后續 gets 被跳過for (i = 0; i < n; i++){gets(pstu->name);scanf(" %c", &pstu->sex);scanf("%d", &pstu->age);scanf("%d", &pstu->score);pstu++;
#if 0gets((pstu+i)->name);scanf(" %c", &(pstu+i)->sex);scanf("%d", &(pstu+i)->age);scanf("%d", &(pstu+i)->score);// gets(pstu[i].name); //\n會導致后續輸入亂掉scanf("%s", pstu[i].name);scanf(" %c", &pstu[i].sex);scanf("%d", &pstu[i].age);scanf("%d", &pstu[i].score);
#endifgetchar();}return n;
}int PutAllStuInfo(struct student *pstu, int len)
{int i = 0;for (i = 0; i < len; i++){printf("姓名:%s\n", pstu[i].name);printf("性別:%c\n", pstu[i].sex);printf("年齡:%d\n", pstu[i].age);printf("成績:%d\n", pstu[i].score);}return 0;
}int main(void)
{struct student s[100]; // 最多int curlen = 0; // 實際curlen = GetAllStuInfo(s, 100);PutAllStuInfo(s, curlen); // 接多少輸出多少return 0;
}