吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5341|回复: 27
收起左侧

[C&C++ 转载] 分享一下大一老师让做的关于指针的总结!希望对小部分人有点用处!

   关闭 [复制链接]
君莫笑WXH 发表于 2017-3-15 19:59
本帖最后由 君莫笑WXH 于 2017-3-15 20:04 编辑

   指针应该算得上是C语言的精华,但也是难点。可以说同学C语言学的好坏,简单通过指针就可以看出来!
计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,
  例如 int 占用4个字节,char 占用1个字节。为了正确地访问这些数据,必须为每个字节都编上号码,就像身份证号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。
  我们将内存中字节的编号称为地址(Address)或指针(Pointer)int a;举个例子,a 就相当于你的名字,而指针指向的是你的身份证号码(唯一性)。
  C语言用变量来存储数据,用函数来定义一段可以重复使用的代码,它们最终都要放到内存中才能供 CPU 使用。
    Tip:理解
  先来想象一下,你正在进行一个密室逃脱真人游戏,发现桌子上有一张纸条,纸条上写着“书柜第二层第三本书66页”,你肯定会跟随纸条的内容找到那一页的内容。那么接下来我们来看一段代码:
int a;int*
pi;pi=&a;  //这里可以将 &a理解为返回a的地址
  pi不就相当于那个纸条么,而纸条内的内容“书柜第二层第三本书66页”不就相当于a的地址,你在看到纸条,自然而然去访问到了这个地址上的内容。
  数据和代码都以二进制的形式存储在内存中,计算机无法从格式上区分某块内存到底存储的是数据还是代码。当程序被加载到内存后,操作系统会给不同的内存块指定不同的权限,拥有读取和执行权限的内存块就是代码,而拥有读取和写入权限(也可能只有读取权限)的内存块就是数据。
    CPU 只能通过地址来取得内存中的代码和数据,程序在执行过程中会告知 CPU 要执行的代码以及要读写的数据的地址。
如果程序不小心出错,或者开发者有意为之,在 CPU 要写入数据时给它一个代码区域的地址,就会发生内存访问错误。
这种内存访问错误会被硬件和操作系统拦截,强制程序崩溃,程序员没有挽救的机会。
    CPU 访问内存时需要的是地址,而不是变量名和函数名!变量名和函数名只是地址的一种助记符,当源文件被编译和链接成可执行程序后,它们都会被替换成地址。编译和链接过程的一项重要任务就是找到这些名称所对应的地址。假设变量 a、b、c 在内存中的地址分别是 0X1000、0X2000、0X3000,那么加法运算c = a + b;将会被转换成类似下面的形式:0X3000 = (0X1000) + (0X2000);( )表示取值操作,整个表达式的意思是,取出地址 0X1000 和 0X2000 上的值,将它们相加,把相加的结果赋值给地址为 0X3000 的内存
