c/c++中的指针一般是指指针变量,它与普通的变量不同的是他能根据指针变量的类型通过*来重新解析指针变量的值,比如 :
int i=3;
int *p=&i;
p=&i是给指针变量赋值,对于i编译器根据变量i的类型(int),在内存中划出了4个字节的空间&i~&i+3,以后对i的操作会映射到&i~&i+3这个字节中,比如i=4;编译器会根据编译时所获得类型信息,将4存储到&i~&i+3内存中。编译器给变量的赋值过程跟指针的解引(*)用过程是相似的。上面p=&i;是把i的地址值赋给p,也就是说p的值是编译器分配i变量对应的内存的起始地址值,现在p的类型是int*,当进行*p操作时,编译器认为p的值是某个int类型变量在内存的地址,于是编译器会从p的值对应的内存开始,往下涵盖四个字节,把这四个字节的内存里的数据按照一定的方式取出。指针变量与普通的变量的不同之处也在于此,指针变量能控制对内存数据的解析方式,如果
int i=3;
char *p=(char*)&i;
p的值还是i的首地址,但*p的内容不一样了,由于是char*现在*p只是i的首地址内存的数据。
所以对于指针变量有两点是至关重要的,首先是指针变量的值,然后是它的类型也就是它对指针变量值的解析方式,搞明白指针变量这两点基本对指针变量比较从容了~~~~
再谈一下数组和指针,一维数组如 int a[10]={0},那么编译器会在内存开辟10*sizeof(int)的连续空间,其中a用来标示这块连续内存的首地址,然后对a[0],a[1].....的访问自动回被转化为*(a+0),*(a+1)....指针形式的访问,因此可以认为a的值是一个编译期就确定下来的常量,默认被解析成对应类型的指针变量的一个值,所以可以赋给对应类型指针变量。因此像
int a[10]={0};
int b[10];
b=a;
这样的语句是编译器所拒绝的,因为编译器要靠b的值,来寻址b[0],b[1]...所以不能修改b的值。另外对于像b[0],0[b]在编译器眼里都会被解析成*(b+0),所数组下标可以为负数,但要注意越界。
- #include<iostream>
- using namespace std;
- int main()
- {
- int a[10]={0};
- 0[a]=10;
- cout<<a[0]<<endl;
- int *p=a;
- p+=1;
- cout<<(-1)[p]<<endl;
- cout<<p[-1]<<endl;
- system("pause");
- }
对于二维数组,他们在内存也是连续的,如int c[10][10],c也可以认为是一个常量默认解析成一个(*)[10]类型,一个指向数组的指针变量的值。可能有人会问为什么不解析成一个二级指针变量的值,道理很简单比如如下代码:
- #include<iostream>
- using namespace std;
- int main()
- {
- int a[10][10]={10};
- int **p=(int**)a;
- cout<<*p<<endl;
- system("pause");
- **p=1;
- }
a的值可以强制赋给p,但是*p时会把a对应的内存开始涵盖四个字节的数据取出,解析成一个int*变量的值,此时程序还没有问题*p的值是a[0][0](0x0000000a)的值,但**p操作会从地址值0x0000000a开始涵盖四个字节内存取其中数据组成一个int变量的值,而对0x0000000a访问,很容易非法,故程序挂掉。
- #include<iostream>
- using namespace std;
- int main()
- {
- int a[2][2]={1,2,3,4};
- int (*p)[2]=a;
- cout<<**p<<endl;//->a[0][10]
- cout<<*p[1]<<endl;//->*(*(p+1)+0)->a[1][0]
- int *q=(int*)a;//验证二维数组在内存布局也是连续
- for (int i=0;i<4;i++)
- {
- cout<<q[i]<<endl;
- }
- system("pause");
- }
ps:个人见解,如有错误望不吝指教。(未完)