C语言 day16 | 我的日常分享

C语言 day16

结构体

typedef关键字

给已有类型取个别名

使用步骤:

  1. 先用已有类型定义一个变量
  2. 用别名替换变量名
  3. 在整个表达式前添加 typedef

案例1:给int取个别名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#if 0
int arr[5];//第一步
int ARR_TYPE[5];//第二步
typedef int ARR_TYPE[5];//第三步

//结果:
typedef int ARR_TYPE[5];
#endif
#include<stdio.h>
int main(int argc,char *argv[]){
typedef int ARR_TYPE[5];
printf("sizeof(ARR_TYPE)=%d\n",sizeof(ARR_TYPE));//20 ARR_TYPE就是一个有5个int类型的数据的类型名

ARR_TYPE arr={12,13,14,15,16};
int n=sizeof(arr)/sizeof(arr[0]);
int i=0;
for(i=0;i<n;i++){
printf("%d ",arr[i]);
}
printf("\n");
return 0;
}

运行结果:
图片

案例3:给指针取个别名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#if 0
int *p;//第一步
int *P_TYPE;//第二步
typedef int *P_TYPE;//第三步

//结果:
typedef int *P_TYPE;
#endif
#include<stdio.h>
int main(int argc,char *argv[]){
typedef int *P_TYPE;
int num=10;
P_TYPE p=NULL;
p=&num;
printf("num=%d\n",*p);
return 0;
}

运行结果:
图片

案例4:给函数指针取个别名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
int my_add(int a,int b){
return a+b;
}
int main(int argc,char *argv[]){
int (*p)(int,int)=my_add;
#if 0
int (*p)(int,int);//第一步
int (*FUN_P)(int,int);//第二步
typedef int (*FUN_P)(int,int);//第三步

//结果:
int (*FUN_P)(int,int);
#endif
typedef int (*FUN_P)(int,int);
FUN_P p1=my_add;
printf("%3d\n",p1(3,4));
return 0;
}

运行结果:
图片


给结构体类型取个别名

案例5:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<stdio.h>
struct stu{
int num;
char name[128];
int age;
};
#if 0
//方式1:
typedef struct stu STU;
//方式2:
typedef struct stu{
int num;
char name[128];
int age;
}STU;//此时stu可以去掉 不去掉也可以
#endif
typedef struct stu STU;
int main(int argc,char *argv[]){
STU lucy;
lucy.age=123;
printf("%5d\n",lucy.age);
return 0;
}

运行结果:
图片


结构体指针

案例6:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<stdio.h>
typedef struct stu{
int num;
char name[128];
int age;
}STU;
int main(int argc,char *argv[]){
STU lucy={100,"lucy",18};
STU *p=&lucy;

//printf("%s\n",((char *)p+4));//lucy
printf("num=%d name=%s age=%d\n",lucy.num,lucy.name,lucy.age);
//*p=*&lucy=lucy;//即*p等价于lucy
printf("num=%d name=%s age=%d\n",(*p).num,(*p).name,(*p).age);//. 的优先级最高 *p要加()
printf("num=%d name=%s age=%d\n",p->num,p->name,p->age);
return 0;
}

运行结果:
图片

案例7:从堆区给结构体申请空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
#include<stdlib.h>
typedef struct stu{
int num;
char name[128];
int age;
}STU;
int main(int argc,char *argv[]){
STU *p=NULL;
//申请空间
p=(STU *)calloc(1,sizeof(STU));
//判断是否申请成功
if(NULL == p){
perror("calloc");
return 0;
}

//获取键盘输入
printf("请输入一个学生信息:\n");
scanf("%d%s%d",&p->num,p->name,&(*p).age);

printf("num=%d name=%s age=%d\n",p->num,p->name,p->age);
return 0;
}

运行结果:
图片


结构体指针作为函数的参数

一般指针作为函数参数的目的就函数需要修改指针所指向空间的内容

案例8:

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>
#include<string.h>
typedef struct stu{
int num;
char name[128];
int age;
}STU;
void my_scanf(STU *p){
printf("请输入一个学生信息:\n");
scanf("%d%s%d",&p->num,p->name,&p->age);
return;
}
void my_printf(STU n){
// printf("num=%d name=%s age=%d\n",p->num,p->name,p->age);
printf("num=%d name=%s age=%d\n",n.num,n.name,n.age);
return;
}
int main(int argc,char *argv[]){
STU lucy;
memset(&lucy,0,sizeof(lucy));
STU *p=&lucy;
//获取键盘输入
my_scanf(p);
//打印所有值
my_printf(lucy);
return 0;
}

