【程序员面试宝典】错题好题汇总ch7
错题,知识盲点、查漏补缺
好题,开阔思路、锻炼思维
ch7 指针与引用
1.
传递动态内存
1 #include<iostream> 2 #include<iomanip> 3 #include<cstdlib> 4 #include<cstring> 5 using namespace std; 6 7 void GetMemory(char *p,int num){ 8 9 p = (char*)malloc(sizeof(char)*num); 10 } 11 void GetMemory_plus(char **p,int num){ 12 13 *p = (char*)malloc(sizeof(char)*num); 14 } 15 int main(){ 16 17 char*str = NULL; 18 //GetMemory(str,100);//如果注释掉下一行,程序会崩溃,因为str还是空的 19 GetMemory_plus(&str,100); 20 strcpy(str,"hello"); 21 cout<<setw(8)<<"str : "<<str<<endl; 22 cout<<setw(8)<<"*str : "<<*str<<endl; 23 cout<<setw(8)<<"&str : "<<&str<<endl; 24 return 0; 25 }
结果与分析:
GetMemory()函数中,p只是str的一个副本,p的改变不影响str。
但是GetMemory_plus中,传入的str的地址&str,后面*p的赋值自然会影响&str。
2.字符串常量
1 #include<iostream> 2 #include<iomanip> 3 #include<cstdlib> 4 #include<cstring> 5 using namespace std; 6 7 char *strA(){ 8 char str[] = "Hello,world"; 9 return str; 10 } 11 char *strB(){ 12 char *str = "Hello,world"; 13 return str; 14 } 15 int main(){ 16 17 cout<<strA()<<endl;//可以输出一些东西,但是违背函数的栈帧机制。char []是局部变量,“helloworld”保存在栈中。 18 cout<<strB()<<endl; //没问题。char *定义了一个字符串常量,保存在只读的数据段。 19 return 0; 20 }
结果与分析:
总结扩展:
charp[]="hello";//1 char*p="hello";//2 char*p;p=(char*)malloc(sizeof(char)*6);strcpy(p,"hello");//3
这三种情况下:
1中所有6个char字符都连续的存放在栈区。
2中的"Hello"存在程序内存的常量区中,是编译时就固定下来的(不可更改),然后p是一个指向常量区"hello"的指针,p本身存在栈区。
3中malloc向堆申请了空间,p存放在栈区,指向malloc申请出来的地址,最后"hello"就被copy到了p所指向的地址。
1中所有6个char字符都连续的存放在栈区。
2中的"Hello"存在程序内存的常量区中,是编译时就固定下来的(不可更改),然后p是一个指向常量区"hello"的指针,p本身存在栈区。
3中malloc向堆申请了空间,p存放在栈区,指向malloc申请出来的地址,最后"hello"就被copy到了p所指向的地址。
3.
内存偏移:
1 #include<stdio.h> 2 #include<iostream> 3 using namespace std; 4 class A{ 5 public: 6 A(){ 7 m_a = 1;m_b = 2; 8 } 9 ~A(){ 10 }; 11 void fun(){ 12 printf("%d %d\n",m_a,m_b); 13 printf("%x\n",(int)&m_a); 14 printf("%x\n",(int)&m_b); 15 } 16 private: 17 int m_a; 18 int m_b; 19 }; 20 class B{ 21 public: 22 B(){ 23 m_c = 3; 24 } 25 ~B(){ 26 }; 27 void fun(){ 28 printf("%d",m_c); 29 } 30 private: 31 int m_c; 32 }; 33 int main(){ 34 A a; 35 a.fun(); 36 B *pb = (B*)(&a); 37 pb->fun(); 38 }
结果与分析:
B*pb = (B*)(&a);
强制把a地址的内容看作一个B类的对象,也就是说pb指向的是a类的内存空间;
pb->fun();
正常情况,B中只有一个int m_c,B对象的内存空间中只有一个m_c,fun()函数就会去对象的内存首地址去寻找m_c,然后打印。
现在的话,fun()函数再去对象的内存首地址去取m_c的时候,就会把m_a打印出来。
4.
#include<iostream> using namespace std; int main(){ int a[] = {1,2,3,4,5}; cout<<*(a)<<endl; int *ptr = (int*)(&a + 1); int *ptr1 = (a + 1); cout<<*(a + 1)<<*(ptr - 1)<<*(ptr1)<<endl; int b[2][5] = {{1,2,3,4,5},{6,7,8,9,0}}; int *p = (int*)(b[0] + 1); int *p1 = (int*)(&b[0] + 1); cout<<*p<<*p1<<endl; return 0; }
结果与分析:
总结起来就是:
数组名本身就是指针,再加上&,就变成了双指针,这里的双指针就是二维数组,加1,就是数组整体加一行。
5.
auto_ptr是安全指针,如下定义是正确的:
std::auot_ptr <object> pObj(new Object); std::auto_ptr <Object> source(){return new Object;}
auto_ptr不可以放在容器中。因为auto_ptr的拷贝不等价,原来的一份会被删除。