分类:
2012-02-15 11:17:14
原文地址:程序员面试宝典 第7章 指针与引用 作者:developinglife
(1)非空区别(2)合法性检验区别(3)可修改区别(4)应用区别
7.2传递动态内存(1)void getMem(char*p, int num){ p = (char*)malloc(sizeof(char)*num);}
void main(){char*str = NULL; getMem(str,100); strcpy(str,”hello”); cout<<*str<
//error: 内存0x00000000不能为written.
Notes:此程序会导致内存泄露.当将str传给getMem时,*p实际上是str的一个副本,为p开辟了内存,但str没有改变:str->NULL ,p->新开辟的内存。
A1:
void getMem1(char**p,int num){ *p = (char*)malloc(sizeof(char)*num);}
void main(){char*str = NULL; getMem1(&str,100); strcpy(str,"hello"); cout<<*str<
A2:
char *getMem2(char*p, int num){p = (char*)malloc(sizeof(char)*num); return p;}
void main(){char*str = NULL; str = getMem2(str,100); strcpy(str,"hello"); cout<
整形变量传值:void getMem3(int *z){*z = 5;} void main(){int i; getMem3(&i); cout<
(2)char *strA(){ char str[] = "hello,world!"; return str;}
void main(){ char * str1 = strA(); cout<<*str1<
//h 乱码 空
Notes:
str存放的是函数strA栈帧里”hello,world!”的首地址,函数调用完成,栈帧恢复到调用strA之前的状态,临时空间被重置,strA不再属于应该访问的范围。
正确的做法:
A1:char *strA(){ char *str = "hello,world!"; return str;}
void main(){ char * str1 = strA(); cout<<*str1<
//h hello,world! h
A2: char* strA1(){static char str[] = “hello,world!”; return str;}
void main() {char* str1 = strA1(); cout<<*str1<
//h hello,world! h
char c[] = “hello”; char *c = “hello”;的区别:
Notes: 前者是分配一个局部数组,位于内存的栈中;后者是分配一个全局数组,位于内存的全局数据区。全局数据区的值不可更改,局部区的数据可改变:
char c[] = "hello";cout<
c[0] = 'H';cout<
char *c1 = "leo";cout<
c1 = "jia";cout<
//*c1 = 'J'; //false,内存不可写
//c1[0] = 'J';//false,内存不可写
(3)
int a[3];a[0] = 1;a[1] = 2;a[2] = 3;int *p,*q;p = a;q = &a[2];
cout<
cout<
cout<
cout<<*p<
cout<
cout<<*q<
cout<
cout<
(4)void change(int *a,int &b, int c){c=*a;b=3;*a=2;}
int a = 1,b = 2,c=3;
change(&a,b,c);
(5)不能随意给指针分配一个地址:int *ptr =(int*)0x80000;//error
(6)class A
{
public:
int a;
A(){ a = 1;}
};
class B:public A
{
public:
int a;
B(){a = 2;}
};
B b;
b.print();//1,输出的是A的a.
cout<
(7)函数形参在函数未调用时不被分配空间。
若函数定义出现在main之前则不必再声明。//erro!
Notes: 函数需在它被调用前声明,与main无关。
(8)struct S{ int i; int *p;};
S s;
int *p = &s.i;
p[0] = 4;
p[1] = 3;
//s.p = p;
cout<
cout<<&p[0]<<" "<<&s.i<
cout<
cout<<&p[1]<<" "<<&s.p<<" "<<&s.p[0]<<" "<<&s.p[1]<
//cout<
//cout<
cout<
s.p = p;
cout<
cout<<&p[0]<<" "<<&s.i<
cout< 1310584 0013ff7c 1310584
cout<<&p[1]<<" "<<&s.p<<" "<<&s.p[1]<
cout<
s.p[1] = 1;
cout<
(1)函数指针
int max(int x, int y)
{
return x > y ? x : y;
}
void main()
{
int max(int, int);
int (*p)(int, int) = &max;
int a,b,c,d;
scanf("%d%d%d",&a,&b,&c);
d = (*p)((*p)(a,b),c);
printf("%d%d%d%d",a,b,c,d);
}
(2)
1) float(**def)[10]; def是个二级指针,它指向一个一维数组的指针,数组元素是float型。
2)double*(*gh)[10];gh是一个指向一维数组的指针,数组元素是double*型。
3)double(*f[10])();f是一个函数指针数组,数组元素都是指向函数的指针,函数类型是没有参数且返回 double的函数。
4)int*((*b)[10]); 和int*(*b)[10]一样,b是一维数组的指针,数组元素类型为int*。
5)int(*(*f)(int,int))(int);f是一个函数指针,函数类型为有两个int参数并且返回一个函数指针的函数,返回的函数指针指向有一个int参数且返回int的函数。
7.4指针数组和数组指针(1)
int v[2][10]=
{
{1,2,3,4,5,6,7,8,9,10},
{11,12,13,14,15,16,17,18,19,20}
};
int (*a)[10] = v;//指向数组的指针,指向一维数组v[0];
cout<<**a<
a++;//向后移动1*sizeof(所指向数组)的大小即40
cout<<**a<
(2)
int a[]={5,4,3,2,1};
cout<<&a<
cout<<*a<
cout<<*a+1<
cout<<*(a+1)<
int *ptr = (int*)(&a+1);
cout<<*ptr<
cout<<*(ptr-1)<
int *ptr2 = (int*)(b[1]);
int *ptr3 = (int*)(&b+1);
cout<<*ptr2<
cout<<*ptr3<
(1)迷途指针也叫悬浮指针,或失控指针,是对指针进行delete后(这样会释放指针所指向的内存),没有将它设置为空而造成的。若果没有对其重新赋值,再次引用时结果将是不可料的,程序有可能崩溃。
a. delete后的指针仍然指向原内存区,但是编译器把这块内存分给了其他的数据,不给指针重新赋值而再次使用这个指针则有可能改变了已作他用的这块内存,造成程序出错。为了防止这种情况发生,在delete掉一个指针后应该将其赋值为0,这样若果再次使用它之前忘了赋值,编译器会报错。
eg:
unsigned short int* pInt = new unsigned short;
int* pInt2 = new int;
*pInt = 10;
cout<<*pInt<
cout<
delete pInt;
cout<
long *pLong = new long;
*pLong = 90000;
cout<
cout<<*pLong<
*pInt = 20;//delete后未置零,再次使用后患无穷啊!
cout<
cout<<*pLong<
Notes:
pInt被delete后,没有置为0,再次使用会把本来pLong指向的分配给90000的内存给改掉了,迷途指针就像被驱逐出狮群的流浪客,没找到自己的归宿,就会回去惹是生非。
(2)空指针和迷途指针的区别:
int *p = new int;
*p = 10;
delete p;
delete p;//debug assertion failed!删除一个指针后再把它删一次,出错
int *p = new int;
*p = 10;
delete p;
p = 0;
delete p;//删除空指针是没问题滴!
int a = 10;
int *p = new int;
*p = 10;
delete p;
*p = 20;//这个编译不报错,但是很危险!见(1),使用迷途指针是非法的!
int a = 10;
int *p = new int;
*p = 10;
delete p;
p = 0;
*p = 20;//使用空指针虽是非法的,但编译可以查出来,相对没那么危险!
(3)c++中有了malloc/free,为什么还要new/delte?
malloc/free是c/c++的标准库函数,new/delete是c++的运算符,都可用于申请动态内存和释放内存。
内部数据类型大小固定可用malloc/free申请动态内存和释放内存,但对于非内部数据类型只用malloc/free无法满足动态对象的需求。对象在创建时要自动执行构造函数,对象消亡前要自动执行析构函数。由于malloc/free是库函数,不再编译器控制权限内,不能把执行构造和析构的任务强加与malloc/free。故c++需要new来完成对象的动态内存分配和初始化,用delete完成内存的清理和释放。
(4)
char* a[] = {"hello","the","world"};//a为指针数组,存放三个字符串的首地址
cout<<*a<
cout<<*a+1<
cout<<*(a+1)<
char* *p =a;//p为指向指针(此指针为字符指针)的指针
cout<<*p<
cout<<*p+1<
cout<<*(p+1)<
cout<<*p++<
cout<<*p<
cout<<*++p<
cout<<*(p++)<
(1)指针和句柄的区别联系
指针标记物理内存地址,而句柄是指向指针的指针,windows用句柄来标记系统资源,隐藏系统信息。它是windows在内存中维护的一个对象的内存物理地址列表的整数索引,是一个uint。对象的物理地址是变化的,程序将想访问的对象的句柄传递给系统,系统根据句柄检索自己维护的对象列表来访问对象。
Windows是一个以虚拟内存为基础的操作系统,其内存管理器经常在内存中移动对象来满足不同程序的内存需要,为了能继续访问被移动后的对象,系统把对象新的地址用句柄保存起来,用句柄可以间接知道对象的具体物理地址。句柄地址(稳定)->对象在内存中的地址(不稳定)->实际对象。
(2)智能指针
智能指针是存储指向动态分配对象指针的类,能在适当的时间自动删除所指向的对象,尤其是在遇到异常时,能确保正确地销毁动态分配的对象。也可以跟踪被多用户共享的动态分配对象。智能指针大部分时候用于生存期控制和阶段控制,使用”operate->”和”operate*”生成原始指针,使其看上去像一个普通指针。可以用来处理线程安全、提供写时赋值、提供远程交互服务以及扩展指针方法等。
智能指针类将指针变量作为成员变量封装起来,在智能指针类对象离开作用域时,会再析构的过程中完成指针的释放。
Eg:A* pA = new A;f(); delete pA; 当f()抛出一个异常而没有被捕捉时,在没有_finally扩展关键字的情况下无法执行delete pA;而用如下代替:auto_prt a = auto_ptr(new A);则抛出异常后,清理堆栈时,a会被自动析构,释放它所指向的A*内存。