逃不掉的语法小技巧 指针
指针是 C 语言的核心技巧,通过指针,我们可以实现很多高级功能,比如动态内存分配、函数指针、回调函数等等。但是指针也是 C 语言中最容易出错的地方,因为指针的操作非常复杂,一不小心就会出错。本文将介绍一些指针的语法小技巧,帮助大家更好地理解和掌握指针。
取地址:
当我们想要获取某个变量的地址,首先找到这个变量的变量名,我们假设它是 a,如果你在这个变量名前面加上&
(&a
),那么恭喜你,你成功的取出了 a 这个变量的地址。
特别地,如果是一个数组,那么它的数组名就是指向它第一个元素的地址,这也是为什么 scanf
数组的时候不要加 &
存地址:
现在你成功的取出了某个变量的地址(假设是一个int变量),你现在想把它存下来,以方便在其它函数里面找到这个变量,怎么办呢?
你可以用 int *p
;来新建一个指向 int
的指针变量。
这里的 *
号指的是你告诉编译器你新建的变量是一个指针类型,这点要注意,因为一会这个符号还有另一个含义。
提示
我们建立的是指针变量,它本质上是一个存储地址的变量。
用地址:
我们现在得到了变量 a
的地址,并把它存在了 p1
这个指针变量里面。我们怎么来使用 p1
呢?
这里我们又要用到 *
号
当我们在定义过 p1
指针后再次使用 *p1
,它的含义就发生了改变。
这里的 *p1
指的是 p1
这个指针指向的变量,也就是说——
*p1
实际上指的就是 a
,无论你在什么地方修改了它的值,a
的值也会随之发生改变。
那么借助指针的这个性质,我们可以写一些更方便的函数来让我们的代码更加简洁。
比如交换两个数,这个操作在某些问题中很常用,我相信大家都不想到处花上好几行的代码来实现它,那么我们可以这样写:
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
// 在main函数中↓
int a = 1, int b = 2;
swap(&a, &b);
// 结果:a = 2, b = 1
通过使用指针,我们可以利用这个swap函数来将某个和这个函数没有半毛钱关系的变量交换值。
开一个指定大小的连续空间(以 Byte 为单位):
翻找 C Reference 我们可以找到 malloc
这个函数和 free
这个函数,这两种函数是我们经常可能要用到的。
为什么要用 malloc
和 free
呢?
我们知道,当你想根据输入的值来确定你的数组大小时,你必须得在确定了输入之后再新建数组,然而,这也意味着你的数组在新建时就受限于当前作用域,当这个函数结束,新建的数组就失效了。此时,如果你还在别处需要这个数组,你便没有办法再获得它了。
所以,我们用 malloc
来向编译器申请一段内存空间,大小可以由你自己指定,它会将一段空间分配给你,并返回这段空间的首地址。这段空间来自堆空间,它不会受限于当前作用域,除非你在别处用 free
释放了它,否则它会一直存在。
注意
申请指针必须有始有终,否则会导致内存泄露(产生了大量的无效内存占用)!如果你发现你的程序越跑越慢,还关不掉,指不定就是内存泄露了!
比如说,你想要申请一个 int
变量和一个大小为 n
的 int
数组,你可以这样写:
int *p1 = (int *)malloc(sizeof(int));
int *p2 = (int *)malloc(sizeof(int) * n);
注意,malloc
返回的是一个 void *
类型的指针,所以我们需要把它强制类型转换为 int *
类型的指针,否则编译器会报错。
提示
此时 p1
和 p2
的变量类型是一样的,但 p2
指向的是一段内存空间的首地址,你可以把它当作数组使用,但 p1
,虽然你也可以把它当作只有一个元素的数组使用,但实际上和单个 int
变量的指针没有区别。
当你使用完了之后,记得用 free
释放它:
free(p1);
free(p2);
提示
free
释放的是指针指向的内存空间,而不是指针本身!为了避免出现野指针,你一定要记得把指针空置!这是好习惯!
p1 = NULL;
p2 = NULL;
顺带一提,我们知道数组的名字就是指向它第一个元素的指针,那么数组到底是什么意思呢?
原来,数组后面方括号里面的数字实际上指的是相对于这个数组指针在内存上的偏移值,偏移0那就是第一个元素,偏移1那就是第二个元素,以此类推。
也就是说,下面 if
中等号两侧这两种表达是等价的:
int *p = malloc(sizeof(int) * n);
if (*(p + 2) == p[2]) {
// do something
}
题单链接(但是没有题):
逃不掉的语法小技巧 指针 - 题单 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)