c语言指针的复习

1. 指针的概念
要理解指针,必须清楚几个概念:指针类型、指针指向数据类型、指针指向数据的大小、
指针在内存中占空间大小。如:int *p。
指针类型:把变量名去掉,就是指针类型,如int *是整形指针,就是指针的类型。
指针指向数据类型:把变量名去掉,再去掉*,int就是指针指向数据的类型。
指针指向数据的大小:指针指向数据类型为多大,那么数据的大小就为多少。
指针在内存中占空间大小:指针在内存中始终是一个占四个字节的数据类型,而不管是指向数据是什么类型。
2. 指针的声明
指针类型  指针变量名;
如:int *p;//定义一个整形指针变量,其指向一个整形整数。
3. 指针的运算
定义一个数组和指针
Char A[]={‘a’, ‘b’, ‘c’ ‘d’, ‘e’};
Int *p=A;
那么p++到底是p移动一个指针类型的大小,还是移动一个指向数据类型的大小呢?移动一个数据类型的大小,想一下,如果移动一个指针类型的大小,那么就移动四个字节,而字符在内存中占一个字节,那岂不是越界了么?所以知道p++指向哪个地方了吧。
4.指针和数组
定义一个数组Char A[]={‘a’, ‘b’, ‘c’};
则A指数组的首元素,&A指数组的地址,所以要把一个数组赋给一个指针,一定要写清楚,虽然两个地址是一样的,但是代表意义不一样,所以要好好区分。
如果把数组赋给一个指针,则:char *p=&A;而char *p=A;严格来讲不规范的。
5.指针应用
要区分一下两个概念,可以从运算符的优先级来考虑,如:(*p)运算符()优先级高,所以在这里定义一个指针变量,指针指向一个int [10]的数组,而第二个p[10]p与[]结合表示定义一个有十个指针的数组。
定义一个指向数组的指针:int(*p)[10]
定义一个有十个指针的数组:int* p[10]
例子:
第一种:用一个指向数组的指针来访问二维数组
int  a[4][5],*p[4],i;     //p表示指针数组
for( i=0;i<4;i++ )
    p[i]=a[i]; /*有了这个定义后,指针数组p中的每一个指针分别指向了二维数组a每一行的首地址,以后通过p就可以访问a */
访问格式:p[i][j]   ,   (*(p+i))[j]   ,  *(*(p+i)+j)  ,  *(p[i]+j)   都表是a[i][j]
eg: p[1][1]=1;     //相当于a[1][1]=1; 、
 
第二种:用一个指向有5个指针元素的数组来访问二维数组
int  a[4][5],(*p)[5];     //p表示数组指针
p=a;
/*有了这个定义后,数组指针p指向了二维数组a的首地址,以后通过p就可以访问a */
访问格式:p[i][j]   ,   (*(p+i))[j]   ,  *(*(p+i)+j)  ,  *(p[i]+j)   都表是a[i][j]
eg: p[1][1]=1;     //相当于a[1][1]=1;
 
6.使用指针要注意的问题
指针用得好,能够很方便的实现用户的功能,如果用不好,则会引发好多的问题:
l         指针所指存储区访问安全的问题
如:char s=’a’;
Int *p=(int)&s;
*p=1234;
如果这样定义,会引发一个问题:p后面三个自己指向的内容是什么?如果程序中用到的另一个变量的值,那么就会改变这个变量的值,这样会导致程序的崩溃。
l         指针创建必须要被初始化。
l         指针申请内存时必须赋予初值。
l         指针指向一块内存后,如果内存被释放掉,必须把指针指向NULL。
l         释放内存时,如果是数组指针,必须通过delete []p释放内存,并且要把指针指向NULL。
如:char *p=new char[5];
Strcpy(p,”aaa”);
则使用完之后要delete []p;p=NULL;
如果使用malloc,则要使用free释放相关申请的内存。
l         数组指针的内容不能超过数组指针的最大内存空间。
7. 分析指针的复杂申明
分析要点:记住int *p[]和int (*p)[]两者的区别,其他的复杂声明都是从这个基础上衍生过来的,另外要清楚修饰符是修饰哪一个元素的。
如:int (*func[5])(int *p) //返回值是int数组的指针,函数有一个int指针类型的参数,*是修饰func[5],表示func里面5个元数是指针。
8.右左法:应用分析指针的复杂申明
右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
上面尽管是已经说得很通俗易懂了,但是离实用还隔着一层窗户纸。我(也就是这个博客的HOST)还要对它加上一条说明:“对我们汉语人群,每次用一句话概括一次转向到下一次转向的内容,每一次的宾语是下一次的主语”。由于本人不是研究语言的,所以这句话说得很晦涩,所以用例子来加以说明。这里的例子都是网上原文中的例子,但是用我的这一条原则加以说明后就更清楚易懂了。
int   (*func)(int   *p);
首先找到那个未定义的标识符,就是func。它向右是括号,然后向左,是*,用语言表达为“func是一个指针”。这一句话的宾语是“指针”。向右碰到(int *p)。由于上一句话的宾语是"指针“,所以这一句话的主语是”指针“,则这一次便为”这个指针指向的是一个函数"。宾语为“函数”。向左碰到int,即为“这个函数的返回类型为整型"。再把三句话连起来便很清晰了。
int   (*(*func)[5])(int   *p);
用同样的方法翻译,即为:func是一个指针,指针指向的是一个五维数组,数组元素的类型为指针,指针指向的是函数,函数的自变量为指针,指针指向的为整型。可以看到上面几句话每一句的宾语都是下一句的主语。大家可以自己根据上面的方法右左右左地来分析。
9. 指针常用问题解析
指针常见的问题:指针越界,指针没分配内存,指针指向的内存没初始化。
如:
Char *p=NULL;
P=(char *)malloc(sizeof(char)*50);//给指针p分配一个50个字符空间的内存
Memset(p,0,50);//给p指向的内存空间50个字符长度初始化为0
在指针的操作过程中,如果出现异常,则很可能指针被改变了,导致输出结果不准确或者越界。
10.    指针练习题
l         有一个数组int A[nSize],要求写一个函数:
int * myfunc(int *p,int nSize);
将A中的0都移交只数组末尾,将非0的移至开始(保持原来的顺序不变)
例如:
A原来是:1,0,3,4,0,-3,5
经过myfunc处理后为:1,3,4,-3,5,0,0
l         编写函数void fun(int x,int *pp, int *n),他的功能是,求出x的偶数因子,并按从小到大的顺序放在pp所指的数组中,这些因子的个数通过形参n返回(假设pp指向足够大的空间)。如,若x中的值为24,则有6个数符合要求,它们是2,3,4,5,12,24
l         实现一个比较字符串大小的函数,也即实现strcmp函数。
l         对奇阶魔方阵,可用Dole Rob算法生成,其过程为:
从1开始,一次插入个自然数,知道N平方为止。
选择插入位置原则为:
a、  第一个位置在第一行的正中
b、  向已填充的前一个数字位置(p、q)的左上角(p-1、q-1)填入下一个数字,如果出现以下情况,则修改填充位置:
1)、若填充位置超出上边界,则修改为下边界的相应位置,即把p-1修改为n-1
2)、若填充位置超出左边界,则修改为最右边的相应位置,即把q-1修改为n-1
3)、若填充位置已有数字,则修改为该数字(当前数字)的下一行同一位置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值