指针数组和结构体嵌套

一维数组名

除了两种情况外一维数组的名字都是数组的第一个元素的指针

1 sizeof统计数组长度,返回的是数组长度的大小

2 对数组名取地址,得到的是一个数组指针,步长为整个数组大小

 

数组名是一个指针常量,指向是不可变的

数组索引下标可以为负数

数组指针的定义方式

typedef int(自定义类型)[大小]

是一个数组指针类型

typedef int(*自定义类型)[大小]

定义的是一个数组指针的指针

int (*p)[5]

 1 //数组指针相当于把一个数组当做一个变量,类似于int float之类的来处理
 2 #define _CRT_SECURE_NO_WARNINGS
 3 #include<stdio.h>
 4 //第一种通过typedef来定义一个别名来表示数组类型变量
 5 void test01()
 6 {
 7     int a[5] = { 1,2,3,4,5 };
 8     typedef int(ARRARY_TYPE)[5];//这里就相当于把ARRARY_TYPE作为一个类型
 9     //可以和int之类的正常来申明了处理
10     ARRARY_TYPE* b = &a;//后面的操作就可以类似的看作int等类型变量来处理
11     //这里相当于申请了一个ARRAY_TYPE类型的指针赋值为ARRARY_TYPE类型的a
12     for (int i = 0; i < 5; i++)
13     {
14         printf("%d\n", (*b)[i]);//这里的*b表示对b进行获取内容后得到的其实是a数组的首地址的内容
15         //然后可以把*b看成a再用正常数组来处理
16     }
17 }
18 
19 //通过typedef来定义别名指针来表示数组指针
20 void test02()
21 {
22     int a[5] = { 1,2,3,4,5 };
23     typedef int(*MY_TYPE)[5];//这里表示定义的是一个指针类型的类型
24     //类似于 typedef int* aaaa那么aaa就是一个定义的int *的指针类型来处理
25     MY_TYPE b = &a;//这里的b已经是一个指针了
26     for (int i = 0; i < 5; i++)
27     {
28         printf("%d\n", (*b)[i]);//这里和前面是一样的
29     }
30 }
31 //第三种方式直接用指针来处理
32 void test03()
33 {
34     int a[5] = { 1,2,3,4,5 };
35     int(*p)[5] = &a;//这里就相当于一一对应来处理,用同样的指针数组类型
36     //来申明p指针对应a的地址来处理
37     for (int i = 0; i < 5; i++)
38     {
39         printf("%d\n", (*p)[i]);
40     }
41 }
42 
43 void main(void)
44 {
45     //test01();
46     //test02();
47     test03();
48 }//数组指针相当于把一个数组当做一个变量,类似于int float之类的来处理
49 #define _CRT_SECURE_NO_WARNINGS
50 #include<stdio.h>
51 //第一种通过typedef来定义一个别名来表示数组类型变量
52 void test01()
53 {
54     int a[5] = { 1,2,3,4,5 };
55     typedef int(ARRARY_TYPE)[5];//这里就相当于把ARRARY_TYPE作为一个类型
56     //可以和int之类的正常来申明了处理
57     ARRARY_TYPE* b = &a;//后面的操作就可以类似的看作int等类型变量来处理
58     //这里相当于申请了一个ARRAY_TYPE类型的指针赋值为ARRARY_TYPE类型的a
59     for (int i = 0; i < 5; i++)
60     {
61         printf("%d\n", (*b)[i]);//这里的*b表示对b进行获取内容后得到的其实是a数组的首地址的内容
62         //然后可以把*b看成a再用正常数组来处理
63     }
64 }
65 
66 //通过typedef来定义别名指针来表示数组指针
67 void test02()
68 {
69     int a[5] = { 1,2,3,4,5 };
70     typedef int(*MY_TYPE)[5];//这里表示定义的是一个指针类型的类型
71     //类似于 typedef int* aaaa那么aaa就是一个定义的int *的指针类型来处理
72     MY_TYPE b = &a;//这里的b已经是一个指针了
73     for (int i = 0; i < 5; i++)
74     {
75         printf("%d\n", (*b)[i]);//这里和前面是一样的
76     }
77 }
78 //第三种方式直接用指针来处理
79 void test03()
80 {
81     int a[5] = { 1,2,3,4,5 };
82     int(*p)[5] = &a;//这里就相当于一一对应来处理,用同样的指针数组类型
83     //来申明p指针对应a的地址来处理
84     for (int i = 0; i < 5; i++)
85     {
86         printf("%d\n", (*p)[i]);
87     }
88 }
89 
90 void main(void)
91 {
92     //test01();
93     //test02();
94     test03();
95 }
View Code

 

