目录
前言:
指针是我们学习编程避不开的话题,它是编程中最重要的概念之一,很多初学者对它闻之色变、胆战心惊。虽然指针很重要,但并不代表它难如登天。
一、初识指针
1.内存和地址
我们知道在计算机处理数据的时候,数据是从内存中读取,处理完成后又放回内存之中,那计算机是如何管理那些内存的呢?
其实是把内存分为一个一个的内存单元,每一个内存单元的大小为1字节,而1字节在计算机管理中为8个比特位。每个字节都有自己的内存单元编号(也叫地址),在C语言中给地址又取了新的名字:指针。
所以内存单元编号==地址==指针
2.关于指针的操作符(&和*)
a.&操作符
如果我们想要得到一个整形a的地址,我们只需要用到‘&’操作符。(注:这里使用的是x86(也就是32位)的环境,不同的环境打印出来的地址长度可能不同)
#include <stdio.h> int main() { int a =10;//创建一个整形a。 printf("a的地址:%p",&a);//%p用来打印地址。 return 0; }结果如下:
b.*操作符
如果我们要改变一个数,我们可以直接用它的变量名称来改变,也可以直接“上门”改变(通过指针变量来找到它的地址)它的数。
#include <stdio.h> int main() { int a =10;//创建一个整形a。 int* pa = &a;//这里创建一个指针变量来接收a的地址。 *pa = 20; printf("*pa=%d\n",*pa);//打印观察a是否发生变化。 printf("a=%d\n",a); return 0; }结果如下:
c.二级指针
那否也能指针变量的地址,然后存到另一个指针变量里面呢?(这里ppa叫做二级指针)
#include <stdio.h> int main() { int a =10;//创建一个整形a。 int* pa = &a;//这里创建一个指针变量来接收a的地址。 int* *ppa = &pa; //这里的ppa叫做二级指针。 *pa = 20; **ppa = 30; printf("**ppa = %d,**ppa);//打印观察a是否发生变化。 printf("*pa=%d\n",*pa); printf("a=%d\n",a); return 0; }结果如下:
我们对照可以发现a和*pa的值都变了,所以我们的猜想成立,那是不是可以重复这个操作呢?答案是肯定的,但我们并不需要这么多的指针变量(一般最多就用二级指针)
3. 数组
a.一维数组
数组是一个固定长度的存储相同数据类型的数据结构,数组中的元素被存储在一段连续的内存空间中。它是最简单的数据结构之一。
但与此同时在一般的编译器里数组名其实是它的首元素的地址。(但有两个例外sizeof(数组名)和&数组名)
#include <stdio.h> int main() { int a[3] = {1,2,3}; printf("a = %p\n",a); printf("&a = %p\n",&a); return 0; }结果如下:
或许有人发现这俩的地址打印出来的结果一样,那它们俩的作用效果会不会也是一样的呢?
(这里先卖一个小关子,后面我会写出它们的不同)
b.二维数组
二维数组与一维数组差不多
int a[2][2] = {1,2,3,4};//创建一个数组 //若要存放一个二维数组的地址&a应该如何存放。 int (*pa)[2] = &a;//这里的pa其实存放了二维数组a第一行的地址。 //此时的pa+1就代表了a的第二行的地址
二、指针的运用
1.指针的运算+ -
下面我用几个例子来解释。
a. + 操作符
#include <stdio.h> int main() { int a[10] = {1,2,3,4,5,6,7,8,9,10};//创建一个数组 int* pa = a;//这里的a是首元素的地址,所以不用&操作符 for(int i = 0; i < 10; i++) { (*pa)++;① pa++;② } return 0; }这里最开始的*pa是代表a[0],而操作①是a[0]++,而开始pa指向的是a[0]的地址,当操作②后,pa指向的地址是a[1]了,同时*pa代表a[1],然后循环操作。最终结果应该如下
b. - 操作符
既然地址可以用 + 操作符,那 - 操作符呢?
#include <stdio.h> int main() { int a[10] = {1,2,3,4,5,6,7,8,9,10};//创建一个数组 int count = &a[10] - &a[0]; printf("count = %d\n",count); return 0; }结果如下:
这里我们其实可以得到一个结论:俩个处于同一块空间的数组的不同地址,相减得到的数的绝对值是它们之间的元素个数。
2.指针的实际利用
或许会有人说,想要改变一个值还不简单,直接用它的变量名改就可以了,但真的这么简单就可以完成C语言的基本操作了吗?
若我们要交换两个值,我们可能会写出下面的代码。
#include <stdio.h> int main() { int a = 10; int b = 20; int tmp = a; a = b; b = tmp; return 0; }这个代码改变了a和b的值吗?答:确实改变了。
那如果要求在一个Swap()函数里改变两个变量的值呢?
#include <stdio.h> void Swap(int x,int y) { int tmp = x; x = y; y =tmp; } int main() { int a = 10; int b = 20; Swap(a,b); return 0; }上面的代码改变了a和b的值了吗?答:并没有。因为在Swap()函数中传过去的是实际参数,而接受的是形式参数,而形式参数的改变并不能改变实际参数。我们只需将上面的代码改为下面的就可以了。
#include <stdio.h> void Swap(int* x,int* y) { int tmp = *x; *x = *y; *y =tmp; } int main() { int a = 10; int b = 20; Swap(&a,&b); return 0; }这样a和b的值就交换了,因为我们是直接从地址上找到a和b然后改变它们。
3.指针的一些危险用法
首先,我们要有一个野指针的概念,野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。
a.没有初始化指针变量就使用
#include <stdio.h> int main() { int *p; *p = 20;//err return 0; }上面的代码就是错误的,产生了野指针。
b.没有正确的对标指针变量
#include <stdio.h> int main() { char c = 'a'; int *p = (int*)&c;//err return 0; }这里的c是char类型,占1字节,但我们用了4个字节的int类型指针来存放c,若改变了*p,c就会改变4个字节,但c若要改变应只要改变1字节,可想而知,可能会发生一些不可预测的错误。
本文详细介绍了指针在编程中的基本概念,包括内存地址、操作符应用(如&和*)、一维和二维数组,以及指针的运算和实际利用。同时强调了指针的危险用法,如未初始化的指针和不正确的类型标定。



我们对照可以发现a和*pa的值都变了,所以我们的猜想成立,那是不是可以重复这个操作呢?答案是肯定的,但我们并不需要这么多的指针变量(一般最多就用二级指针)
这里我们其实可以得到一个结论:俩个处于同一块空间的数组的不同地址,相减得到的数的绝对值是它们之间的元素个数。
16万+

被折叠的 条评论
为什么被折叠?



