前言:设计程序时,选择一种合适的方式表达数据很重要。很多情况下,简单的变量甚至数组还不够。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;