序言

本章我们将要学习的是一下几个内容

指针与函数 结构体 动态内存分配 算法时间复杂度

指针与函数

我们依旧是拿题来学习这个知识:

设计一个函数,传入两个 int 参数,并交换着两个参数的值

这个程序听起来很简单吧,我们可以直接用一个中间变量来进行传递他们的变量值

1
2
3
4
int temp;
temp = a;
a = b;
b = temp;

正常我们这样写就可以了。

但是如果我们学了指针之后,我们就可以更加方便了

现在我们先把上面的那个代码完整补充一下:

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

void swap(int x,int y) {
int temp;
temp = x;
x = y;
y = temp;
printf("交换后x=%d,y=%d\n",x,y);
}

int main() {
int a = 10;
int b = 20;
swap(a,b);
printf("a=%d,b=%d\n",a,b);
return 0;
}

运行结果:

交换后x=20,y=10

a=10,b=20

我们可以看到一个很奇怪的事情,我们在 main 函数中的第二个 printf 中输出出来的值是没有交换的。

为什么呢?

因为我们传入 swap()中的不是 m 与 n 这两个变量,而是 m 与 n 的变量的值 。所以我们在后面在运行 printf 的时候,m 与 n 的值才会没有变化

现在我们来通过指针来让他的值彻底改变。

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

void swap(int *x,int *y) {
int temp;
temp = *x;
*x = *y;
*y = temp;
printf("交换后x=%d,y=%d\n",*x,*y);
}

int main() {
int a = 10;
int b = 20;
swap(&a,&b);
printf("a=%d,b=%d\n",a,b);
return 0;
}

我们知道指针变量是用来保存某个数据在内存中的地址,那我们用取地址符去传入一个 a 和 b 的地址,那么我们的指针变量就可以直接根据地址去更改 a 和 b 的值了。

我们在大脑中要有一个快速的转换,在函数里面看到了指针就得想到地址,想到地址就不得不想到取地址符。

我们可以看看用了指针之后,我们的 swap 函数接收的参数有什么变化。

img

从接收 m 与 n 的值转换成了接收 m 与 n 的地址。

指针与数组

在 C 语言中,指针与数组的关系十分密切。通过数组下标能完成的操作都可以通过指针完成。

一般来说,用指针编写的程序比用数组下标编写的程序执行速度快。

我们通过一个小程序来学习一个小玩意:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main() {
int a[] = {1,2,3,4,5};
int *p;
p = a;

printf("%p\n",a);
printf("%p\n",p);
printf("%d\n",*p);
return 0;
}

输出结果:
00000017db5ff730

00000017db5ff730

1

我们可以看到我们的指针 p 获取的数数组的首地址。我们获取了首地址,那我们也可以获取到数组中的首个元素。

那如果我想要获取 2,3,4,5 该怎么办呢?

一个数组,他们地址肯定是连续的,假设 1 的地址是 101,那么 2 的地址就是 105 然后 109,114.以此类推,我们可以写一个循环,可以使用 sizeof 来算出我们数组中一个数的字节,然后让我们的 p 每次都加这个字节。以此类推就可以了。

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main() {
int a[] = {1,2,3,4,5};
int *p;
p = a;

for (int i = 0; i < sizeof(a)/sizeof(a[0]);i++) {
printf("%d ",*(p+i));
}
return 0;
}

但是有一个很奇怪的一个点啊,这里的 i 是从 0-4 的,然后我们是(p+i),那从感官上来看就像是 101,102,103,104 这样的,但是为什么我们运行出来没有问题?

因为在对指针做算数运算的时候,我们的的程序其实是这样玩的

p = p+1; -> p = p + 1 * 4;

给指针加上一个整数,实际上加的是这个整数和指针数据类型对应字节的乘积。

结构体

结构体本身也是一种数据类型,不过是自己自定义的数据类型。

比如说我想用一种数据类型,来表示一个坐标上的一个点,能表示出来吗?

有人可能会想到我直接设两个变量一个 x 一个 y。这样不行,因为这是两个变量。

我们想要的是一个数据类型,就一个变量就可以完成这件事。这个时候我们就可以使用结构体了

本质上结构体就是一个多个变量的集合。

结构上怎么写:

1
2
3
4
5
6
7
8
9
10
11
12
struct point
{
int x;
int y;
};


struct 结构体名
{
数据类型 变量名;
数据类型 变量名;
};

结构体的初始化与调用

初始化:

1
2
struct 结构体名 结构体名;
struct point p;

调用:

1
2
3
变量名.结构体内部变量名 = 值.
p.x = 10;
p.y = 15;

我们这里把代码完善一下:

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

struct point {
int x;
int y;
};

int main() {
struct point p;
p.x = 5;
p.y = 6;
printf("p.x=%d,p.y=%d\n",p.x,p.y);
return 0;
}

那现在假设我要创建一个数据类型是 student。

那我们在数据类型里面应该包含

  1. stuId
  2. stuName
  3. sex
  4. homeTown
  5. major

ok,那我们现在来完善一下我们这个代码

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>

struct student {
char stuid[20];
char stuName[20];
char sex[5];
char homeTown[50];
char major[20];
} stu;

int main() {
strcpy(stu.stuid,"20230101");
strcpy(stu.stuName,"张三");
strcpy(stu.sex,"男");
strcpy(stu.homeTown,"北京");
strcpy(stu.major,"计算机");
printf("------------------------------\n");
printf("student id=%s\n",stu.stuid);
printf("student name=%s\n",stu.stuName);
printf("student sex=%s\n",stu.sex);
printf("student home=%s\n",stu.homeTown);
printf("student major=%s\n",stu.major);
printf("------------------------------\n");
return 0;
}

我们这里需要注意一下,在传入字符类型的时候,我们需要使用的 strcpy

typedef

给一个数据类型起一个别名。

typedef 数据类型 别名
typedef int zx
那么后续我就可以直接使用 zx 来充当我们这个 zx 了。

但是我觉得很奇怪?我有 int 了我为什么不直接使用 int?而是在去命名为一个 zx,然后再去使用这个 zx 去替代我们的 int 呢?这不是脱裤子放屁吗?

原因是这样的:
每次声明结构体变量的时候,都要写 struct 关键字,这很麻烦,而且逻辑上也很难受,但是我们的 typedef 就可以完美的解决这个问题。

比如说我们看这个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
#include<string.h>

struct point {
int x;
int y;
};

int main() {
struct point stu;
stu.x = 5;
stu.y = 6;
printf("stu.x=%d,stu.y=%d\n",stu.x,stu.y);
return 0;
}

现在我们来看看这个 typedef 的类型定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct 结构体名
{
数据类型 变量名;
数据类型 变量名;
......
}别名;



------------------------------------------------------
typedef struct
{
数据类型 变量名;
数据类型 变量名;
......
}别名;

一旦我们这个 typedef 给这个结构体起了别名的之后,我们写代码就可以直接用这个别名来声明一个变量了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
#include<string.h>
//用typedef
typedef struct {
int x;
int y;
}point;

int main() {
point p;
p.x = 5;
p.y = 6;
printf("stu.x=%d,stu.y=%d\n",p.x,p.y);
return 0;
}