欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言之指针

程序员文章站 2024-03-08 08:39:39
...

转眼间出来工作已经几年了,岁月无情,决定也写写博客吧,记录下点东西,或许后面回头看看也挺有意思。

回想了下这些年,用的多的还是C语言。虽然有时代码文件后缀是.cpp、偶尔也写了个class,但是还是当成了struct来用的多。废话就到这吧。开始这次想说的主题。

说到C语言,那些说C语言难学的同学都会提到指针这个东西。“指针好难啊!” 。在这我也不评论到底难不难,这里我想就着指针这个点说下自己的认识。

1、指针的初认识

了解指针之前,我们先来认识下内存这个东西。简单的说,内存就是程序运行时代码和数据存放的地方。大部分情况下都是在ram里面,比如pc的内存条、stm32的iram等。我们的程序想要运行,就必须加载到内存里面。那么问题就来了,加载到内存后,我们怎么来获取我们想要的数据呢?我们来看个例子:

在一列高铁动车上,列车长需要找一个人A,这时列车长可以通过查询知道A的车票的座位号,假设是1车1A。他只要走到1车1A的位置就能找到A。如果需要找B,查看B的座位号(2车5F)就可以直接过去找到他。

我们的程序也是这样的,我需要某个数据X,查看X的地址,就可以到这个地址取到这个数据X。那么我们是怎么才能做到让程序到指定的地方取数据呢?这时指针就派上用场了。指针就相当于那张车票,上面记录着一个内存地址(座位号),当我们需要去这个内存地址操作数据时(去座位号上找人),通过指针指向的地址就可以操作这个数据(通过车票上的座位信息就能找到这个人)。

说得有点抽象,那么我们来看个程序的例子。

int main(int argc, char**argv)
{
	int num = 0x12345678;
	int *ptr = #//把num的地址赋值给指针ptr

	printf("ptr addr:0x%p\n", ptr); //打印
	printf("num =    0x%X\n", num); //打印num的值	
	printf("val =    0x%X\n\n", *ptr);//打印ptr指向地址的值

	*ptr = 0x11223344;//向ptr指向的地址赋值
	printf("val =    0x%X\n", *ptr);//打印ptr指向地址的值
	printf("num =    0x%X\n", num); //打印num的值	

	return 0;
}

C语言之指针
程序一开始我们定义了一个int变量num(乘客),并赋值为0x12345678(注意是16进制的数)。然后定义一个int类型的指针ptr(车票),并且把num的地址赋值给ptr(把乘客的座位信息打印到车票上)。从printf(“ptr addr:0x%p\n”, ptr);打印的结果我们可以看到,ptr 的值是0x010FF8C4(乘客的座位是0x010FF8C4).接下来我们用这个指针ptr去取数据,并且打印出来。printf(“val: 0x%X\n”, *ptr);得到的结果是0x12345678.和num的结果完全一致。我们再打开内存查看窗口(我用的是VS2015,在菜单“调试” - “窗口” - “内存” -“内存1”可以打开),输入地址0x010FF8C4,可以看到里面的数据是78 56 34 12.这个就是0x12345678在内存里面的存储形式(小端模式 -详情可以去百度下“大小端模式”)。
C语言之指针
程序继续往下运行,我们给ptr指向的地址赋值0x11223344。然后打印出ptr指向的地址的值和num的值,结果发现,都同时为0x11223344。这时再在内存窗口里面看到0x010FF8C4地址里面存的值已经变成了44 33 22 11。

从以上结果可以看到:当我们用一个指针指向某个变量(某个地址)时,我们对这个指针指向的地址进行读写操作时,等同于直接操作这个变量。

2、指针与数组

说到数组,我们可能会想到这是一个连续的空间,他是用来放一些数据类型相同的地方。那么数组和指针又有什么关系呢?从上面我们已经知道,指针就是指向一个内存地址的变量。而数组,他是数据的一种类型,因此他也是存在内存里面的某个地方。既然数组也是存储在内存里面,那么指针就可以指向他。我们来看一个例子
C语言之指针
程序运行到add函数前,可以看到nums第一个元素的地址是0x00CBFD6C,而0x00CBFD6C地址开始的数据就是我们初始化数组时的数据。
C语言之指针
进入add函数后,变量ptr的值是0x00CBFD6C,和nums[0]的地址一致。可以看出,当数组当成参数传递给一个指针变量时,传递的是这个数组的第一个元素所在的地址,也就是传的就是个地址。这时候add函数里面的ptr参数操作的等同于直接操作nums数组。

这里有个有趣的问题,我们的数组是大小是10,那么我们去访问第11个元素会是什么样子?
C语言之指针
我这里第11个输出输出的结果是0xCCCCCCCC,从内存空间里面也可以看到这个值。那为什么是这个值呢?这么做会有什么问题呢?这个我打算在后面再专门写一篇文章来谈这个问题。这个情况我们可以说是数组溢出了,数组越界了。我们访问到了一个我们事先没定义好的地方,他的值将是“未知的”。当我们的程序有数组越界时,是个致命的bug,它可能会导致你的程序运行到这里时会产生无法预估的结果,更严重的会导致程序崩溃无法继续运行。因此在编写代码时,时刻得小心自己的数组操作是否越界了。

3、指针与函数

一开始我们说到,内存里面存储的是程序的代码和数据。函数就是程序的一段代码,因此他肯定也是存储在内存里面的。既然是存储在内存里面,那么我们就可以用指针指向他。我们来看个例子:
C语言之指针
我们定义了一个函数指针类型为typedef void(*MyFuncType)(int ptr);他是一个void返回,有一个int作为参数的函数。MyFuncType为我们定义类型名。(详情可以百度下typdef函数指针
程序的一开始,我们打印出add函数和sub函数的地址,分别为00E0D20A、00E0D20F。
随后我们自己调用了一次add函数,可以看出i的值被加1了。接着我们将add函数的地址赋值给func变量。再次打印func的值,是00E0D20A,和add函数的地址完全一致。这时我们直接用func来调用add函数,得到的结果也是i被加1。最后我们将syb函数的地址赋值给func变量,打印出func的值,可以看到正是sub函数的地址00E0D20F。这时我们再次调用func,得到的i被减1的结果。

从以上结果可以看出,当我们用一个指针指向某个函数时,我们就可以通过这个指针去调用这个函数。

4、小结

指针是什么?指针就是一种指向内存地址的数据。程序运行时需要的数据和代码都存放在内存里面,因此,我们就可以通过指针来访问这些数据或者代码(函数)。

第一次写文章,给自己的感觉是件困难的事,想要把自己想表达的东西写出来,写得清楚,真的不容易。如果文章哪里有什么错误,欢迎指出。

相关标签: 指针 c语言