首页 > 财经旅游 > 正文

黑客基础—C语言编程篇—指针

2019-08-31 14:50:59   来源:东方头条   评论:0

在进入今天的内容前,先放个小杀招……

请看图:

答案我最后再公布,哈哈!

今天讲的是指针,这个玩意儿在C语言中可以说很烦人……很容易搞错……小编我是自学的,有不合理的地方请多多包涵……另外,由于指针内容比较多,也是重点,我可能会分几篇文章,循序渐进的讲述我理解的指针!

先来看指针的声明格式:

数据类型 *指针变量名记住,定义好之后,此指针只能指向定义的该数据类型!否则会出错!新手注意!

这里还有一个易错点,那就是,如果指针没有指向任何变量,即没有赋值或初始化,那么可以对此指针使用间接访问运算符*吗?

答案是不可以!因为指针还没有指向任意变量,换句话说,就是指针内部还没有存储变量地址,既然没有存储变量地址,怎么能取出变量的值呢?是不是?

来个杀招过把瘾!看题:int *p,x=2;*p=5;

请问这样可以吗?

如果你认真看了我上面的内容,那么就不可以。这是一种内存盗用的行为!很危险!因为指针没有初始化,可能指向内存中的任意一个位置,这就导致了后面给他赋值可能会篡改指针原来指向的那个值。如果那个值刚好是应该被其他程序调用的,那么就会造成轻则程序错误,重则程序崩溃的后果!

好,基本的差不多了,下面看几个常见的形式:

int x=1,*p;p=x;

&*x等价于x&*p等价于&x或者p*p+1等价于++x*p++等价于*(p++)这里得注意一下优先级

下面我们在来看看指针作为函数的参数会发生什么。(这里有个概念,很多新人,我保证你会错的很惨!)

首先我们就要明确一个概念,实参的值是可以传递给形参的,形参却无法改变实参的值!(如果你不用指针去改变的话),因为函数的参数是单向传递的。

问题来了,如果函数的形参是指针呢?在传递的过程中,哪些地方会变动?整个流程你心中是否有数?

我开始解析了。首先,实参指针会把自己的地址传递给形参,然后形参对地址做出一系列的改变、赋值等操作,这里要注意的是,形参已经拥有了实参所指的地址,也就是说,形参怎么操作都会对实参所指的那个内存地址产生影响!反过来,如果你再对实参进行操作,那么那个内存地址里面的值也会改变。总结成一句话就是:形参实参都会直接对内存修改!(因为是指针)

这里还有一个注意点,那就是函数调用以指针为参数的实数时,形参与实参的指针类型必须是指向同一种数据类型的,即类型相同,否则出错。

还没完,我还有一个坑!请问:可以通过修改指针形参的值来修改指针实参的值吗?我建议读者把这句话读5篇以上再思考!

我不卖关子了,实话告诉你吧!不可以!什么?小编你上面不是说可以修改的吗?怎么这里就不可以了?

我想说,请你看仔细了,很容易理解错这个概念!这里修改的是指针形参的值,即指针形参的地址!通过修改形参的地址,是无法改变实参的地址的!这就和我刚开始提的概念相一致了。单向传递!不过,指针形参所指向的变量值的修改,可以改变对应实参指针指的变量。

最后一个小知识点:假设下面变量都合法,没有语法错误,p1p2是指针,分别指向abexchange(p1,p2)等价于exchange(&a,&b)

这样写也是可以的。

哦对了,差点忘了上面第一题的答案,看图:

简单提示一下吧,fun括号里面的是字符,0是字符不是数值,下面*p!=0这里的0是数值……

我们都知道,指针是可以用来操作数组的,并且,这样子速度还比较快!二数组的名字通常就是数组首元素的地址。比如:

int a[3]={1,2,3}

其中,a就代表首元素1的地址。哦,对了,之前有读者在指针与二维数组的赋值这里有点小疑问,我这里就在说一下。

先来看个二维数组以及数组指针的声明:

int a[2][3];

int *p[3];

p[0]=a[0][1];

我先说明一下,第二行声明的是数组p,这个数组p里面的元素是指针元素,共三个。第三行p[0]的意思是将数组p中的第一个指针元素赋值为a[0][1]这个元素的值。嗯,我这里将p[0]这个元素假设成指针k元素,p[0]就等价于*k,后面a[0][1]就是一个值,假设是3,那么就是*k=3,我个人不知道这样理解对不对,因为我是想通过这个例子说明上面的三行是正确的。(因为有读者想不通)。

