9.C/C++指针操作
a. C++中的东西是有个名(name)的:
定义有以下几种:
变量: type name; 比如:int i;
数组: type name[N1][N2]…;比如:char chs[4][5];
函数: type name(type1 v1,type2 v2…);比如: int fun(int a,char c);
b. 可以如下定义一个指向名的指针:
分别是:
变量: type (*pname); 比如:int (*pi);
数组: type (*pname) [N1][N2]…;比如:char (*pchs)[4][5];
函数: type (*pname) (type1 v1,type2 v2…);比如: int (*pfun)(int a,char c);
c.其实任何name的定义都可以写成type name;的样子,这需要用到typedef定义一个类型的名称。
定义指针有以下几种:
变量: typedef type (*pname_t); 比如:typedef int (*pi_t);
数组: typedef type (*pname_t) [N1][N2]…;比如:typedef char (*pchs_t)[4][5];
函数: typedef type (*pname_t) (type1 v1,type2 v2…);比如:typedef int (*pfun_t)(int a,char c);
这样b中的示例定义全部可写为type name的样子:
变量:pi_t pi;
数组:pchs_t pchs;
函数:pfun_t pfun;
d.小结
n 定义一个指针p_name指向一个名字name只需要在定义name的语句上如下改动:
仅需把name改写成(*pname);
n 定义一个类型name_t使其表示name的类型的别名,只需在定义name的语句上如下改动:在name定义语句前加上typedef并把name改写为name_t;
e.一个重要的问题——数组和指针
1.
char a[10];
char (*pa) =a;//注意数组名会自动变成指向其元素的指针类型,函数名也可以自动转换成指向自己的指针。
2.
char a[3][4];
注意:a的意义是:a是一个数组,数组里面3个元素,每个元素是一个存放四个char的数组(从左向右看)。这样我们可以定义如下:
char (*p)[4]=a;
由于任何时候a[N]都会被替换成*(a+N),所以上面当然可以也写成如下形式:
char p[][4]=a;
还有一点:
如果p++;则p的值增加了4*sizeof(char);
3.
string *pstr=new string(“I am a string!”);
….
delete pstr;
对于数组string * pstr=new string[10];
….
delete [] pstr;//删除数组需要加[],这样编译器才会调用对象的析构函数。任何不一致的对detete调用的结果将是没有定义的。
这里有个东西有点意思,就是系统收回分配的内存时是如何根据一个指针来知晓分配的空间的大小的。其实,这里分配的内存在堆中,堆一般来说是由操作系统管理的,是一个内核对象,一般会做成一个链表,链表记录了各个空闲块和已分配块的大小以及起始地址。当然根据一个起始地址,遍历链表就可以找到一个链表节点,它记录了这个地址对应的空间的大小。之后就可以释放分配的内存了,一点问题都没有。
刚刚提到delete[] pstr;这里由于有10个string,就需要编译器插入代码调用10次string的析构函数,每次调用时,针对的对象是不同的,编译器必须找到每个对象的起始地址,由于pstr是第一个对象的地址,用pstr+sizeof(string)*(i-1),就得到第i个对象的起始地址了,所以也是没问题的。
a. C++中的东西是有个名(name)的:
定义有以下几种:
变量: type name; 比如:int i;
数组: type name[N1][N2]…;比如:char chs[4][5];
函数: type name(type1 v1,type2 v2…);比如: int fun(int a,char c);
b. 可以如下定义一个指向名的指针:
分别是:
变量: type (*pname); 比如:int (*pi);
数组: type (*pname) [N1][N2]…;比如:char (*pchs)[4][5];
函数: type (*pname) (type1 v1,type2 v2…);比如: int (*pfun)(int a,char c);
c.其实任何name的定义都可以写成type name;的样子,这需要用到typedef定义一个类型的名称。
定义指针有以下几种:
变量: typedef type (*pname_t); 比如:typedef int (*pi_t);
数组: typedef type (*pname_t) [N1][N2]…;比如:typedef char (*pchs_t)[4][5];
函数: typedef type (*pname_t) (type1 v1,type2 v2…);比如:typedef int (*pfun_t)(int a,char c);
这样b中的示例定义全部可写为type name的样子:
变量:pi_t pi;
数组:pchs_t pchs;
函数:pfun_t pfun;
d.小结
n 定义一个指针p_name指向一个名字name只需要在定义name的语句上如下改动:
仅需把name改写成(*pname);
n 定义一个类型name_t使其表示name的类型的别名,只需在定义name的语句上如下改动:在name定义语句前加上typedef并把name改写为name_t;
e.一个重要的问题——数组和指针
1.
char a[10];
char (*pa) =a;//注意数组名会自动变成指向其元素的指针类型,函数名也可以自动转换成指向自己的指针。
2.
char a[3][4];
注意:a的意义是:a是一个数组,数组里面3个元素,每个元素是一个存放四个char的数组(从左向右看)。这样我们可以定义如下:
char (*p)[4]=a;
由于任何时候a[N]都会被替换成*(a+N),所以上面当然可以也写成如下形式:
char p[][4]=a;
还有一点:
如果p++;则p的值增加了4*sizeof(char);
3.
string *pstr=new string(“I am a string!”);
….
delete pstr;
对于数组string * pstr=new string[10];
….
delete [] pstr;//删除数组需要加[],这样编译器才会调用对象的析构函数。任何不一致的对detete调用的结果将是没有定义的。
这里有个东西有点意思,就是系统收回分配的内存时是如何根据一个指针来知晓分配的空间的大小的。其实,这里分配的内存在堆中,堆一般来说是由操作系统管理的,是一个内核对象,一般会做成一个链表,链表记录了各个空闲块和已分配块的大小以及起始地址。当然根据一个起始地址,遍历链表就可以找到一个链表节点,它记录了这个地址对应的空间的大小。之后就可以释放分配的内存了,一点问题都没有。
刚刚提到delete[] pstr;这里由于有10个string,就需要编译器插入代码调用10次string的析构函数,每次调用时,针对的对象是不同的,编译器必须找到每个对象的起始地址,由于pstr是第一个对象的地址,用pstr+sizeof(string)*(i-1),就得到第i个对象的起始地址了,所以也是没问题的。