Stark_【指针】一点个人的指针学习记录

来源:互联网 发布:日系淘宝店铺推荐 编辑:程序博客网 时间:2024/05/01 12:26


指针是一个很神奇的东西,反正你不好好学会挂科就是了。
整理一下个人的学习笔记+代码示例,这是一个新手写的,资料来源于谭浩强《C程序设计》,第四版。
一.指针是什么?
指针指向的是一个地址,例如 int  *p(此处以int为例而已),指向一个地址,比如说,让你去找钢铁侠,你至少要知道钢铁侠住在哪里是不是?指针也就是提供地址给你 的一个东西。就是取出我们所需的地址。
举个例子:


#include <stdio.h>#include <stdlib.h>int main(){int *p1;int a=1;p1=&a;printf("%d\n",p1);return 0;}


---------------

#include <stdio.h>#include <stdlib.h>int main(){int *p1;int a=1;p1=&a;printf("%d\n",*p1);return 0;}


----------------

二.在应用中出现的一些小错误。
进行比较以后容易发现,在输出的时候,p1的前面是有*和没有*,输出以后是不一样的,有*的话,输出的就是1,表示取出a表示的地址后,输出这个地址的值,就好像你跑到了美国,找到了钢铁侠啦,然后要到了签名是一样的道理。没有*,就是说你已经到了美国,找到了钢铁侠的地址,但却没有要到签名一样。
但是注意,不能把一个整型或者其他float,char,什么的变量直接赋值给指针变量哈,VC6.0虽然不会报错,但是绝对得不到你想要输出的东西。
另外还要注意一点,这里写一个伪代码。


int *temp,*a;int b=25;a=&b;*temp=*a;


any problem?对的,在这里*temp指向了一个未知的地址,或者说是根本不存在的地址,但是a则有具体值,就好比你想把一个东西放进去一个根本不存在的地址里,可能吗?肯定是不可能的。
三.通过指针引用数组
1.引用数组元素指针的运算
比如,int *p,p++ or p--表示指向下一个元素。
举个例子:
比方说,我读入几个数,我用指针的方法来进行输出。


#include <stdio.h>#include <stdlib.h>int main(){int *p;int a[5],i;//我比较懒,输入5个数字好啦for(i=0;i<5;i++){scanf("%d",&a[i]);}//读入数据完成;p=a;//指向元素的首地址;for(i=0;i<5;i++){printf("%d ",*(p+i));//注意哈,没有*,输出的就是地址啦,还有那个神奇的括号,不打就粗事情了。//注意规范格式;}printf("\n");return 0;}


来一波简化版,如下:


#include <stdio.h>#include <stdlib.h>int main(){int *p;int a[5],i;for(i=0;i<5;i++){scanf("%d",&a[i]);}p=a;for(p=a;p<(a+5);p++){printf("%d ",*p);}printf("\n");return 0;}


补充说明一下关于指针所占字节数的说明,大家都知道,int 为4个字节,char为1个字节,但是,无论什么类型的指针,字节数都为4.
接着之前的来,再来一波坑爹版。


#include <stdio.h>#include <stdlib.h>int main(){int *p;int a[5],i;p=a;//p指向a[0]for(i=0;i<5;i++){scanf("%d",p++);//读入时不要*}p=a;//初始化,这里是一个坑233for(i=0;i<5;i++){printf("%d ",*p++);//输出时记得*}printf("\n");return 0;}


2.通过指针指引多维数组
这个东西的格式要很小心,因为一不小心就错了。
a[0],*(a+0),*a--->都是0行0列首地址
a[1],*(a+1)---->1行首地址
--下面两个例子要高度注意啊----
①a[1]+2,*(a+1)+2——>都表示的是a[1][2]的地址;
②*(a[1]+2),*(*(a+1)+2),a[1][2]——>表示的是a[1][2]的值。
【补充】,知道行数和列数怎么求出一个数字相对于开头的位置。
(i-1)*m+(j-1)//这里,m表示的是一行有m个元素。
===================神奇的分割线====================
下面,我把用 【指向数组的指针作为函数参数】,【返回指针值的函数】 放在一起记录下来。
为啥这条分割线这么神奇,因为谭浩强教授在写书的时候这三个东西用的例子很相似,所以Po就写一起了呗。
【指向数组的指针作函数参数】
例题,有一个班,3个学生,4门课程,计算一下总的平均分以及第n个学生的成绩。
思路:根据要求,这个题用指针来写,调用函数,average求平均数,search求需要查找的学生成绩。


#include <stdio.h>#include <stdlib.h>int main(){void average(float *p,int n);void search(float (*p)[4],int n);float score[3][4]={{65,67,70,60},{80,87,90,81},{90,99,100,98}};average(*score,12);search(score,2);//有话说,注意到两次调用的时候score之前的*号问题了吗?//如果是定义了(*p)[4]这种类型的,调用时,哪怕调用函数的行参那里是指针,这里只要写出调用的数组名就好;//但是,如果不是所说的这种类型的话,不要漏掉*号,OK?//补上官方解释://search(score,2),起始地址为score[0]作为实参;//but,虽然我不是辣么正规,但是至少记住了可以避免wa;return 0;}void average(float *p,int n){float *p_end,aver;int i;float sum=0;p_end=p+n-1;//此时我们输入的是12个成绩,即指向数组的最后一位;for(;p<=p_end;p++){sum=sum+(*p);}aver=sum/n;printf("%.2f\n",aver);}void search(float (*p)[4],int n){int j;for(j=0;j<4;j++){printf("%.2f ",*(*(p+n)+j));}printf("\n");}



