函数与动态申请内存

案例分析1

void GetMemory(char *p)

{

    p = (char *)malloc(100);

}

void Test(void)

{

    char *str = NULL;

    GetMemory(str);

    strcpy(str, "hello world");

    printf(str);

}

程序不能运行。str一直是NULL指针,strcpy操作需要目标数组的大小不小于源数组大小,所以会造成程序崩溃。程序崩溃的原因在于GetMemory不能动态传递内存,Test调用GetMemory时使用的是值传递,即调用后p==null,str==null,p和str没有关联关系,因此用p申请内存后,不能将该内存传递给str。而且,由于形参在函数调用结束后会自动消亡,p申请的内存无法引用,造成了内存泄漏。

案例分析2

void GetMemory2(char **p, int num)

{

    *p = (char *)malloc(num);

}

void Test(void)

{

    char *str = NULL;

    GetMemory2(&str, 100);

    strcpy(str, "hello");

    printf(str);

}

程序可以运行,即能输出“hello”。与案例1不同的是,Test在调用GetMemory2时传递的是str的地址,即char指针的地址。GetMemory2的第一个形参p是指向char指针(char *)的指针。这样,*p指向的是str的地址,*p = (char *)malloc(num)相当于用str的地址动态的申请一块内存。GetMemory2返回后,str依然指向该内存,所以可以调用strcpy函数。

案例分析3

void GetMemory(char *&p)

{

    p = (char *)malloc(100);

}

void Test(void)

{

    char *str = NULL;

    GetMemory(str);

    strcpy(str, "hello");

    printf(str);

}

程序可以正常运行。Test()调用GetMemory时将str传递给p,注意,这是p是个指向char指针的引用,实参和形参结合的过程中,将&p绑定到str上,即相当于p是str的一个别名。

案例分析4

char *GetMemory(void)

{

    char p[] = "hello world";

    return p;

}

void Test(void)

{

    char *str = NULL;

    str = GetMemory();

    printf(str);

}

程序发生乱码。在GetMemory中,p[]=”hello world”属于局部变量,局部变量在函数返回后自动消亡,这样GerMemory返回后,str指向的地址不是NULL,但内容未知。

案例分析5

void Test(void)

{

    char *str = (char *) malloc(100);

    strcpy(str,"hello");

    free(str);

    if(str != NULL)//释放内存后,str并不为空,即传说中的野指针,if判断为真。

    {

        strcpy(str,"world");//此时对str进行赋值,

        printf(str);

    }

}

“野指针”不是NULL指针,是指向“垃圾”内存(不可用内存)的指针。人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if无法判断一个指针是正常指针还是“野指针”。有个良好的编程习惯是避免“野指针”的唯一方法。

野指针的成因主要有三种:

  一、指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。

  二、指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。

    三、指针操作超越了变量的作用范围.

案例分析6
vector<int> f3()
{
int i = 3;
vector<int> c(3);
vector<int>::iterator it;
for( it= c.begin();it!=c.end();++it)
*it = 2*i++;
for( it= c.begin();it!=c.end();++it)
cout<<*it<<" ";

cout<<endl;
return c;
}
该函数可以正确返回。vector是一个类,返回时调用拷贝构造函数,将vector复制到一个临时变量中,然后返回这个临时变量。程序虽然正确,但是这段代码的效率并不高,如果vector中有很多元素,那么调用拷贝构造函数时会需要大规模的赋值操作,影响程序的性能。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
int * f1()
{
int p[] = {1,2,3,4};
cout<<p[0]<<" "<<p[1]<<" "<<p[2]<<" "<<p[3]<<endl;
return p;
/* 函数不能正确返回p,因为p是局部变量,函数结束后会局部变量会被销毁。*/
}

void f2(int *p )
{
int a[] = {1,2,3,4};
p = a;
return;
}

vector<int> f3()
{
int i = 3;
vector<int> c(3);
vector<int>::iterator it;
for( it= c.begin();it!=c.end();++it)
*it = 2*i++;
for( it= c.begin();it!=c.end();++it)
cout<<*it<<" ";

cout<<endl;
return c;
/*可以正常返回。vector是类,类返回时会自动调用拷贝构造函数,
所以会将vector保存在一个临时变量中,并返回这个临时变量。*/
}
int * f4(int n)
{
int *p;
p = new int[n];
for(int i = 0 ; i < n ; ++ i)
p[i] = i*2;
return p;

/*
可以正确返回。函数中动态申请的内存,是在堆中完成的,堆上
的元素在函数结束后,并不会被系统收回。
*/
}
void f5(int **p)
{
*p = new int[n];
for(int i = 0 ; i < n ; ++ i)
p[i] = i*2;
/*
可以正确返回。函数的形参是int **类型,形参和实参结合时,*p指向的是实参的地址,用*p申请内存
相当于用实参的地址申请内存,所以程序可以正常运行。
*/
}

void f6(int *&p)
{
p = new int[n];
for(int i = 0 ; i < n ; ++ i)
p[i] = i*2;
/*
可以正确运行。函数的形参是实参的地址引用,用实参的地址申请内存当然没有问题啦。
*/
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值