二级指针变量的值为什么不可以赋予一级指针变量
本质上说,指针变量保存的是内存地址,无论该地址中存放的是什么数据,一般情况下逻辑地址都是32位的一个编号,因此理论上说任何变量的地址都是4字节宽度,所以任何类型的指针变量所能储存的地址宽度是一样的,二级指针变量完全可以保存一级指针变量的值。
但是,问题在于,指针变量保存的地址只是首地址,不同类型的变量的数据宽度是不同的,编译器必须能够对不同类型的变量的数据区别并且是正确对待。指针变量之所以存在一级二级或者各种类型,其意义在于:能够按正确的数据宽度访问变量,即数据对齐。比如char是单字节,而int是4字节,当一个char *类型的指针指向一个char变量的首地址时,编译器在编译时必须按单字节读/写内存,而当对一个int *类型的指针访问一个int变量的首地址时,必须按4字节宽度读写,否则会造成数据错乱。因此指针类型就是一种约定,用于规定编译器编译时按对应的数据宽度操作地址。
因此编译前检查时编译器是按类型匹配的约定进行错误检查的,就是为了遵循(数据对齐)约定。当然你如果明确自己在做什么,完全可以将不同的类型的指针强制转换。
给你个例子,满足你的一级指针赋值给二级指针的愿望而不会出错:
int a[10]={1,2,3,4,5,6,7,8,9,10};
int *p1;
int **p2;
int v;
p1=a;
p2=(int **)p1;//一级指针强制转为二级指针,以便于类型一致后可以赋值
v=(int)*(p2+9);//二级指针加索引后取值后得到的是一级指针类型,强制转int
cout<<*(p2+9)<<endl;//直接用二级指针取值后输出
cout<<v<<endl;//输出强转后的值
说明:
将p1强转为二级指针后赋值给p2,注意这个值是a的首地址,因此p2+9之后就是最后一个元素地址(二级指针变量运算时是按地址的数据宽度递增的,而int的数据宽度与地址的数据宽度是一致的,所以正好数据对齐),但是通过二级指针取值后其值类型为 int* ,因此cout输出时是按地址格式输出的,因此输出为0000000A,为4字节宽度。
v=(int)*(p2+9)这句,*(p2+9)同上为取出为int *类型,但是我们知道这个值其实不是地址,而是a的最后一个元素,由于我们采用二级指针取值所以编译器认为其值为地址。为了能通过二级指针也能正确显示元素,还得采用强制转换,将其转为int并赋值给v,因此第二个cout语句就能正确按10进制显示数组a中最后一个元素值了。
通过以上例子我想应该能说明编译器对类型约定的意义了,也说明了只要你充分了解编译器对变量分配、编码以及指针的本质等等,你完全可以“玩弄”编译器。