一、基本使用先来看看下面的代码:
1. int i = 3;  
2. intint *p;      
3. p = &i;        
4. printf("i 存放的内容的值: %d, i 自己所在的地址: %p\n", i, &i);     
5. printf("p 存放的地址的值: %p; p 自己所在的地址: %p; p 存放的地址所指所存放内容的值: %d", p, &p, *p);        
6. return 0;   变量i是int类型,所以存放的是int数据。变量p是int *类型,所以存放的是指向int类型的地址
图片1.png
1. int i = 3; 这句话执行完毕之后,变量i中的内容是3,假设变量i本身的内存地址为 "0x6666"。2. int *p; 只是为指针变量p申请了一块内存地址,假设它的内存地址为 "0x8888"。3. p = &i;
表示将变量i的地址赋值给指针p所存放的内容,至此,就呈现出了上图的情形。
所以程序中的那两句打印结果就很明显了。
输出:i 存放的内容的值: 3, i 自己所在的地址: 0x6666p 存放的地址的值: 0x6666; p 自己所在的地址: 0x8888; p 存放的地址所指所存放内容的值: 3
二、 交换两个整数的值
示例代码如下:
1.
2. int main()
3. {  
4.     int a = 3, b = 5;
5.     int swap(int *a, int *b)
6.     swap(&a ,&b);  
7.     printf("a: %d; b: %d", a ,b);  
8.     return 0;  
9. }
10. int swap(int *x, int *y)
11. {  
12.     int temp = *x;  
13.     *x = *y;  
14.     *y = temp;  
15. }
当程序执行完 int a = 3, b = 5, 然后调用swap(&a, &b); 注意,这里传递的是变量a, b 本身的地址。而函数swap的接受形参int *a, int *b均是指针变量,用来接受传递过来的变量a, b的地址,即传递过来的变量a, b 和 函数 swap中的形式参数a, b 完全是两回事;
1. int temp = *a,  定义一个临时变量temp,用来存储指针swap_x 所指向变量a所存储的值,
2. *x = *y, 表示将将指针swap_y所指向变量b的内容赋值给指针swap_x所指向变量a的内容
3. *y = temp, 就是将temp所存储的内容赋值给指针swap_y所指向的变量b存储的内容
三、 数组与指针
1.指针访问数组元素
不知道大家是否看了我上一个关于数组的总结,里面提到了,在你定义了一个数组 int a[];那么a代表数组的首地址,代表数组第一个元素的地址。大家来看下面一段代码:int i,*p,a[]={5,2,0,1,3,1,4};p=a;for(i=0;i<7;i++)printf(%d,p);很显然,这样也是输出数组a内的值。在看另一段代码:int i,*p,a[]={5,2,0,1,3,1,4};p=a;for(i=0;i<7;i++)printf(%d,*(p+i));以上两段代码输出内容是相同的,故不难理解“a代表数组首地址这句话”。其实,数组名也就是一个指针,它是该数组的首地址。  
2.数组名与指针变量的区别
int i,*p,a[]={5,2,0,1,3,1,4};
p=a;
for(i=0;i<7;i++)
{
  printf(%d,*p);*p++;  //此时指针值被修改
}
可以看出,这一段代码也是将数组各元素输出。有些人可能会说,既然数组名也是一个指针,那么可不可以将代码{  }内的p改成a,你们可以试试,编译出错!!!其实指针p是一个指针变量,而a则是一个指针常量。上面的代码中,指针p在整个循环中,其值是不断递增的,也就是说指针值被修改了。而数组名是一个指针常量,其值是不能修改的,因此不能进行类似的操作:a++。而在前面,*(p+i)处,指针p的值始终未改变,所以,此处p可用a替换。
四、 传递 不知道大家知不知道C语言中函数参数的传递有哪几种? 值传递,指针传递,引用传递。我相信正是这几种参数传递的形式,才会让大家晕针。题一为 值传递,
图片4.png
值传递的一个错误认识
问:你认为这个函数是在做什么呀?
答:好像是对参数 x,y的值对调吧?
请往下看,我想利用这个函数来完成对a,b两个变量值的对调,程序如下:
问:Exchg1 ()里头的  printf(“x=%d,y=%d\n”,x,y)语句会输出什么啊?
再问:Exchg1 ()后的  printf(“a=%d,b=%d\n”,a,b)语句输出的是什么 ?
程序输出的结果是:
x=6 , y=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的关系了。
其实函数在调用时是隐含地把实参a,b 的 值分别赋值给了x,y,之后在你写的Exchg1函数体内再也没有对a,b进行任何的操作了。
交换的只是x, y变量。并不是a,b.当然a,b的值没有改变啦!函数只是把a,b的值通过赋值传递给了x,y,函数里头 操作的只是x,y的值并不是a,b的值。
这就是所谓的参数的值传递了。

题二为 指针传递