是不是hin简单?内心:wtf..这块部分我看了很多遍,有很多很细节的问题,果然,书,永远不能只看一遍的。
来,下面,我们把这个题升级一下哈,interesting!
在上面一题的基础上,把输出第n个学生的成绩改成,查找有不及格的学生的成绩,然后输出该学生的所有成绩。


#include <stdio.h>#include <stdlib.h>int main(){void fun(float (*p)[4],int n);void search(float (*p)[4],int n);float score[3][4]={{65,67,70,60},{80,87,90,81},{90,99,100,98}};fun(score,3);search(score,2);return 0;}void fun(float (*p)[4],int n){int i,j,flag;for(i=0;i<n;i++){flag=0;//解决初始化问题for(j=0;j<4;j++){if(*(*(p+i)+j)<60)flag=1;}if(flag==1){for(j=0;j<4;j++){printf("%.2f ",*(*(p+i)+j));}}}printf("\n");}void search(float (*p)[4],int n){int j;for(j=0;j<4;j++){printf("%.2f ",*(*(p+n)+j));}printf("\n");}


【指向返回值的指针】


#include <stdio.h>#include <stdlib.h>int main(){float *search(float (*pointer)[4]);float score[3][4]={{56,67,70,60},{80,87,90,81},{90,99,100,98}};float *p;int i,j;for(i=0;i<3;i++){p=search(score+i);//调用search函数,对第一行进行判断,相当于*(*(p+i)+j)//saerch函数里i是对列进行操作,这里i是对行进行判断if(p==*(score+i))//如果函数的返回值不为NULL,那就说明有人不及格了,在此默哀{for(j=0;j<4;j++)//以列来输出指向的成绩{printf("%.2f ",*(p+j));}printf("\n");}}return 0;}float *search(float (*pointer)[4]){int i=0;float *pt;pt=NULL;for(;i<4;i++){if(*(*pointer+i)<60)pt=*pointer;//啊哈,这里有个地方和上一题不一样了吧,这里没有*(*(p+i)+j)了,而是(*(*pointer+i))//注意一下,由于我们习惯i表示行,j表示列,这里的i实际上表示的是列}return pt;}


既然列举了两种不同的写法,那就来说一下两种不同的写法有什么区别吧。
指针嘛,就是套路的问题,第一种写法,也就是【指向数组的指针】,是void,木有返回值,在进行函数调用的时候用的是*(*(p+i)+j)的形式,就是两层循环,for(i;;),for(j;;),再加上一个成绩和60的大小判断即可;
第二种写法【指向返回值的指针】,注意,在写调用函数的时候的格式,函数名的前面有*号,小问题,反正不写就是错的2333,这个呢,有返回值,返回的是一个地址,在main函数里进行操作的时候,是以地址的形式来进行操作的。这样说可能显得有点乱七八糟的,那就分个点:
①search函数返回的是一个地址;
②在main函数中定义了一个循环,对读入的地址进行操作;
③在search函数里,定义的指针变量是指向每一列的,判断有没有不及格的成绩,在主函数里通过行(就是每个学生)来判断其每个科目的成绩,所以在main函数的for循环的第一层循环里就有了p=search(score+i);熟悉的配方,这不就是*(*(p+i)+j)了吗?
④在main函数里继续判断,ok,在search函数里我们定义的*pt一开始不是pt=NULL了吗?如果有成绩小于了60,那么*pt就指向了那个元素的所在列的首地址,加之带入主函数,由i就能get到具体的地址,满足条件的话呢,就在第二层循环里输出啦;
⑤那么,问题又来了,为啥这里的*p只用写为*(p+j)呢,hin好,因为它在之前的循环里已经指向了行的首地址了呀。
-------------以上,分析完毕------------------


四.指向函数的指针
如果想调用一个函数,除了可以通过函数名调用以外,还可以通过指向函数的指针变量来进行调用。
1.来一波格式:
类型名    (*指针变量名)(函数参数表列)
如:int (*p)(int,int)
2.这个比起上面的来简直无比简单,看个例子就懂了,那么,来一波例子。


#include <stdio.h>#include <stdlib.h>int main(){int fun(int x,int y,int(*p)(int,int));int max(int x,int y);int min(int x,int y);int a,b,n;while(~scanf("%d",&n))//n用来控制接下来要取max还是min{scanf("%d %d",&a,&b);if(n==1)fun(a,b,max);//简单吧?把函数名写在后面就okif(n==2)fun(a,b,min);}return 0;}int fun(int x,int y,int(*p)(int,int)){int result;result=(*p)(x,y);printf("%d\n",result);return 0;}int max(int x,int y){int z;if(x>y)z=x;elsez=y;return z;}int min(int x,int y){int z;if(x<y)z=x;elsez=y;return z;}


啊哈,我在这里发现了一个有趣的东西,我偷懒就直接照着书上打,然后还删了add这个函数,反正懒,回归正题,这本书第272页的fun函数是int类型的函数,但是木有返回值,2333,还有就是之前的查找那题有一个地方书上漏了一个“  ; ”。
--------分割线----------
先写到这里,后面的等老师讲完我自己理解完再写出来哇咔咔~




                                             
0 0
原创粉丝点击