分享

关于函数返回局部指针的总结(大部分来自网文)

 千年长叹 2012-03-13
 
关于函数返回局部指针的总结(大部分来自网文)
2010-08-03 11:05

例子1)
#include<stdio.h>
#include<string.h>
char *fun(char tt[])
{
int i;
for(i=0;tt[i];i++)
{
if((tt[i]>'a')&&(tt[i]<'z'))
tt[i]-=32;
}
return (tt);
}
void main()
{
int i;
char tt[81];
printf("\n Please enter a string: ");
gets(tt);
printf("\nThe result string is: %s",fun(tt));
printf("\n");
}

b.

#include<stdio.h>
#define N 10
int * fun(int a[N],int n)
{
      int b[N];
     ..。。。。
      .。。。。(省略一些代码)
.
.
       return b;
}

void main()
{
int w[N],*p;
     .。。。。
     .。。。。(省略一些代码)
.
p=fun(w,N);
}


结论:a的例子是没问题的,因为数组就是指针,你传数组实际上传的是指向它的首指针,然后在fun函数中利用指针把数组(外面的)中的值修改了,并仍返回这个数组的首指针。

b的例子是有问题的,错在fun函数本身。
int * fun(int a[N],int n)
{
int b[N];
return b;
}
b数组不是动态申请的,它的作用域仅在fun函数中,出了这个函数b数组就不存在了。这时返回b数组的指针,外边引用时会生意想不到的内存错误。
所以说这时的b就成了无向指针了。

所以就可以理解例子2了

typedef struct node *link;
struct node
{
int v;
link next;
};

link NEW(int v, link next)
{
link x = malloc(sizeof *x);
x->v = v; x->next = next;
return x;
}

这个函数是用来在链表头插入一个新元素。让我疑惑的是最后一句return x; x是一个局部指针,在函数返回以后就被销毁了,函数返回值是否还有意义呢?

在 New() 函数里分配了一块内存,并把内存的地址赋值给了 x,而最后 return x 只是返回了这块内存的地址,而这块内存由于并没有释放,因此返回的地址是有效的。

另外注意,x 是局部变量,它在栈里分配,函数退出后由于函数原先所使用的栈框架无效了,局部变量也无效了。但返回的是 x 的值而不是地址,x 的值被赋予了接受这个函数返回值的变量,即使 x 本身的存储空间无效了也没有关系了。而动态分配的内存在堆里,如果不释放,这块地方一直有效。

link x = malloc(sizeof *x);

这时变量x指向的是堆中的东东,
所以返回时,是可以的。

char * a()
{
char str[]="Hello World.";
return str;
}

这里,str是指向栈上的东东,返回就不对的啊~

函数的返回值有意义,因为这个返回值已经在调用函数中赋给了一个指针变量。这个指针变量所指的就是一个堆中的一块内存。
注意malloc是在堆中分配内存,不是在栈中,所以函数退出后,内存不会自动释放。要想释放就必须用free显式释放。

所以说

有两种情况,函数会返回指向局部变量的指针:

  1. 返回由malloc动态分配的内存指针。这种情况是合法的,但它假设调用者会释放动态分配的内存。在这种情况下通常会有另一个函数提供释放内存的功能。
  2. 返回指向局部变量的指针。局部变量占用的内存会在函数返回时被系统自动回收,因此系统可以随时将其它数据写入这块内存。在这种情况下函数可以编译通过,但不能保证运行正确。

这种函数通常可以被改造如下:

  • 把返回的指针加到参数列表里
  • 加一个指示长度的参数,或者假设指针指向的数据以null结尾
  • 修改返回指针指向的数据
  • 函数或者不返回值,或者返回一个bool值表示成功/失败

Bluffer C programmers are forever returning pointers to character arrays from functions. If you come across one of these functions you know that one of the following must be true:

  1. The data pointed to by the pointer was allocated dynamically within the function with malloc (or new in C++), and the function expects the caller to un-allocate the data dynamically with free (or delete in C++). This would be legal but is only likely if the function is allocating resources for you in some special way. In these cases a second function is generally provided to un-allocate the resource when it is no longer needed.
  2. The data pointed to by the pointer was allocated automatically within the function and was un-allocated automatically when the function returned. The data pointed to by the pointer may contain the correct data right now, but the system may decide to overwrite it at any time. Bluffer programmers think this is OK because their program compiles and it occasionally works.

When a bluffer C programmer has returned a pointer to a local variable from a function, the function should generally be re-written as so:

  • Add a return pointer to the list of parameters.
  • Either add a length parameter, or expect the data to be null-terminated.
  • Modify the data pointed to by the return pointer.
  • Return void or a boolean to show success/failure.

Callers of this function must allocate the return data before calling the function with the address of that return data. Normally this data is allocated and unallocated automatically simply by declaring a normal variable.

e.g.:

char chArray[10];
bool bTest = MyFunction(chArray, 10);
// remember chArray is the address of chArray[0]. I could have declared it as char pchArray[10] to avoid confusion.

The classic example is the use of the standard strcpy and strncpy functions.


#include <cstdio>

char* get_str()
{
    
char *str = {"abcd"};//可以
    
//char str[] = {"abcd"};//错误,结果不确定
    return str;
}

int main()
{
    
char* p = get_str();
     printf(
"%s ", p);
    
    
return 0;
}

char *str = {"abcd"};//可以,是因为"abcd"是一个字符串常量,它并不在一个栈空间上,而是在静态存储区上。
字符串的生命周期是:程序开始时分配,程序结束时释放。
(当然,str是一个指针变量,在栈空间上,因此函数返回时会释放,但是所指为字符串常量,字符串常量所占空间在函数返回时不会释放)

而char str[] = {"abcd"};//错误,结果不确定,虽然从编译器的实现来看(见如下代码(VC6下)的结果),"abcd"仍然是当成一个字符串常量,但是程序又把它复制了一次,放在了栈空间上,返回的时候str所指的是栈上的这一块字符串。问题的本质仍然是由于返回了指向栈空间的指针。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多