二维数组名

二维数组名除了两个特殊情况外是指向第一个一维数组的 数组指针

特殊情况:

sizeof()统计的是二维数组的大小

对数组名取地址返回的是一个二维数组指针,步长为整个数组大小

二维数组做函数参数

(int (*p)[])

(int p[][N])

(int array[N][N])  

 1 //二维数组名做函数参数
 2 #define _CRT_SECURE_NO_WARNINGS
 3 #include<stdio.h>
 4 //第一种情况来表示二维数组做函数参数
 5 void test01(int (*p)[3],int row,int col)//
 6 {
 7     for (int i = 0; i < row; i++)
 8     {
 9         for (size_t j = 0; j < col; j++)
10         {
11             printf("%d ", p[i][j]);
12         }
13         printf("\n");
14     }
15 }
16 void test02(int p[3][3],int row,int col)
17 {
18     for (int i = 0; i < row; i++)
19     {
20         for (size_t j = 0; j < col; j++)
21         {
22             printf("%d ", p[i][j]);
23         }
24         printf("\n");
25     }
26 }
27 void test03(int p[][3],int row,int col)
28 {
29     for (int i = 0; i < row; i++)
30     {
31         for (size_t j = 0; j < col; j++)
32         {
33             printf("%d ", p[i][j]);
34         }
35         printf("\n");
36     }
37 }
38 
39 void main()
40 {
41     int a[3][3] = {
42         {1,2,3},
43         {4,5,6},
44         {7,8,9}
45     };
46     test01(a, 3, 3);
47     test02(a, 3, 3);
48     test03(a, 3, 3);
49 
50 }
View Code

结构体基本概念

typedef

加上typedef可以给结构体起别名

typedef struct test{

}TEST;

不在开始加typdef可以直接给结构体初始化一个变量

struct test{

}test1;

匿名结构体

不给结构体命名,可以直接创建一个结构体变量

struct{

}test1;

在栈和堆上创建结构体

 

 1 //在堆区和栈区创建结构体
 2 #define _CRT_SECURE_NO_WARNINGS
 3 #include<stdio.h>
 4 #include<stdlib.h>
 5 #include<string.h>
 6 //在栈区创建结构体
 7 void test01() 
 8 {
 9     struct Link {
10         int a;
11         char b;
12     };
13     struct Link a = { 1,'c' };
14 }
15 //在堆区创建结构体
16 void test02()
17 {
18     struct Link {
19         int a;
20         char b;
21     };
22     struct Link* p = (struct Link*)malloc(sizeof(struct Link));
23     p->a = 1;
24     p->b = 'a';
25 
26     //用完了需要free掉
27     free(p);
28 }
29 
30 void main()
31 {
32     test01();
33     test02();
34 }
View Code

 

结构体深浅拷贝

系统提供一个结构体的直接赋值操作:但是是逐字节操作,连指针地址也会改变

所以当在堆区时如果用直接赋值会导致释放的时候产生问题

 

 

结构体嵌套一级指针

 1 //结构体嵌套指针数组
 2 #define _CRT_SECURE_NO_WARNINGS
 3 #include<stdio.h>
 4 #include<stdlib.h>
 5 struct Person
 6 {
 7     char* name;
 8     int age;
 9 };
10 struct Person** Space()
11 {
12     struct Person** temp = (struct Person **)malloc(sizeof(struct Person*) * 3);
13     for (int i = 0; i < 3; i++)
14     {
15         //创建结构体内存
16         temp[i] = (struct Person *)malloc(sizeof(struct Person));
17         //创建结构体的name字符串内存
18         temp[i]->name = (char *)malloc(sizeof(char) * 64);
19         //给name赋值
20         sprintf(temp[i]->name, "name=%d", i + 1);
21         temp[i]->age = i + 1;
22     }
23     return temp;
24 }
25 void Print_p(struct Person** p)
26 {
27     for (int i = 0; i < 3; i++)
28     {
29         printf("this name=%s", p[i]->name);
30         printf("this age=%d", p[i]->age);
31     }
32 }
33 void Delete(struct Person** p)
34 {
35     for (int i = 0; i < 3; i++)
36     {
37         free(p[i]->name);
38         p[i]->name = NULL;
39         free(p[i]);
40         p[i] = NULL;
41     }
42 }
43 
44 void main()
45 {
46     struct Person** p = NULL;
47     p = Space();
48     Print_p(p);
49     Delete(p);
50     free(p);
51 }
View Code