阴雨连绵,不能外出,只好窝在家里看书!
看啥呢!想起多年的C语言!想到了C里的指针!忘的差不多了,于是找了些资料看看!发现真忘的差不多了!
所以整理下在阅读资料的基础上关于C指针的知识吧!
这里权当自己做个笔记了!如果哪位同学搜到了本篇博文,能够获得一点帮助或启迪!那就最好不过了!
废话结束!
请大家重点阅读第五章数组和指针的关系,这里讲的比较透彻,摘选自C专家编程。
、、、、、、、、、、、、、我不是分割线、、、、、、、、、、、、、、、、、、、、、、、、、
一、指针相关的概念和知识点
相信大家都听老师说过,指针就是地址,但是这句话到底是什么意思呢?
其实是这个意思,
举个简单的例子,int a = 3; 此 a 是一个整型变量,存储的值是3.这点大家应该都能明白。
上图:在内存中的表示如下图所示
再举个例子,int a = 3;int *b = &a; 这句话的意思也估计都能明白把整型变量a的地址赋给了指针变量b;
这时候b存的其实也一个整数,和具体的平台有关,32位平台就是一个32位的整数,可以通过sizeof(b)测得;
这时b存的值是什么呢,就是前面的 00001,是一个地址;这就是指针变量!
好了,说好了指针变量这个概念,下面再细说下指针的相关知识点!
指针的类型 指针所指向的类型 指针的值或指针所指向的内存区 指针本身所占据的内存区域
1)指针的类型,如果从语法的角度来说,只需要去掉指针声明语句中的指针变量名去掉,剩下的部分就是这个指针的类型。
eg:
int *p; // 指针的类型是 int *;
char *p; // 指针的类型是 char *
int **p; // 指针的类型是 int **
int (*p)[9]; // 指针的类型是 int(*) []
这个找出来还是挺简单的!
2)指针所指向的类型
当通过指针访问指针所指向的内存区域时,指针指向的类型就决定了编译器把这块内存区域的内容当成什么样的类型来看待。
仍然是从语法上来说,找出指针所指向的类型只需将指针声明中指针变量名和变量左边的*去掉,剩下部分就是指针指向的类型
eg:
int *p; // 指针所指向的类型是 int
char *p; // 指针所指向的类型是 char
int **p; // 指针所指向的类型是 int *
int (*p)[9]; // 指针所指向的类型是 int() [ ]
3) 指针的值
指针的值是指指针本身存储的数值,就像开篇举得例子中的int *b = &a; 此时b的值是00001,这个值被编译器当作一个地址来对待,而不是一个一般的数值。在32位程序中,指针的长度是32位;
4)指针本身所占据的内存区
这个只要用sizeof(指针的类型)就ok了。
=====================我是分割线吗===========================
说好了指针的相关观念,下面来说下指针的算术运算
二、指针的算术运算
大家都知道,指针变量可以加上或者减去一个整数,这和普通的算术运算还是很大差异的,下面细说
char c[10];
int *p = (int *)c;
p++;
指针p的类型是:int *,
p指向的类型是 :int
p 初始化为指向整型变量c;接下来执行了p++,那么编译器是如何处理的呢?
编译器首先计算出:sizeof(int)的值,32位程序中是4,因为int占4个字节,所以p指向的地址由原来的变量c的地址向高地址方向增加了4个字节。由于char占一个字节,原来p指向c的第0号单元开始的四个字节;此时指向了c从4号单元开始的四个字节。
指针和指针之间的加减法
两个指针是不能进行加法运算的,这属于非法操作,如果相加,得到的结果指向一个不确定的地方,并且毫无意义。但是两个指针可以进行减法运算,但是必须类型相同。
三、运算符 & 和 *
& 是取地址运算,而*是简介运算符,也称解除指针引用。
&a 得到的是a的地址;
*a :就是a所指向的东西;
四、指针表达式
一个表达式的结果如果是一个指针,那么这个表达式就叫做指针表达式。
eg:
int a,b;
int array[10];
int *pa;
pa = &a; // &a 就是一个指针表达式
int **ptr = &pa; // &pa 也是一个指针表达式
*ptr = &b; // *ptr 和 &b都是指针表达式
pa = array;
pa++; // 也是指针表达式
由于指针表达式的结果也是指针,所以也适用上面所说的指针的四个要素。
当一个指针表达式的结果指针已经明确的具有了指针自身占据内存的话,这个指针表达式就是一个左值,否则就不是一个左值。在上面的例子中&a 就不是一个左值。*ptr是一个左值,因为*ptr已经占据了内存,其实*ptr就是指针pa,既然指针pa已经在内存中有了自己的位置,那么*ptr当然也有了自己的位置。
五、数组和指针的关系
要讲数组和指针的关系,先介绍下C语言中声明和定义的区别。
声明相当于普通的声明:它所说明的并非自身,而是描述其他地方创建的对象。
定义相当于特殊的声明:它为对象分配内存。
C语言中的extern对象告诉编译器 对象的类型和名字,对象的内存分配则在别处进行。
图A展示了对数组下标的引用:
从数组中提取一个字符,只要简单的从符号表显示的a的地址加上下标,需要的字符就位于这个地址中。
如果声明的是char *p,它将告诉编译器p是一个指针(在许多现代编译器里它是一个4字节的对象),它指向的对象是一个字符。为了取得这个字符必须得到地址p的内容,把它作为字符的地址并从这个地址中取得这个字符。指针访问要灵活的多,但需要增加一次额外的提取,如图B所示:
当你“定义为指针,但以数组方式引用”时会发生什么 ?
现在让我们看一下当一个外部数组的实际定义的是一个指针,但却以数组的方式对其引用时,会引起什么问题。需要对内存进行直接的引用(如图A所示)。但这时编译器所执行的却是对内存进行间接引用(如图B所示)。之所以会如此,是因为我们告诉编译器我们拥有的是一个指针,如图C所示。
对照图C的访问方式:
char *p = "abcdefgh";....p[3]
图A的访问方式:
char a[] = "abcdefgh";... a[3]
在这两种情况下,都可以取字符‘d’,但两者的途径非常不一样。
当书写了extern char *p,然后用p[3]来引用其中的元素时,其实质就是图A和图B的访问方式的组合。首先,进行图B所示的间接引用。然后,如图A所示的用下标作为偏移量进行直接访问。更为正式的说法是,编译器将会:
1.取得符号表中p的地址,提取存储与此处的指针。
2.把下标所表示的偏移量与指针的值相加,产生一个地址。
3.访问上面这个地址,取得字符。
编译器已被告知p是一个指向字符的指针(相反,数组定义告诉编译器p是一个字符序列)。p[i]表示”从p所指的地址开始,前进i步,每步都是一个字符(即每个元素的长度为一个字节)“。
既然把p声明为指针,那么不管p原先定义为指针还是数组,都会按照上面所示的三个步骤进行操作,但是只有当p原来定义为指针时这个方法才是正确的。考虑一下p在这里被声明为extern char *p;而他原先的定义却是char p[10];这种情形。当用p[i]这种形式提取这个声明的内容时,实际上得到的是一个字符。按照上面的方法,编译器却把它当成一个地址,把ASCII字符解释成地址显然是驴头不对马嘴。如果此时程序当掉,你应该感到幸运。否则的话,它很可能会污染程序的地址空间的内容,并在将来出现莫名其妙的错误!
那么数组和指针什么时候是相等的呢?
只有在下列情况下是相等的:作为函数参数的数组和指针,两者是完全可以呼唤的。
另外C语言作了下面3条说明:
1.表达式中的数组名(与声明不同)被编译器当作一个指向该数组第一个元素的指针。
2.下标总是与指针的偏移量相同。
3.在函数参数的声明中,数组名被编译器当作指向该数组第一个元素的指针。
==========================================================
数组和指针的总结:
1.用a[i]这样的形式对数组进行访问总是被编译器改写成或解释为像*(a+1)这样的指针访问。
2.指针始终是指针。它绝不可以改写成数组。你可以用下表形式访问指针,一般都是指针作为函数参数时,而且你知道实际传递给函数的是一个数组。
3.在特定的上下文中,也就是它作为函数的参数(也只有这种情况),一个数组的声明可以看作是一个指针。作为函数参数的数组(就是在一个函数调用中)始终会被编译器修改成为指向数组第一个元素的指针。
4.因此,当把一个数组定义为函数的参数时,可以选择把它定义为数组,也可以定义为指针。不管用哪种方法,在函数内部事实上获得的是一个指针。
5.在其他所有的情况中,定义和声明必须匹配。如果定义了一个数组,在其他文件对它进行声明时也必须把它声明为数组,指针也是如此。
六、指针和结构类型的关系
typedef struct {
int a;
int b;
int c;
}MyStruct;
struct MyStruct ms = ss{10,20,30};
struct MyStruct *p = &ms;
p->a;p->b;p->c;
七、指针和函数的关系
可以把指针声明为一个指向函数的指针。
int fun1(char *,int);
int (*pfun1)(char *,int);
pfun1 = fun1;
int a = (*pfun1)("abcdefg",7);
八、指针类型转换
如果有一个指针p,我们需要把它的类型和所指向的类型改为
TYPE *TYPE,语法的格式是(TYPE*)p;
=================================================================
以上便是对C语言中指针的总结!其中第五章数组与指针的关系参考<C专家编程>