c++ 面试题

void getMemeory1(char *p)
{
   p = (char *)malloc(100*sizeof(char));
}
 
char * getMemeory2()
{
   char p[100] = "Hello world";
   return p;
}
 
int main()
{
    //test1
    char *str1 = NULL;
    getMemeory1(str1);
    strcpy(str1, "Hello world");
    printf("str1 = %s\n", str1);

    //test2
    char *str2 = NULL;
    str2 = getMemeory2();
    printf("str2 = %s\n", str2);
}
 
执行结果:test1程序报错,test2打印乱码或者“Hello world”(一般乱码)
 
结果分析:
test1:
在函数中给指针分配空间,实际上是给指针的临时变量分配空间,函数结束后,这个临时变量也消亡,而str仍然为NULL,没有为其分配空间,
此时strcpy()是肯定会出错的。
 
test2:
1、可能是乱码,也有可能是正常输出,因为GetMemory返回的是指向“栈内存”的指针,该指针的地址
   不是NULL,但其原来的内容已经被清除,新内容不可知程序员面试宝典里有专门讲该部分知识的。
2、因为p的生命周期在GetMemory函数执行完了就被销毁了,str 指向的是个野指针。       

//相关分析资料摘录
1、指针参数是如何传递内存的?

  如果函数的参数是一个指针,不要指望用该指针去申请动态内存。以下Test函数的语句GetMemory(str, 200)并没有使str获得期望的内存,str依旧是NULL,为什么?
1.     void GetMemory(char *p, int num)
2.     {
3.      p = (char *)malloc(sizeof(char) * num);
4.     }
5.     void Test(void)
6.     {
7.      char *str = NULL;
8.      GetMemory(str, 100); // str 仍然为 NULL
9.      strcpy(str, "hello"); // 运行错误
10.  }
复制代码
示例1.1 试图用指针参数申请动态内存

  毛病出在函数GetMemory中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器使 _p = p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p申请了新的内存,只是把 _p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因为没有用free释放内存。

  如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见示例1.2。
1.     void GetMemory2(char **p, int num)
2.     {
3.      *p = (char *)malloc(sizeof(char) * num);
4.     }
5.     void Test2(void)
6.     {
7.      char *str = NULL;
8.      GetMemory2(&str, 100); // 注意参数是 &str,而不是str
9.      strcpy(str, "hello");
10.   cout<< str << endl;
11.   free(str);
12.  }
复制代码
示例1.2用指向指针的指针申请动态内存

  由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态内存。这种方法更加简单,见示例1.3。
1.     char *GetMemory3(int num)
2.     {
3.      char *p = (char *)malloc(sizeof(char) * num);
4.      return p;
5.     }
6.     void Test3(void)
7.     {
8.      char *str = NULL;
9.      str = GetMemory3(100);
10.   strcpy(str, "hello");
11.   cout<< str << endl;
12.   free(str);
13.  }
复制代码
示例1.3 用函数返回值来传递动态内存

  用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把return语句用错了。这里强调不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡,见示例1.4。
1.     char *GetString(void)
2.     {
3.      char p[] = "hello world";
4.      return p; // 编译器将提出警告
5.     }
6.     void Test4(void)
7.     {
8.      char *str = NULL;
9.      str = GetString(); // str 的内容是垃圾
10.   cout<< str << endl;
11.  }
复制代码
示例1.4 return语句返回指向“栈内存”的指针

  用调试器逐步跟踪Test4,发现执行str = GetString语句后str不再是NULL指针,但是str的内容不是“hello world”而是垃圾。
如果把示例1.4改写成示例1.5,会怎么样?
1.     char *GetString2(void)
2.     {
3.      char *p = "hello world";
4.      return p;
5.     }
6.     void Test5(void)
7.     {
8.      char *str = NULL;
9.      str = GetString2();
10.   cout<< str << endl;
11.  }
复制代码
示例1.5 return语句返回常量字符串

  函数Test5运行虽然不会出错,但是函数GetString2的设计概念却是错误的。因为GetString2内的“hello world”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。

  2、杜绝“野指针”

  “野指针”不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用。 “野指针”的成因主要有两种:

  (1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如
1.     char *p = NULL;
2.     char *str = (char *) malloc(100);
复制代码
(2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。

  (3)指针操作超越了变量的作用范围。这种情况让人防不胜防,示例程序如下:
1.     class A
2.     {
3.      public:
4.       void Func(void){ cout << “Func of class A” << endl; }
5.     };
6.     void Test(void)
7.     {
8.      A *p;
9.      {
10.    A a;
11.    p = &a; // 注意 a 的生命期
12.   }
13.   p->Func(); // p是“野指针”
14.  }
复制代码
函数Test在执行语句p->Func()时,对象a已经消失,而p是指向a的,所以p就成了“野指针”。但奇怪的是我运行这个程序时居然没有出错,这可能与编译器有关。

二 、面向对象七大原则

https://www.cnblogs.com/sunflower627/p/4718702.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值