图片3.png
指针传递的目的,不是改变实参的值,而是通过改变*px,达到改变a的目的之所以能通过改变*px,改变a的值,是因为px=&apx代表的是a的地址。
把地址传递给函数,在函数里通过这个地址,就能改变里面存储的数据。这样就达到了调用函数交换的目的。
题三为 引用传递
图片5.png
指针传递不同的是,形参a,b的地址也与x,y相同,交换a,b就相当于交换x,y。
针传递和引用传递一般适用于:函数内部修改参数并且希望改动影响调用者。对比值传递,指针/引用传递可以将改变由形参“传给”实参(实际上就是直接在实参的内存上修改,
不像值传递将实参的值拷贝到另外的内存地址中才修改)。指针/引用传递的另外一种用法是:当一个函数实际需要返回多个值,而只能显式返回一个值时,
可以将另外需要返回的变量以指针/引用传递给函数,这样在函数内部修改并且返回后,调用者可以拿到被修改过后的变量,也相当于一个隐式的返回值传递吧。               
五、 二级指针
二级指针为了改变该指针指向的变量的指向。改变p指针所指的方向。
1. #include<stdio.h>  
2. int main()  
3. {  
4.     int a=12,*p,**ptr;  
5.     ptr=&p;  
6.     p=&a;  
7.     **ptr=34;  
8.     printf("%d %d %d\n",a,*p,**ptr);  
9. }          
**p是双重指针,p可以指向其一个指针的地址,即变量里面放数据,指针里面放变量的地 址,二级指针放指针的地址  
Tip:对未初始化指针取值使用指针,有一个规则需要特别注意:不能对未初始化的指针取值!!!   
例:     
int* pt;  // 未初始化的指针     
*pt = 5; // 一个可怕的错误!表示把数值5存储在pt所指向的地址中。   
但是由于pt没有被初始化,因此它的值是随机的,不知道5会被存储在什么位置。这个位置也许对系统危害不大,但也许会覆盖程序数据或代码,导致程序的崩溃。   
切记:当创建一个指针时,系统只分配了用来存储指针本身的内存空间,并不分配用来存储数据的内存空间。因此在使用指针之前,必须给它赋予一个已分配的内存地址。
再如:        
char* name;        
scanf("%s", name);   
这可能会通过编译器,但是在读入name的时候,name会覆盖程序中的数据和代码,并可能导致程序异常终止。这是因为scanf()把信息复制到由参数给定的地址中,而在这种情况下,参数是个未初始化的指针,name可能指向任何地方。

这些都是自己根据一些书本内容,博客加上自己理解总结出来的,希望对大家有用!大神勿喷,感觉初学指针的小伙伴还是有帮助的!

免费评分

参与人数 8吾爱币 +8 热心值 +8 收起 理由
rico_xiang + 1 + 1 我很赞同!
sphao + 1 + 1 感谢分享,学到了
Gh0stRo2kie + 1 + 1 用心讨论,共获提升!
钱小样 + 1 + 1 我们老师就让自学,多难都要自学。
ptshj + 1 + 1 用心讨论,共获提升!
yempty + 1 + 1 谢谢@Thanks!
刘串 + 1 + 1 真好需要
banon22421 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 君莫笑WXH 发表于 2017-3-17 00:10
guozj 发表于 2017-3-16 18:38
第二个 难不成是声明一下函数 声明的话不是应该main函数前面吗

那样写没问题的,我在main里面有声明所以放后面去了……看喜好……怎么方便,容易看
siwuxie095 发表于 2017-3-16 18:32
君莫笑WXH 发表于 2017-3-16 18:29
哈哈,我们是小组内讨论学习……带了4个妹子……所以写的详细点……我觉着认真看会会有点用

厉害厉害,详细些也好
lovxyj 发表于 2017-3-15 20:06
siwuxie095 发表于 2017-3-15 20:22
[fly] 感谢楼主分享,讲解的不错,就是有点长了 [/fly]
guozj 发表于 2017-3-15 22:23
楼主好厉害 啊 佩服佩服了 只是有个问题主函数里面的第二个语句 是不是可以不用写
Hibiki 发表于 2017-3-15 22:51
感谢分享,刚好最近教到指针相关的
真爱贤 发表于 2017-3-16 08:15
可以的,小伙子!!!
Lion1505 发表于 2017-3-16 08:39

谢谢楼主分享,学习一下
banon22421 发表于 2017-3-16 09:30
通俗易懂,很不错
Huiever 发表于 2017-3-16 13:49
学习了,谢谢分享
 楼主| 君莫笑WXH 发表于 2017-3-16 17:59
guozj 发表于 2017-3-15 22:23
楼主好厉害 啊 佩服佩服了 只是有个问题主函数里面的第二个语句 是不是可以不用写

哪一个代码?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-27 01:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表