好,我们继续下面的内容。数组与指针之间的转换。

int a[3]={1,2,3}

int *p=a;

p[1]=20;

像第三行这样表示是完全可以的。也可以像下面这样:

int *p=&a[1];

另外,二维数组和指针结合在一起后,通常会让很多人头疼,我们先看看二维数组的一些易错表示:

int a[3][3]假设已经初始化了……我后面不写了。那么后面这几种表示我们得熟悉:

a[1]+1 表示的意思是第二行第二列

*(a[1]+1)等价于a[1][1],记住,这里是数值相等!数值!

*(a[1]+1)等价于 *(*(a+1)+1),后面这种情况要慢慢理解,好好理解。要始终谨记,我们这是在处理二维数组,所以看这个式子的时候,括号里面代表的是二维数组坐标,大括号外的*号,才暗示我们输出对应坐标的值。

最后,我想考一下各位,请你们判断我下面的式子是否正确。(以下都是以二维数组为基础)

*(a[1]+0)等价于 *a[1] 吗?

*a[1] 等价于 **(a+1) 吗?

正确答案是,上面两个全都是等价于。小编我还是解释一下吧!

已知这是基于二维数组的,那就表示第一行中的a[1]表示二维数组第二行,a[1]+0表示二维数组第二行第一列,外面又加个括号和*号,那就说明这是取那个对应坐标的值。后面的*a[1]解释就是将第一列对应的0给消去了,如果没有*号,则表示这是第二行,有了则表明要取值了。

第二个例子*a[1]和上面意思一样,就是取二维数组的第二行第一列坐标的值,因为把0列的0消去了,所以干扰了读者的理解。后面的**(a+1)更难理解,我们都知道a代表数组首元素的地址,那么*(a+1)则代表二行,这个式子可以扩写为 *(*(a+1)+0),这样一看就懂了吧!

我现在在想,要不要再写一点内容呢,还是今天的内容就到这了?这上面的内容小白们和初学者应该能掌握吧!那我就再开个头好了,写不完,大不了明天接着写。

指针与函数

先给大家看两个例子,嘿嘿。(小编我又邪笑了!)

int (*p)( a,b );

int *p( a,b );

请问,这两个是一个意思吗?如果你觉得不是,那么他们又各自代表什么意思?

我先不说,我先给大家讲个函数的小知识。那就是“函数代码的存储空间的起始地址又称为函数的入口地址”此外,存放函数入口地址的指针变量就称为指向函数的指针。

是不是还是不清楚什么意思?没事,我们回到上面的两个例子上。

第一行,代表声明一个指向函数的指针。

第二行,代表声明一个函数,他的返回值是指向int类型的指针。

这下很清晰明了了吧!

补充一下,如果要给指向函数的指针赋值,那么只需要:

(*p)=fun;fun是自定义函数

还有一个易错的地方,假如:

int fun(int,int);

那么声明指向这个函数的指针必须要这样声明:

int (*p)(int,int );括号里的形参最好要一致,否则很危险,同理对应的返回值类型也要一致。、

最后,再说一个常见错误!

已有指向函数的指针p

p=fun(a,b);这样赋值给p是错误的,因为这里赋值的是函数的返回值,不是函数入口地址!

并且,记住,函数指针与数组指针的最大不同是——函数指针不能做算数运算,如p+1;虽然C不允许把函数作为函数的的参数,但是我们可以用指针来搞。

好了,大家看完之后有什么感想呢,请在评论区告诉我呦!

文章来源于“危险一瞬间GG”

  责任编辑:

今日推荐

习近平在第五届中国国际进口博览会开幕式上发表致辞

11月4日晚,国家主席习近平以视频方式出席在上海举行的第五届中国国际进口博览会开幕式并发表题为《共创开放繁荣的美好未来》的致辞。新华社记者 李学仁 摄[详细]

中国共产党第二十次全国代表大会闭幕会在京举行

10月22日,中国共产党第二十次全国代表大会闭幕会在北京人民大会堂举行。新华社记者 陈建力 摄[详细]

天天学习|中南海月刊(2022.09)

天天学习金色九月,喜迎丰收。9月,一个个瞬间令人难忘:主持中央深改委会议决定健全关键核心技术攻关新型举国体制;出席中央军委晋升上将军衔仪式颁发命令状;新冠肺炎疫情发生以来首次出访...[详细]