结构
C语言里有多种多样的变量类型,比如int, float, double,short等等。但当有时候我们希望有一种自己定义的变量类型,它里面可以包含我们所需要的int,float,double,可以表达比较复杂的数据,但又希望是用一个整体,么就要用到结构了。一个结构就是一个复合的数据类型,它里面可以有各种数据,然后我们可以只用一个变量来表达它们。
1.结构声明
声明结构有三种方式:
第一种:
struct date{
int year;
int month;
int day;
};
注意在末尾大括号处要有一个分号。千万不要漏掉
第二种:
struct date{
int year;
int month;
int day;
}d1,d2;
第一种与第二种很相似,它们都声明了一个名叫date的结构,里面有三个Int类型的变量year,month和day。不同的是第二种声明里面同时定义了两个结构变量d1和d2,d1和d2都是date结构类型的变量。
第三种:
struct{
int year;
int month;
int day;
}mybirthday,dadbirthday;
这是一种无名结构,一般用于短期使用。(不常见)
可以这样理解,d1和d2就是一种新的类型的变量,它们里面都包含着三个Int类型的变量year,month和day。
我们既可以在main函数(或其他函数)里面声明结构类型,也可以在函数外面声明。和本地变量一样,在函数内声明的结构类型只能在这个函数里面使用,所以通常我们在函数外面声明结构类型,这样我们在每个函数里面都可以使用这个结构类型。
2.结构变量
当我们声明了一个结构之后,就可以定义自己的结构变量了。
struct date{
int year;
int month;
int day;
}d1;
这是一种常用的方式,我们在声明结构类型的时候就定义了一个date结构类型的变量d1。
我们也可以在结构声明下面自己定义结构变量,格式是struct 结构名 结构变量
struct date d1;
我们来给他赋值:
d1.year=2005;
d1.month=11;
d1.day=16;
这里我们分别给d1中的year、month、day进行赋值,用到了一个运算符,也就是小数点.
小数点 . 这个运算符用来在结构类型中访问结构成员,格式是结构变量名.结构成员名。
利用这个格式,我们可以对d1中的三个成员分别赋值。
当然,我们还有一种方法来赋值,那就是在定义结构变量的时候顺便做初始化:
struct date d1={2005,11,16};
当然,还可以指定结构成员来赋值:
struct date d1={.year=2005,.month=11,.day=16};
这里可以联想到数组的初始化,与结构变量的初始化比较类似,与数组相同,没有被初始化到的数据为0。比如:
struct date d1={.year=2005,.month=11};
这里我们没有初始化结构成员day,那么在d1中,day值为0。
3.结构运用
3.1结构运算
我们可以直接用结构变量的名字访问整个结构,可以对它做赋值、取地址。
struct date d1={.year=2005,.month=11,.day=16};
d2=d1;
一个结构变量可以直接赋值给另外一个结构变量,这里我们将d1的值直接赋值给d2,此时d2的值就和d1完全相同,即:
d1.year == d2.year
d1.month ==d2.month
d1.day ==d2.day
我们甚至可以给几个数据做一个强制类型转换,然后赋值给一个结构变量:
d3=(struct date){2023,10,1};
这里我们让大括号里的三个数据强制转换成date类型的结构数据并赋值给了d3。
3.3结构做为函数参数
构建一个函数,我们:可以直接将一整个结构变量作为参数的值传进函数内,也可以返回一个结构。
void centry(struct date d){
struct date xyz;
return xyz;
}
注意:在c语言中,当结构作为参数时,其实只是在函数内部新建了一个结构变量,复制调用的结构变量的值,也就是说,当结构作为参数时,在函数里面对结构变量的单元进行修改时,并没有修改函数外那个被调用的结构变量,只是对函数内那个克隆体进行修改了。所以我们一般使用结构指针作为参数,而不是结构本身,这样我们在函数内部直接对指针进行修改,就可以改变指针所指结构变量的数据。不管是效率还是效果,传指针比传结构都要好。
3.2结构指针
由于结构变量的名字不是结构变量的地址,在构建指向结构的指针的时候需要用到取地址符&,这与数组是不一样的。
struct date *p=&d1;
struct date *p1=&d1.year;
struct date *p2=&d1.month;
对于指针p,我们可以使它也指向结构变量中的成员:
(*p).month=11;
p->month=12;
这是两种等价的方式,我们既可以用运算符小数点. 来访问结构成员,与可以使用符号->,就是一个减号和一个大于号,这两个符号组合起来就像一个箭头,很形象地表示出指向结构成员的意思。
利用第二种方式,我们可以很方便地利用指针来修改数据。
3.3复合的结构
结构成员可以是各种各样的东西,可以是数组,可以是结构,根据这个,我们可以做出一些复合的结构。
3.3.1结构数组
struct date ddd[100];
struct date ddd[]={{2005,11,13},{2005,11,14}};
我们可以构建一个结构数组:这里有个名叫ddd的数组,里面有一百个单元,每个单元是一个date类型的结构,也就是说最外面的大括号是说我们在初始化一个数组,里面的大括号是代表结构单元。
3.3.2嵌套结构
struct date{
int year;
int month;
int day;
}d1;
struct time{
int hour;
int minute;
int second;
}t1;
struct DateAndTime{
struct date d1;
struct time t1;
}dt1;
这里我们有三个结构,date、time、 DateAndTime。
其中 DateAndTime就是一个结构中有结构的嵌套结构,每个 DateAndTime类型的结构里面有一个date和一个time结构。
这时,我们的结构变量dt1就有:
dt1.date.year、dt1.time.hour
dt1.date.month、dt1.time.minute
dt1.date.day、dt1.time.second
如果这时再有一个指向dt1的指针*p
那么下面四种形式等价:
dt1.date.year
p->date.year
(dt1.date).year
(p->date).year
不存在有p->date->year,因为date不是指针。
其实那两个括号是多余的。
3.3.3复合结构总说
我们可以做数组结构,可以做结构数组,可以做结构中有结构,还可以做结构中的结构的数组······
总之只有你想不到,没有你做不到···