就上面的博客作一下笔记:
关于【int (*p)[3]】与【int *p[3]】两个的区别
技巧1:注意*与[与变量结合的优先顺序,p有可能是指针,也有可能是数组,也有可能是函数名。
技巧2:关于“指针类型”的判定:
1)首先,要确保变量就是一个指针类型。
2)去掉变量名,剩下的就是指针类型。
技巧3:关于“指针所指向的类型”的判定:
1)首先,要确保变量就是一个指针类型。
2)去掉变量名指针的声明符*,剩下的就是指针指向的类型。
void如果来修饰指针运算符*,就代表是任意类型的指针。
int (*p)[3];
关于复杂指针类型,上面这个类型。注意(*p)这个括号,仅仅是用来约束运算符优先级的。不要和下面的指针类型混淆。
Int (*p)(int);
上面这个类型。注意(*p)这个括号,代表p指向的是一个函数。
所以在判断(*p)指针的指向的内容类型时,可以将(*p)同时去掉再行判断 。
指针打印:采用%p
1)对于“例二”
如果ptr指针类型声明为char *,ptr++之后的打印结果为b。
#include "stdafx.h" #includeint _tmain(int argc, _TCHAR* argv[]) { char a[20]={'a','b','c','d','e','f'}; char *ptr= a; //强制类型转换并不会改变a 的类型 ptr++; printf("%c",*ptr); system("pause"); return 0; }
如果ptr指针类型声明为int *,ptr++之后的打印结果为e。
#include "stdafx.h" #includeint _tmain(int argc, _TCHAR* argv[]) { char a[20]={'a','b','c','d','e','f'}; int *ptr=(int *)a; //强制类型转换并不会改变a 的类型 ptr++; printf("%c",*ptr); system("pause"); return 0; }
所以当指针声明成不同的类型,++的效果是不一样的。++和指针的类型有关。
如果指针类型和指针所指向的类型不一致时,要注意++的使用。
2)对于“例三”
#include "stdafx.h" #includeint _tmain(int argc, _TCHAR* argv[]) { int array[20]={0}; int *ptr=array; for(int i=0;i<20;i++) { (*ptr)++; ptr++; } for(int i=0;i<20;i++) { printf("[%d] = %d\n",i,array[i]); } system("pause"); return 0; }
3)对于“例四”
#include "stdafx.h"#includeint _tmain(int argc, _TCHAR* argv[]){ char a[20]="You_are_a_girl"; int *ptr=(int *)a; ptr+=1; printf("%d\n",*ptr); system("pause"); return 0;}
对行%d,*ptr输出的是1600483937
对行%c,*ptr输出的是a
这是为什么,请高手解答?
4)对于“例五”
#include "stdafx.h" #includeint _tmain(int argc, _TCHAR* argv[]) { char a[20]="You_are_a_girl"; char *p=a; char **ptr=&p; //printf("p=%d\n",p); //printf("ptr=%d\n",ptr); //printf("*ptr=%d\n",*ptr); printf("**ptr=%c\n",**ptr); ptr++; //printf("ptr=%d\n",ptr); //printf("*ptr=%d\n",*ptr); printf("**ptr=%c\n",**ptr); system("pause"); return 0; }
这个例子有点绕,需要注意,上面我来配个图
**ptr:分解开就是*(*ptr)
*ptr取指ptr所指向的内容,ptr指向的地址是指针变量p所占用的内存地址,ptr所指向的内容就是指针p变量。
*(*ptr) 就是*p,也就是取p所指向的a的首地址的值,所以第一次打印ptr的值是Y。
ptr++,就是得明白指针的++与普通的运算符是不一样的(指针变量的++,代表它所指向的个体的内存地址的递增,且增长单位为指针类型所占字节个数)。
ptr++,也就是 ptr所指向的地址+4(注意是p的地址+4,并非a的地址+4).
ptr++ , 就是ptr所指向的内存地址是指针p的内存地址加4个字节的地址,至于这个地址里存储的对象是啥,谁也不知道。
*ptr,ptr新指向内存地址就是下面的这个蓝牙框。 *(*ptr),就是把*ptr当作是一个指针,而*ptr并非一定是一个指针。这样程序可能就会报错。
5)对于“例9”
假如我像下面这么写,会报一个错误:
#include "stdafx.h" #includeint _tmain(int argc, _TCHAR* argv[]) { int array[10]={0,1,2,3,4,5,6,7,8,9},value; array++; value=*array; printf("%d\n",value); system("pause"); return 0; }
error C2105: “++”需要左值
上面的错误百度了一个解释:
就是数组名是一个指针,但是不是一个变量。不可能对它进行++运算。++不可使用在常量上
改一下代码:
int _tmain(int argc, _TCHAR* argv[]) { int array[10]={0,1,2,3,4,5,6,7,8,9},value; int *ptr = array; ptr++; value=*ptr; printf("%d\n",value); system("pause"); return 0; }
结果输出1
其实,说到数组,我还一个 需要补充的:数组元素的内存地址是连续的
通过下面的代码打印:
for(int i = 0; i < 10; i++){ printf("array[%d] address = %d\n",i,&array[i]); }
6)对于“例十”
strcpy函数,会将char *指针所指向的字符串复制,而不仅仅是一个字符。
printf("%s",array); %s是从起始位置输出字符直到遇到\0为止,所以%s输出char[]数组,会输出整个串。
关于strcpy函数的详解:
7)对于“例十一” (数组和指针)
sizeof 函数:
(详细说明数组名与指针的关系)
8)对于“例十二” (结构体和指针)
成员调用的方法(->左边必须是指针,"."左边必须是实体)
特别注意结构体与数组,和指针的关系是不一样的。
对于*(ptr +1)打印的不是结构体的第2个元素,很奇怪。难道数组名与结构体名不一样?
printf("%s\n","----------结构体名取结构体正常数据------------------"); printf("%d\n",*ss); printf("%d\n",*(ss+1));
增加上述代码,工程一编译就报错:
错误1error C2100: 非法的间接寻址
错误2error C2676: 二进制“+”: “wmain::MyStruct”不定义该运算符或到预定义运算符可接收的类型的转换
所以我得出一个结论,数组名与结构体名有完全不一样的特性:结构体名不能当成指针使用,结构体名不是指针常量。
注意这行代码:
struct MyStruct *ptr=&ss;
假如ss是数组,上面的代码就不用加&号了。
struct MyStruct *ptr=ss;
但是结构体会报错:
错误1error C2440: “初始化”: 无法从“wmain::MyStruct”转换为“wmain::MyStruct *”
这就更加证明了结构体名不是指针常量这个结论 。
继续修改代码:
注意上面的打印结果,通过pstr取的结构体元素地址是正确的,但是ptr取的结构体元素地址是错误的。
注意代码中ptr与pstr的定义:
struct MyStruct *ptr=&ss; int *pstr=(int*)&ss;
ptr指向的类型是 MyStruct,指向的对象为结构体实体ss。
pstr指向的类型是int,指向的对象为结构体的实体ss的首元素。
ptr+1,就是&ss这个地址+sizeof(MyStruct),就是&ss+16。
pstr+1,就是&ss这个地址+sizeof(int),就是&ss+4。
--------------------------------------------------------------------------------------------
| 结构体与数组的共性:
| 1)结构体实体的地址和结构体第一个元素的地址一样, 各元素的地址也是连续的。(特殊情况也有不连续的)
| 数组实体的地址和数组第一个元素的地址一样, 各元素的地址也是连续的。
| 2)数组和结构体自身的实体(变量)并不占据独立的内存(和首元素地址一样),只有元素才占用真正的内存地址,
| 它只是标明自身的元素是一组特殊的数据结构, 通过实体封装,便于元素的访问。
|
| 结构体与数组的区别:
| 1)数组名是指针常量,但是结构体名和指针没有任何的关系。
--------------------------------------------------------------------------------------------
9)对于“例十三”
注意作者对结构体的特殊之处的解释
10)指针类型的转换
可以把指针的值当作一个整数取出来,也可以把一个整数值当作地址赋给一个指针
11) 指针安全问题
这个很重要
使用指针必须要清楚指针指向了哪里