您的位置:首页 > 编程语言 > C语言/C++

c语言指针的复习

2015-07-19 11:16 316 查看
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],(
4000
*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)、若填充位置已有数字,则修改为该数字(当前数字)的下一行同一位置。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: