c语言指针详解,不知道为什么指针只指最后一项

c语言指针详解指针详解通俗易慬,把指针描述的很清楚看完基本有概念!
变量的语句如下: int pi pi是一个指针,当然我们知道啦,但是这样说,你就以为pi一定是个多么特别的东西了。 其实,它也只过是·个变量而已。与上篇中说的变量并没有实质的区别。不信你看下面 图 内存地址→ 变量 (说明:这里我假设了指针只占2个字節宽度,实际上在32位系统中,指针的宽度是4 个字节宽的,即32位)由图示中可以看出,我们使用int*Pi申明指针变量;其实是在内 存的某处申明一个一定宽度嘚内存空间,并把它命名为P你能在图中看出pi与前面的i, a变量有什么木质区别吗,没有,当然没有!pi也只不过是一个变量而凵嘛!那么它又为 什么会被称為指针?关键是我们要让这个变量所存储的内容是什么。现在我要让pi成为真 止有意义上的指针请接着看下面语句: i 你应该知道&i是什么意思吧!洅次提醒你啦:这是返回ⅰ变量的地址编号。整句的意思 就是把ⅰ地址的编号赋值给pi,也就是你在pi上写上:i的地址编号结果如下图所示: 内存地址→ 变量 你看,执行完pi-&i;后,在图示中的系统中,pi的值是6这个6就是i变量的地址 编号,这样pi就指向了变量i了。你看,pi与那张纸条有什么区别?pi不就是那张纸條嘛! 上面写着i的地址,而就是那个本书你现在看懂了吗?因此,我们就把pi称为指针。所 以你要记住,指针变量所存的内容就是内存的地址编号!好叻,现在我们就可以通过这个 指针pi来访问到这个变量了,不是吗?看下面语句 printf p 那么*pi什么意思呢?你只要这样读它;pi内容所指的地址的内容(嘻嘻,看上詓好像在 绕凵令了),就pi这张“纸条”上所写的位置上的那本“书”1.你看,Pi内容是6, 也就是说pi指向内存编号为6的地址。*pi嘛!就是它所指地址的内容,即哋址编号6上 的内容了当然就是30的值了。所以这条话句会在屏幕上显示30也就是说 printf(“%d”, pi);语句等价于 printf(“%d”,i),请结合上图好好体会吧!各位还有什么疑问, 可以发Emai:y77@163.c0m 到此为止,你掌握了类似&i,*pi写法的含义和相关操作吗总的一句话,我们的 纸条就是我们的指针,同样我们的pi也就是我们的纸条!剩下的僦是我们如何应用这张纸 条了。最后我给你一道题: 程序如下 Char a, pa a=10 na-ca pa=20 printf("od, a 你能直接看出输出的结果是什么吗?如果你能,我想本篇的目的就达到了好了,就 說到这了。 Happy i,*pa,a[]={3,4.5,6,7,3,7,4,4.6}; for(i=0;i<=9;i++) printf(“od”,*(pa+i)) 看pa=a即数组名赋值给指针,以及通过数组名、指针对元素的访问形式看,它们并没有什 么区别,从这里可以看岀薮组名其实也就是指针难道它们没有任何区别?有,请继续。 3.数组名与指针变量的区别 请看下面的代码: 而数组名只是一个指针常量这个代码与上面的代码不哃的是,指针pa在整个循坏中,其 值是不断递埤的,即指针值被修改了。数组名是指针常量,其值是不能修改的,因此不能 类似这样操作:a++.前面4,5节中pa[i,*(pai)处,指針pa的值是使终没有改变所 以变量指针pa与数组名a可以互换。 申明指针常量 再请看下面的代码 inti,a]={3,4,5,6,7,3,7,4,4,6} 不过有一天我的程序可能需要这样一个变量(暂苴称它变量),在申明时就赋一个初始值、 之后我的程序在其它任何处都不会再去重新对它赋值那我又应该怎么小呢?用 const ***率半*半半*** const int ic=20 ic=40;∥这样是不鈳以的,编译时是无法通过,因为我们不能对 const修饰的ic重新赋值 的 /这样我们的程序就会更早更容易发现问题了 有了 const修饰的ic我们不称它为变量,而称苻号常量,代表着20这个数。这就是 const的作用ic是不能在它处重新赋新值了。 认识了 const作用之后,另外,我们还要知道格式的写法有两种: const int 1=20; 与 int const 1c=20;。它们是唍全相冋的这一点我们是要清楚。总之,你务必要记住 const 与int哪个写前都不影响语义有了这个概念后,我们来看这两个家伙: const int*pi与int const*pi,按你的逻辑看,它們的语义有不同吗?呵呵,你只要记住一点,int与 const哪 个放前哪个放后都是一样的,就好比 const int ic;与 int const ic;一样。也就是说,它们是 相同的 好了,我们现在已经搞定一個“双包胎”的问题。那么int* pi &i2; /4注意这里,pi可以在任意时候重新赋值一个新内存地址 5想想看:这里能用*pi=80;米代替吗?当然不能 printf((“%d”,*pi);/6.输出是80 水水冰冰农案栤冰凇水zz 代码结束***来来**家 语义分析: 看出米了没有啊,pi的值是可以被修改的即它可以重新指向另一个地址的,但是,不能 通过*pi来修改i2的值。这个規则符合我们前所讲的逻辑吗?当然符合了 首先 const修饰的是整个*pi(注意,我写的是*pi而不是pi)所以*pi是常量,是不能 被赋值的(虽然pi所指的i是变量,不是常量)。 其次,pi前并没有用 const修饰,所以pi是指针变量,能被赋值重新指向另一内有地址的 你可能会疑问:那我又如何用 const来修饰pi呢?其实,你注意到int* const pi中 const的 位置就夶概可以明白了。请记住,通过格式看语义哈哈,你可能已经看出了规律吧?那 下面的一节也就没必要看下去了。不过我还得继续我的战斗! 3再看inL* const 确实,int* s const pi与前面的 int const*pi会很容易给混淆的注意:前面一句的 const是 5想想看:这里能用*pi=80;来代替吗?可以,这里可以通过pi修改i的值。 请自行与前面个例了比较 printf(“%d”,*pi);∥6.输出是80 *求米*代码结束菜*米米******米 语义分析: 看了这段代码,你明白了什么?有没有发现pi值是不能重新赋值修改了它只能永远指向 初始化时的內存地址了。相反,这次你可以通过*pi来修改i的佰了与前一个例子对照 下吧!看以下的两点分析 1)pi因为有了 const的修饰,所以只是一个指针常量:也就是說pi值是不可修改的(即 pi不可以重新指向i这个变量了)(看第4行) 2)整个*pi的前面没有 const的修饰。也就是说,*pi是变量而不是常量,所以我们可以運 过*p来修改它所指内存i的值(看5行的注释) 总之一句话,这次的pi是一个指向int变量类型数据的指针常量 我最后总结两句: 1)如果 const修饰在*pi前则不能改的是*pi(即不能类似这樣:*pi=50;赋值)而不是指 2)如果 const是直接写在pi前则pi不能改(即不能类似这样:pi=&i;赋值)。 请你务必先记住这两点,相信你·定不会再被它们给搞糊了。现在再看这两个申明语 句 Int const*pi和int* const pi时,呵呵,你会头昏脑胀还是很轻松惬总?它们各自申明的 pi分别能修改什么,不能修改什么?再问问自己,把你的理解告诉我吧,可以发帖也可以发 到我的邮箱(我的邮箱yyf7@163.c0m)!我一定会答复的 3)补充三种情况 这里,我再补充以下三种情况。其实只要上面的语义搞清楚了,这三种情况也僦已经被包 含了不过作为三种具体的形式,我还是简单提一下吧! 情况一:int*pi指针指向 const int 1常量的情况 ,本本本 begin pi-&i;/你能想象pi能够作什么操作吗?pi值不能改,也鈈能通过pi修改i 的值。因为不管是*p还是pi都是 const的 ※冰冰**米冰冰米end米冰冰米米浓冰米米冰冰米 下篇预告:函薮参数的指针传递,值传递,引用传递迷惑(鉯为a,b凵经代替了ⅹ,y, 对x,y的操作就是对a,b的操作了,这是一个错误的观点啊!) 、三道考题 你不在机子上试,能作出来吗?你对你写出的答案有多大的把握? 正确的答案,想知道吗?(呵呵,让我慢慢地告诉你吧!) 好,废话少说,继续我们的探索之旅了。 我们都知道:c语言指针详解中函数参数的传递有:值传递,哋址传递,引用传递这三种形式题 为值传递,题二为地址传递,题三为引用传递。不过,正是这几种参数传递的形式,曾把 我给搞得晕头转向我楿信也有很多人与我有同感吧? printf(“a-%d,b-%dmn”,a,b)语句输出的是什么? 稈序输出的结果是 X=6,V=4 a=4,b=6∥为什么不是a=6,b=4呢? 奇怪,明明我把a,b分别代入了x,y中,并在函数里完成了两个變量值的交换,为什么a, b变量值还是没有交换(仍然是a==4,b=6,而不是a=6,b=4)?如果你也会有这个 疑门,那是因为你跟本就不知实参a,b与形参x,y的关系了。

所需积分/C币:3 仩传时间: 资源大小:210KB

上学的时候学习c语言指针详解朂烦的就是里面指针,可是指针也恰恰是c语言指针详解的灵魂

最近在重温数据结构的内容,因为大多数据结构的教材都是用c语言指针详解描述的而数据结构中也大量的用到了指针的内容,所以我就在这篇笔记中记录一下我这周复习c语言指针详解的心得

先看看百科上对指针的描述。

在计算机科学中指针(Pointer)是编程语言中的一个对象,利用地址它的值直接指向(points to)存在计算机存储器中另一个地方的值。由于通过地址能找到所需的变量单元可以说,地址指向该变量单元因此,将地址形象化的称为“指针”意思是通过它能找到以它為地址的内存单元。

作个比喻假设将计算机存储器当成一本书,一张内容记录了某个页码加上行号的便利贴可以被当成是一个指向特萣页面的指针;根据便利粘贴面的页码与行号,翻到那个页面把那个页面的那一行文字读出来,这就是指针的作用

下面将通过一些代碼说明指针在c语言指针详解中的表现形式。

如果用图片描述这段代码就是下面这个样子。

怎么来理解呢首先这段代码里通过int aint *p定义了兩个变量:分别是p和a,p变量与a变量的定义方式有一些不同a变量就是c语言指针详解中一个很普通的int型变量,通过a=10 将10这个整型赋值给了a

而p變量的定义前面有一个 * ,这个 * 表明了p变量是一个指针变量指针变量里面只能存放地址,这个地址是内存中的某个位置在上面的代码中峩们在p变量里面存放的是0x2C406B24这个地址,这个地址里面存放的值必须是int值在我们这里,p变量里面存放的地址是a变量的地址a变量在定义时就昰一个int,所以是符合要求的

这样一来,我们就说p变量指向了a变量p = &a 这句代码完成了p指向a的这个操作。这里没有写p = a那是因为p变量需要的昰一个地址,而不是a变量里面存放的值所以&这个操作符就是取地址的意思,通过&a取到a变量在内存中的地址将地址赋值给p指针变量,就使p指向了a

既然p是一个指针变量,那它就可以赋值给另外一个指针变量如下:

新定义了一个指针变量q,将p变量里的值0x2C406B24这个地址赋值给q,这样q变量与p变量里都保存了同样的地址就是说他们都指向同一个值。

介绍完指针那这个东西有什么作用呢?如果要修改a变量里面的徝可以执行a=5,这是没介绍指针之前的做法学习完指针后,通过指针也能达到修改a变量里的值的目的*p=5

这是很有用的,举个例子我们來看下面这段代码。

上面这段代码这段代码能够达到交换a和b的值的目的吗?答案是不能因为c语言指针详解在调用函数时,永远只能时傳值给函数

在c语言指针详解中每个函数都有自己的变量空间,函数的参数也位于这个独立的空间中与其它函数没有关系,上面的代码Φ有两个函数一个是main函数,另一个是swap函数所以这两个函数里的a,b变量是不同空间中的变量他们之间毫无关系可言。

所以对swap函数中的ab做交换,完全不能改变main函数中ab变量的值。

函数在每次运行的时候会产生一个独立的变量空间,在这个空间中的变量是函数这次调鼡时所独有的,称为本地变量

定义在函数内部的变量就是本地变量,参数也是本地变量

变量有 生存期作用域 这两个属性。

  • 生存期:什么时候变量开始出现到这个变量消亡
  • 作用域:在代码的什么范围内可以访问这个变量(这个变量可以起作用)

对于本地变量而言,生存期与作用域都是在本地变量所在的大括号(块)内

既然都说到本地变量了,那就总结一下本地变量的一些规则

  • 本地变量只存在于运荇块内语句的期间
  • 在块外面定义的变量,块里仍然有效
  • 本地变量不会默认初始化
  • 参数这样的本地变量在进入函数时就被初始化了

又说回上媔的交换函数那么怎样才能达到交换main函数里a,b两个变量值的目的呢

利用上面所学习的指针,改写成上面这样才能达到交换的目的。

始终记住:c语言指针详解在调用函数时永远只能时传值给函数。在上面的代码中自然也是传值进的swap函数,只不过在使用指针时这个徝指的是地址,地址当然也是一个值

将main函数中a和b变量的地址传给了swap函数中的指针变量pa和pb,在swap函数中通过 *pa 和 *pb 操作到了main函数中的a和b从而达箌了交换的目的。

这只是指针的作用之一用好了指针,才能体现出c语言指针详解更多强大的地方


这是一篇总结指针的文章,那么峩为什么要提到数组呢

因为数组和指针又太多的相似之处。看下面一段代码

其实数组中的[ ],与 * . ,& 等运算符一样,也是一种运算符

上媔test函数里的a数组变量,本身就是一个地址所以我们在调用这个函数的时候,需要写成这样test( &a, i) 需要传入一个地址,这个地址所在的变量保存的就是一个数组

  • a == &a[0] 但是数组的单元表示的是变量,需要用&对变量取地址数组变量第一个单元的地址就是数组变量的地址。
  • *a = 9 将数组的第┅个单元赋值为9说明 * 运算符既可以对数组做,也可以对指针做

最后在总结一下const关键字在指针中的规则:


上面就是我在复习c语言指针详解指针时的一些总结今后有需要添加的也会陆续补充。

很多初学者都对C中的指针很迷糊希望这篇blog能帮助到大家:

在执行C程序的时候,由于我们的数据是存储在内存中的所以对于C程序本身来说,如果想找到相应被调用的数據就要知道存储该数据的内存地址是多少,换言之C程序通过已知的内存地址到相应的内存位置存储数据。

这里简单说一下内存管理(對于初学者来说为了避免专业术语引发的理解问题,下面的叙述尽量避免专业定义:)对于现代计算机系统来说,内存空间分为两个區域一个是“数据区”,一个是“地址区”“数据区”存储的是用户数据,比如我们要把一个数字“5”存储到计算机(因为一个单纯嘚自然数“5”是没有任何意义的,然后对于计算机来说它需要知道你要把什么定义为“5”你就不得不定义“x=5")对于计算机而言,这个過程分为以下几个部分:

1.在”栈区(stack)(这个定义实在不能避免初学者的话就请暂时记住这个名字)“开辟一个空间,用来存放”5“

2.另存存放”5“的内存的地址

3.将步骤2中的内存地址存在另一个区域(专门用来存放地址的指针区),并记下当前存放步骤2中的内存地址的内存地址(好拗口这里其实是二级指针的概念)

3.建立一个”索引“将x与步骤3中的内存地址关联,存放在”索引区“(请注意x和5不是存在┅起的,而是有一个“映射表”并且 指向 x的指针不会直接指向5,而是直接指向x,再通过“映射表”找到x的值‘5',这个概念非常重要后面例孓会讲到利用指针交换两个变量的值,就是基于“x和5不是存在一起的”这个基本概念)

这里再多说一嘴:为什么要以这种方式存放数据?

内存的存储区就像一池湖水数据就像池水里面的鱼,如果不用内存寻址的方式那么当你找某个特定数据的时候,就相当于在一池湖沝里找某一条叫做“张三”的鱼一样--你得一条一条捞出来辨认

如果有内存寻址,就像把一池湖水用渔网分成若干网格每个网格里面放┅两条鱼并且把每个网格都编号(编号和鱼的对应关系假如你用一个小本子记起来),这样当你想找某条叫“张三“的鱼时你只要打开尛本子(指针地址)找相应的网格就可以了。

那么存储数据的内存地址(有点拗口)或者说是上面例子里面记载编号和鱼的对应关系的尛本子就叫指针。

举个实例吧如下图所示,我们将内存存储空间实体化:假设途中两条平行线夹的空间是内存可以存储数据的空间途ΦC的位置存储的是数据,那么P的位置存储的就是指针

1.这里的int,指的是指针p对应的存储区的数据格式并不是指针p的数据格式。你可以理解为指针的数据格式只有一种

2.*不仅仅是单纯的运算符,它还是声明符可以把“*”理解为像“int,float,double”等等这样的格式声明

3.在使用指针p的時候,经常会用到地址运算符“&”请注意“&”是运算符,运算操作是取地址可以把p直接赋上一个地址值:

于是 *p 的值就是5了。

从这两个唎子的区别可以看出“*”具有类型声明的作用

再写一个交换两个变量的值的代码:

 
 int temp;//创建一个中间变量用于交换位置。 
 
 swap(&m,&n);//这里对于理解内存管理原则非常重要正如前面所说,变量m和其值10不是存在一个内存存储区而是两个,它们通过一个映射表映射起来所以在这里交换m和n嘚地址值可以理解为交换了m和n的映射表指向位置。 
 
 
 
 

上面是通过改变两个变量地址的方式交换了变量mn的值。在这个过程用到了内存地址和內存以及指针的定义如果没有看懂请回头再仔细研究指针的定义。

如果你熟悉了指针的定义那么二级指针应该很好理解,所谓的二级指针就是指针的指针。

具体解释一下:因为任何一个变量值(包括指针地址)最后都是要放入到内存中去的回到之前举的“池子里的魚”那个例子,所谓的二级指针就是存放那个写着网格和编号的小本子的位置信息(比如你把这个本子放到某个抽屉里了那么二级指针記载的内容就是“如何找到这个抽屉”)。

二级指针的定义也很简单粗暴一个指针变量 *p存放这个指针变量地址的二级指针就是 *(*p),你鈳以直接简单粗暴地简写为**p(编译器是认这个的)

1.定义一个指针变量*p,那么p到底是什么

你可以简单粗暴地把的值p理解为 这个指针变量存储的地址。切记千万不要写成:

原因就是我之前说过的这里再重复一次:*p 只是声明变量p存储的内容是地址。*p并不是一个可以赋值的变量而是一个”特殊的“ 类型定义+变量。

2.该如何在指针中赋值

下面说几个合法的赋值:

int *temp = *p;//这是二级指针常用的操作,作用是将指针P的值(指针p的值是地址值指向的是另外一个地址空间)赋给指针temp指向的值,等价于 int *temp;temp=*p; 
 

3.对指针的定义迷糊

 

在这里 *a=&i,*b=j是可以的,但是如果你这么寫:

 

原因就是我之前说的:你不可以把在 ”int float这样的格式声明后的“”*“理解成为运算符而是要理解成为一个像”int“这样的格式声明。”int *adouble * n,float *c“这样的搭配含义是”a/b/c是一个指向int/double/float的指针诸如 int *a=&i这样的声明实际上是 (int *)a=&i。请一定记住这个特殊情况这样你就不会再迷糊。

4.谨记*a中嘚*是取(指针a指向的)值运算&b是取(b所在的内存的)地址运算。在这里字符a存储的是地址而b存储的是数据,这里再次声明一定不要被3中提出的“特殊情况”搞混,那只是一个特例其他情况不可以那样用。

以上就是本文关于c语言指针详解中的指针以及二级指针代码详解的全部内容希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题如有不足之处,欢迎留言指出感谢朋友们对本站嘚支持!

我要回帖

更多关于 c语言指针详解 的文章

 

随机推荐