指针与引用案例分析

典型案例
Ex1
#include <iostream>

void GetMemory(char *p, int num)
{
    p = (char *)malloc(sizeof(char) * num);
}

int main()
{
    char *str = NULL;
    GetMemory(str, 100);
    strcpy(str, "hello");

    return 0;
}
分析:

main()函数的strGetMemory()函数的p的生存周期不同,通过传值的方式(传的指针的值)并没有改变实参指针str所指向地址空间的值,所以调用GetMemory()str依旧是NULL,这时使用strcpy造成程序崩溃.

如何修改:
分清 "传值,传址,传引用" 的作用,这类问题迎刃而解:值传递的是一个值的副本,函数对形参的操作不影响实参的值;)

采用 指向指针的指针 来解决!!! (一般实际编码又不会这样做,指针很危险,指针的指针更危险)

void GetMemory(char ** pp, int num)              // 指针的指针
{
   *pp = (char *)malloc(sizeof(char) * num);
}
...
int main()
{
   char *str = NULL;

   GetMemory( &str, 100);      // 取址!!!

   strcpy(str, "hello");

   return 0;
}

EX2

Q:下面的函数有什么问题?该如何修改

char  * StrA()
{
    char str[] = "hello world";
    
    return str;
}
分析:

str里存放的地址是函数StrA()函数所有栈帧中"hello world"的首地址,函数调用完后,栈帧恢复到调用strA()之前的状态,临时空间被重置,栈帧"回缩",strA()栈帧不再属于应该访问的范围,存在于栈帧里的hello world当然也不应该访问。
这段程序可以正确输出结果,但是这种访问方法违背了函数的栈帧机制,这种方式有不合理性及危险性

总结:
上述的strA()函数返回的是局部变量的地址,当调用这个函数后,这个局部变量str就释放了,所以他的返回结果是不确定且不安全的,随时有被回收的可能

修改:

const char *strA()
{
    char * str = "hello world";

    return str;
}

首先区分:char str[]char *str

  • char str[] = "hello world"是分配一个局部数组,是局部变量,对应分配至栈区,通过赋值操作将字符串常量赋值给局部数组str保存的是栈区的地址(即局部数组)
  • char *str = "hello world"字符串常量,分配在全局数据区,str保存的是全局数据区的地址,指向全局数据区的字符串常量区域

虽然上面两个str都是局部变量,生存周期只是在所处的函数区间,但是通过return返回,第一个返回的地址是栈区的地址,第二个返回的地址是全局数据区的地址。需要用到的数据所处的位置不同,效果也就不一样。

此外:
字符串常量保存在只读数据段,而不是普通数据区,
如:
char * c = "hello world";
*c = 't'; // false

char c[] = "hello world";
c[0] = 't'; // true,局部区的数据可以修改
这里c不占存储空间

补充另外一种修改方法:

const char * strA()
{
    static char str[] = "hello world";

    return str;
}

通过static开辟一段静态存储空间。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容