运行结果:
图片

案例9:

但是对于结构体无论是否函数需要修改结构体变量的值,我们一般参数都传入指针

原因:在32位系统下,指针永远只占4字节,在函数调用时,函数会为形参的指针开辟4字节,但是如果形参不是指针而是一个结构体变量,如果传进来的结构体变量实参非常大,比如200字节,这样就会占用比较大的内存

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
#include<stdio.h>
#include<string.h>
typedef struct stu{
int num;
char name[128];
int age;
}STU;
void my_scanf(STU *p){
printf("请输入一个学生信息:\n");
scanf("%d%s%d",&p->num,p->name,&p->age);
return;
}
void my_printf(const STU *p){
printf("num=%d name=%s age=%d\n",p->num,p->name,p->age);
return;
}
int main(int argc,char *argv[]){
STU lucy;
memset(&lucy,0,sizeof(lucy));
STU *p=&lucy;
//获取键盘输入
my_scanf(p);
//打印所有值
my_printf(p);
return 0;
}

运行结果:
图片

从堆区申请一个结构体数组(分函数实现)

案例10:

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
39
40
41
42
43
44
45
46
#include<stdio.h>
#include<stdlib.h>
typedef struct stu{
int num;
char name[128];
int age;
}STU;
STU *my_apply(int n){
return (STU *)calloc(n,sizeof(STU));
}
void my_scanf(int n,STU *p){
int i=0;
for(i=0;i<n;i++){
printf("请输入第%d个学生信息(共%d个):",i+1,n);
scanf("%d %s %d",&(p+i)->num,(p+i)->name,&(p+i)->age);
}
return;
}
void my_print(int n,STU *p){
int i=0;
for(i=0;i<n;i++){
printf("第%d个学生信息为:num=%d name=%s age=%d\n",i+1,(p+i)->num,(p+i)->name,(p+i)->age);
}
if(p!=NULL){
free(p);
p=NULL;
}
return;
}
int main(int argc,char *argv[]){
STU *arr=NULL;
int n=0;
//申请空间
printf("请输入学生的人数:\n");
scanf("%d",&n);
arr=my_apply(n);
if(NULL == arr){
perror("calloc");
return 0;
}
//获取键盘输入
my_scanf(n,arr);
//打印学生成绩
my_print(n,arr);
return 0;
}

运行结果:
图片

案例10的一个错误:

找了两个小时,人都自闭了
图片

  • 问:上图中函数存在什么问题?
  • 形参为STU *p,但是我们是要赋值给STU *arr,我们传参时传的是arr,我们应该传arr的地址才行,也就是形参是二级指针才行STU **p

所以my_apply要改成这样才行
图片
这时传入的就不是arr了是&arr

因此,给指针变量赋值时,一般用的返回值,不然要传入二级指针比较麻烦

修改好的完整代码:

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
39
40
41
42
43
44
45
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef struct stu {
int num;
char name[128];
int age;
}STU;
void my_apply(int n, STU **p) {
*p = (STU*)calloc(n, sizeof(STU));
if (NULL == *p) {
perror("calloc");
return;
}
return;
}
void my_scanf(int n, STU *p) {
int i = 0;
for (i = 0; i < n; i++) {
printf("请输入第%d个学生信息(共%d个):", i + 1, n);
scanf("%d %s %d", &(p + i)->num, (p + i)->name, &(p + i)->age);
}
return;
}
void my_print(int n, const STU* p) {
int i = 0;
for (i = 0; i < n; i++) {
printf("第%d个学生信息为:num=%d name=%s age=%d\n", i + 1, (p + i)->num, (p + i)->name, (p + i)->age);
}
return;
}
int main(int argc, char* argv[]) {
STU *arr = NULL;
int n = 0;
//申请空间
printf("请输入学生的人数:\n");
scanf("%d", &n);
my_apply(n, &arr);
//获取键盘输入
my_scanf(n, arr);
//打印学生成绩
my_print(n, arr);
return 0;
}