前言:設計程序時,選擇一種合適的方式表達數據很重要。很多情況下,簡單的變量甚至數組還不夠。C語言提供了結構變量,該數據類型可以包含多個基本類型及數組類型,而且還能保持各個類型獨立,滿足程序對複雜數據類型的需求。
一、聲明結構的形式
//(1)類型1
struct point{ //point 爲結構標記,可以看成結構類型名
int x;
int y;
};
struct point p1,p2;// struct point 類比於int,p1,p2爲struct point類型的結構變量
//(2)
struct{
int x;
int y;
}p1,p2; //無結構標記point,可以看成沒有結構類型名
//(3)
struct point{
int x;
int y;
}p1,p2; //是類型(1)的簡化模式
二、結構成員(與數組的區別)及結構運算
1、 結構和數組有點像:
-
數組用[ ]運算符和下標訪問其成員:a[0] = 10;
-
結構用.運算符和名字訪問其成員:p1.x;
注:.比&優先級高,所以&p1.x=&(p1.x);
2、結構運算
- 要訪問整個結構,直接用結構變量的名字;
- 對於整個結構,可以做賦值,取地址,也可以傳遞給函數參數;
p1 = (struct point){5,10};//相當於p1.x=5;p1.y=10;
p1 = p2; //相當於p1.x = p2.x;p1.y=p2.y;
3、結構指針
和數組不同,結構變量的名字並不是結構變量的地址,
必須使用&運算符;
struct date *pDate = &today;
三、結構與函數
1、結構作爲函數參數
int numberofDays(struct date d)//實現函數在文章最後的程序段裏
- 整個結構可以作爲參數的值傳入函數;
- 這個時候是在函數內創建一個結構變量,並複製調用者的結構的值;
- 也可以返回一個結構;(與數組完全不同)
2、結構指針作爲參數
struct date{
int month;
int day;
int year;
}myday;
struct date *p = &myday; //把myday的地址賦給p
(*p).month = 12;
p->month = 12; //與上面表達方式一樣,更方便
//用->表示指針所指的結構變量中的成員
四、結構數組與結構中的結構
1、結構數組
struct date dates[100];
struct date dates[] = {
{4,5,2005},{2,4,2005}};//初始化
2、結構中的結構
struct point{
int x;
int y;
};
struct rectangle{
struct point pt1;
struct point pt2;
};
如果有變量struct rectangle r;
可以有:r.pt1.x.、r.pt2.x;
如果有變量定義:
struct rectangle r,*rp;
rp = &r;
那麼一下四種形式等價:
r.pt1.x
r->pt1.x
(r.pt1).x
(rp->pt1).x
//注意沒有rp->pt1->x,pt1不是指針
五、自定義數據類型(typedef)
C語言提供了一個叫typedef的功能來聲明一個已有的數據類型的新名字;
如:typedef int length;
使得length成爲int類型的新名字;
這樣,length就可以代替int來定義變量和聲明函數;
作用:
- 新的名字是某種類型的別名;
- 改善了程序的可讀性;
typedef long int64_t;//重載已有類型名字,新名字具有可移植性
typedef struct ADate{
int month;
int day;
int year;
}Date; //簡化了複雜的名字,用Date可以替換struct ADate;
六、附錄練習程序:
/* 結構體學習1,結構體初始化 */
#include<stdio.h>
struct date{
int year;
int month;
int day
};
int main(int argc, char const *argv)
{
struct date today = {2020,02,18};
struct date thismonth = {.month = 02, .year = 2020
};
printf("Today's date is %d-%d-%d.\n'",
today.year,today.month,today.day);
printf("This month is %i-%i-%i/.\n",
thismonth.year,thismonth.month,thismonth.day);
return 0;
}
/*結構體練習2,結構體作爲函數參數,
該程序爲一個輸出年月日的程序,包含了閏年的判斷函數
結構體包含了年月日三個成員*/
#include<stdio.h>
#include<stdbool.h>
struct date{
int month;
int day;
int year;
};
bool isleap(struct date d); //聲明判斷閏年函數,參數爲結構體
int numberofDays(struct date d); //判斷每個月多少天的函數
int main(int argc,char const *argv[])
{
struct date today,tomorrow;
printf("Enter today's date (mm dd yyyy):");
scanf("%i %i %i",&today.month, &today.day, &today.year);
if(today.day != numberofDays(today)){
tomorrow.day = today.day + 1;
tomorrow.month = today.month;
tomorrow.year = today.year;
}else if( today.month == 12){
tomorrow.day = 1;
tomorrow.month = 1;
tomorrow.year = today.year + 1;
}else{
tomorrow.day = 1;
tomorrow.month = today.month + 1;
tomorrow.year = today.year;
}
printf("Tomorrow's date is %i-%i-%i.\n",
tomorrow.year,tomorrow.month,tomorrow.day);
return 0;
}
int numberofDays(struct date d)
{
int days;
const int daysPerMonth[12] = {31, 28 ,31 ,30 ,31 ,30 ,31 ,31 ,30 ,31 ,30 , 31};
if( d.month == 2 && isleap(d))
days = 29;
else
days = daysPerMonth[d.month-1];
return days;
}
bool isleap(struct date d) //這裏函數類型爲bool型,爲真返回true(1),爲假返回0;
{
bool leap = false;
if(( d.year %4 == 0 && d.year %100 != 0) || d.year % 400 == 0) //四年一潤,百年不潤,四百年再潤
leap = true;
return leap;
}
/* 結構體練習3,嘗試編寫一個輸入函數,能夠一次獲得結構體所有參數 */
#include<stdio.h>
struct point{
int x;
int y;
};
struct point getStruct(void); //相當於封裝一個輸入函數,不需要每一次輸入該結構都要分好幾個成員輸入
void output(struct point); // 同理封裝一個輸出函數
int main(int argc, char const *argv[])
{
struct point y = {0,0};
y = getStruct();
output(y);
}
struct point getStruct(void) //這裏的void表示該函數沒有傳入值
{
struct point p;
scanf("%d",&p.x);
scanf("%d",&p.y);
printf("%d, %d\n",p.x,p.y);
return p;
}
void output(struct point p) //這裏的void表示該函數沒有返回值
{
printf("%d, %d\n ",p.x,p.y);
}
/* 結構體練習4,結構指針作爲參數重寫結構輸入函數 */
//直接通過結構指針操作函數值效率更高,避免傳入函數時要重新創建複製體的問題
#include<stdio.h>
struct point{
int x;
int y;
};
struct point* getStruct(struct point*);
void output(struct point);
void print(const struct point *p);
int main(int argc, char const *argv[])
{
struct point y ={0,0};
getStruct(&y);
output(y);
print(getStruct(&y));
return 0;
}
struct point* getStruct(struct point* p)
{
scanf("%d",&p->x); //->表示指針所指的結構變量中的成員
scanf("%d",&p->y);
printf("%d,%d\n",p->x,p->y);
return p;
}
void output(struct point p)
{
printf("%d,%d\n",p.x,p.y);
}
void print(const struct point *p)
{
printf("%d,%d\n",p->x,p->y);
}
/* 結構體練習6,結構中的結構 */
#include<stdio.h>
struct point{
int x;
int y;
};
struct rectangle{
struct point p1;
struct point p2;
};
void printRect( struct rectangle r){
printf("<%d,%d> to <%d,%d>\n",r.p1.x,r.p2.y,r.p2.x,r.p2.y);
}
int main(int argc, const char *argv[])
{
int i;
struct rectangle rects[] = {
{{1,2},{3,4}},
{{5,6},{7,8}}
}; //初始化了兩個rectangle結構
for(i=0; i<2; i++){
printRect(rects[i]);
}
return 0;
}
/* 結構數組練習 */
#include<stdio.h>
struct time{
int hour;
int minutes;
int seconds;
};
struct time timeUpdate(struct time );
int main(void)
{
//聲明並初始化一個結構數組
struct time testTimes[5] = {
{11,59,59},{12,0,0},{1,29,59},{23,59,59},{19,12,27}
};
int i;
for( i=0; i<5; i++){
printf("Time is %.2i:%.2i:%.2i\n",
testTimes[i].hour,testTimes[i].minutes,testTimes[i].seconds);
testTimes[i] = timeUpdate(testTimes[i]);
printf("One second later it is %.2i:%.2i:%.2i\n",
testTimes[i].hour,testTimes[i].minutes,testTimes[i].seconds);
}
return 0;
}
struct time timeUpdate(struct time now) //一個實時更新下一秒的函數
{
++now.seconds;
if(now.seconds == 60){
now.seconds = 0;
++now.minutes;
} if(now.minutes == 60){
now.minutes = 0;
++now.hour;
} if(now.hour == 24){
now.hour = 0;
}
return now;
}
The end;