说起C语言,这个最低级的高级语言,那真的是折磨了很多嵌入式工程师的脑袋,很多工程师谢顶可能都是拜他所赐,为什么这么说呢?相对于其他高级语言来说,这个语言过于的低级,低级到什么地步呢?它没有强大的库函数,连最基本的数据处理,链表什么的都没有标准的模式,程序员在设计的代码的时候很多常见的功能不得不自己去动手实现,这一点甚至C++做得都比它好的多。
当然这不是最坑爹的,最坑爹的是,C语言很多高级用法都要用到指针,而这个指针在使用的时候会出现各种各样的问题,比如定义错误,指向的内容错误,亦或是分配了空间忘了释放了等一些列很野蛮的事故,都会让人焦头烂额。为了我们的前途着想,我打算在这里花大篇幅把指针的内容详细的跟大家讲下,也是我学习这几年学到的一下知识与感悟,也许各位读者在看的过程中,能领略到以前没有注意的细节。
指针到底是个什么东西,大家肯定能想到的就是,指针变量保存的就是一个变量的地址,这句话是没错,但是理解的顺序有偏差,这里我跟大家更正一下。
对于一个变量来说,总体上分为三个要素,即变量的名字,变量的数据,变量所存放的位置。
对于这三个要素来说,其中最没用的就是变量的名字了,因为这个名字是你自己起的,编译器帮你管理的,其实对于处理器来说它才不管你起的这个名字是否高大上,对它来说,只要你说要读写这个变量,我就去找对应位置操作这段地址。所以这个不重要。
变量的内容这个就很重要了,因为我们之所以要定义一个变量其实就是为了控制其中的数据,这个我就先不多说了。
对于变量的地址来说,这个对于C语言来说,超级重要,可能初学者没有意识到这个问题,这个不怕,后续我会慢慢讲。变量存放的地址换句话说就是这个变量的位置,而指针就是保存这个变量地址的另一个变量……
上边这个图我们分析一下其中的含义,对于第一行来说,红色字体表明变量的名字,比如说第一个变量为“a”,它包含的数据是黑色字体“1”,而它的地址是蓝色字体“0x1000”,这就是一个变量的三个要素。此时在地址为“0x2000”的位置有个指针变量“ptrA”它的数据就是“0x1000”,而这个数据正好就是变量“a”的地址,那么我们就可以说,变量“ptrA”就是变量“a”的指针。
我在这里编写一个代码可能会更加让人清楚:
#include
main()
{
char a = 1; //变量名为a,数据位1
char * ptrA = &a; //把变量a的地址提取出来复制给指针变量ptrA
printf("变量a的数据为%d,地址为%d\r\n", &a, a); //把变量a的数据和地址打印出来
printf("指针ptrA的数据为%d,指向的变量的数据为%d", ptrA, *ptrA);
//把变量ptrA的数据及它指向的数据打印出来
getchar();
}
在我这里运行的结果是:
变量a的数据为5240635,地址为1
指针ptrA的数据为5240635,指向的变量的数据为1
在这里,大家会看到,“ptrA”这个变量保存的数据正好就是变量“a”的地址数据,那么“prtA”就是指向变量“a”的指针。
其实说白了,指针的意思就是一个保存某个固定数据类型(包括基本数据类型、结构体、甚至函数)地址的一种特殊的变量。
可能有些读者就要问了,对于一个变量都有一个固定的地址,这一点好理解,为什么还要重新设计一个变量保存之前那个变量的地址呢?是不是有点多此一举呢?
这个问题比较复杂,对于C语言大牛来说,他们可以举出好多例子来说明为什么C语言必须要用到指针,并且有些场合中你还不得不用到这个复杂的东西。在这里我就先举一个例子,后学我们学其他内容的时候在一点分析一下如何不用指针,有些功能实现起来是何等的麻烦。
课本上一个最经典的例子是,如果想要通过传参的方式,把两个参数的数据进行修改,就不得不用到指针,举个例子。
#include
void change(int w, int u) { //理论上要交换数据的函数
int temp = w;
w = u;
u = temp;
}
main()
{
int a = 1;
int b = 2;
change(a, b);
printf("a = %d, b = %d", a, b); //调用交换数据的函数
}
上边的代码我们设计了一个交换参数的代码,希望把传入的参数进行交换,但是可惜的时候,最终打印出来的数据根本没有交换,这是为什么呢?
是因为这里牵扯到一个函数变量作用域的问题,简单的来说,就是当函数调用之后,函数内部会先把传进去的参数的数值复制一遍,然后再进行读写操作,因此如果想在函数内部改变参数从而影响参数外边的数据,那绝对是不可能的。
当然我知道有人不太理解,我这里重新解释一下,这就类似于A同学有一台电脑,但是不会下载游戏,此时A就让B同学帮忙下载,此时B同学就相当于被调用的函数。然而此时有个问题,对于B同学来说,他是先把A同学的电脑硬盘复制一份,然后再自己电脑上下载游戏,下载完成之后A同学兴高采烈的准备去玩,但是发现自己硬盘上依然没有任何东西……
对于这种情况如何才能让B同学下载游戏之后,A同学的电脑也能玩呢?很简单,告诉B同学,我给你A同学电脑所在的位置(指针地址),让B同学直接在A同学的电脑上下载,这样就完美解决问题了呗。
所以我们就要想办法把传入的参数变成地址,让被调用的函数能够直接找到参数所在的地址,那么这个问题就好解决了。
#include
void change(int* w, int* u) { //把参数传入进去
int temp = *w;
*w = *u;
*u = temp;
}
main()
{
int a = 1;
int b = 2;
change(&a, &b);
printf("a = %d, b = %d", a, b); //调用交换数据的函数
getchar();
}
我知道有些同学脑子里有个疑问,因为听说指针这个东东只是C/C++专用的,其他高级语言没有用到指针,但是他们依然过得风生水起的,这到底是为什么呢?很简单,因为其他高级语言用的是一个叫做“引用”的技术,其实就是隐藏“*”的指针而已,C++上也有这个概念,只是没有没有流行起来就是了。
指针如何定义、如何引用,有什么奇葩的使用方法、如何与普通数据类型进行操作?还有什么在之前使用的时候没有注意的细节呢?
敬请期待下一期——《嵌入式系统中有用的编程技巧—— 一.2 指针的使用的一些细节》