简单理解结构

结构体

功能

  • 为了让一组数据有联系
  • 可以在函数内定义,也可以在函数外面,在外面可以多个函数引用

类型

  • 类型定义
1
2
3
4
struct  结构体名
{
成员列表//由若干成员组成
};
  • 成员定义

类型说明符 成员名;

变量

  • 变量的定义

⑴先定义类型,再定义变量

1
2
3
4
5
6
7
8
struct stu
{
int mun;
char name;
char sex;
float score;
};
struct stu boy1,boy2;

⑵在定义类型的同时定义变量

1
2
3
4
5
6
7
struct
{
int mun;
char name;
char sex;
float score;
}boy1,boy2;

⑶直接定义结构体变量

1
2
3
4
5
6
7
struct  stu
{
int mun;
char name;
char sex;
float score;
}boy1,boy2;
  • 说明:
    • 使用typedef更好定义,也更简洁
    • 的区别就是没有结构体名,直接是变量
    • 一个结构体类型所占的字节并不是所有类型的字节加起来,(使用sizeof(struct 结构体名)可以查看)因为读取效率问题,所以编译器会默认数据对齐
    • 结构体可以嵌套使用
    • 结构体是用户定义的,不是唯一的
    • 只有说明变量系统才会分配空间
    • 结构体指针变量同样可以这样定义

指针

  • 结构体和数组不一样,没有首地址这种说法,要想得到地址必须使用&

结构体的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

struct date
{
int month;
int day;
int year;
};

int main(int argc, char const *argv[])
{
//methods a:
struct date today = {11, 13, 2019};
//methods b:
struct date thismonth = {.month=11, .year=2019};
//%i可以把十六进制和八进制转换位十进制输出
printf("%i-%i-%i\n", today.year, today.month, today.day);
//不给值默认0
printf("%i-%i-%i\n", thismonth.year, thismonth.month, thismonth.day);

return 0;
}

访问成员的运算符

1.成员运算符.

  • 格式:结构体变量名.成员名

  • 功能:访问结构体内的成员

2.指针运算符->

  • 格式:结构体指针变量名->成员名
1
2
3
4
5
6
7
struct str{
int num ; //4
char name[ 20 ] ; //20
char sex ; //1字节对齐后是4
struct date birthday ; //12
float score; //4
}boy1,boy2,*ptr1;
  • 例如
1
printf("%d", boy1.name);

可以输出boy1的成员name

  • 又如
1
printf("%d", ptr1->num);//等价于(*ptr1.num);
  • 说明
    • 如果成员本身是一个结构体的话,则需要引用到具体的成员才行.
    • 结构体必须被初始化才有意义
      • 但我发现定义结构体成员后默认数据是0,指针是NULL
    • .->的优先级比较高,仅次于()

结构体的对齐

  • 主要是为了提高读取效率

  • 四个基本概念:

  1. 数据类型自身的对齐值:对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节
  2. 结构体的自身对齐值:其成员中自身对齐值最大的那个值
  3. 指定对齐值#pragma pack (value)时的指定对齐值value
  4. 数据成员和结构体的有效对齐值:数据成员(数据类型)和结构体的自身对齐值和指定对齐值中小的那个值。(数据成员对齐了数据结构自然也就对齐了)

说明:

  • 有效对齐值N是最终采用的对齐方式,对齐N也就是说存放的原始地址%N=0.
  • 数据结构中的变量都是按定义的先后顺序排放的,第一个数据的起始地址就是数据结构的初始地址.
  • 结构体的变量占用的总长度必须是有效对齐值的整数倍.

例子

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>

main()
{
struct B{
char b;
int a;
short c;
};
printf("%d",sizeof(struct B));
}

运行结果为12

解释:

  • 设初始地址为0x0000

  • char自身对齐值是1,存放地址满足0x0000%1=0

int自身对齐值是4,只能存放0x00040x0007这四个字节,才能满足0x0004%4=0

  • short自身对齐值2,占0x00080x0009,所以0x00000x0009都是B的内容
  • 由于只有10个字节,结构体的有效对齐值是4,因为编译器为了实现结构数据的存取效率,所以自动补充2个字节满足(10+2)%4=0

结构体参数

  • 结构型和传值型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>

struct date
{
int x;
int y;
};

struct date getStruct(void);//返回结构
/*传值*,不改变原来的值*/
// void getStruct(struct date);
void putStruct(struct date);

int main(int argc, char const *argv[])
{
struct date a={0, 0};
a = getStruct();//结构可以赋给结构,数组不可以
putStruct(a);

return 0;
}

// void getStruct(struct date pg){
// scanf("%d", &pg.x);
// scanf("%d", &pg.y);
// printf("pgx=%d,pgy=%d\n", pg.x, pg.y);
// }

struct date getStruct(void){
struct date pg;
scanf("%d", &pg.x);
scanf("%d", &pg.y);
return pg;
}

void putStruct(struct date pp){
printf("x=%d,y=%d\n", pp.x, pp.y);
}

指针型(推荐使用):

K & R:If a large structrue is to be passed to a function, it is generally more efficient to pass a pointer then to copy the whole structrue.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "stdio.h"

struct date
{
int x;
int y;
};

struct date* getStruct(struct date*);
void outputs(const struct date*);
void output(struct date p);

int main(int argc, char const *argv[])
{
struct date a={0, 0};
getStruct(&a);//这个和下面组成一个
output(a);
output(*getStruct(&a));//一句完成上面两句话(指针)
outputs(getStruct(&a));//同上

return 0;
}

struct date* getStruct(struct date *pa){
scanf("%d", &(*pa).x);
scanf("%d", &pa->y);//可以这样简写
printf("pa->x=%d,pa->y=%d\n", pa->x, pa->y);
return pa;
}

void outputs(const struct date* outpa){
printf("outpa->x=%d,outpa->y=%d\n", outpa->x, outpa->y);
}

void output(struct date p){
printf("p.x=%d,p.y=%d\n", p.x, p.y);
}

结构的嵌套

结构数组

1
2
3
4
5
6
7
8
9
10
11
12
13
struct time
{
int hour;
int minute;
int seconds;
}

struct time testTime[5] = {
{01,33,11},
....
}

//testTime[i].hour

结构中的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>

struct point{
int x;
int y;
};

struct rectangle{
struct point p1;
struct point p2;
};

int main(){
struct rectangle r, *rp;
rp = &r;
r = (struct rectangle){{1,2}, {3,4}};//必须进行类型转换才能赋值
/*等价关系:
r.p1.x
rp->p1.x
(r.p1).x
(rp->p1).x
不存在rp->p1->x
*/
printf("%d\n", ((rp->p1.x)+1));//+1表示y
printf("%d\n", (rp->p2.x));
return 0;
}

结构中的结构的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>

struct point{
int x;
int y;
};

struct rectangle{
struct point p1;
struct point p2;
};

int main(int argc, char const *argv[])
{
int i;
struct rectangle rects[] =
{ { {1,2}, {3,4} },{ {5,6}, {7,8} } };
/*
1级大括号是数组rects[]
2级大括号是rectangle {}
3级大括号是p1,p2
可以这样写:
struct rectangle rects[] = {
{{1,2}, {3,4}},
{{5,6}, {7,8}}
};
*/

return 0;
}
作者

manu

发布于

2019-11-04

更新于

2023-01-06

许可协议


:D 一言句子获取中...