C语言自定义函数如何返回数组(上)?
最近看到一些同学问题,有提到说:如何在一个函数中返回数组呢?能否直接在自定义 函数中,写成char *类型返回值,直接返回呢?,代码如下:
直接返回str数组名(注意不需要加&,还有好多同学犯这个错)
但事实上,运行结果并非正常,我们尝试在调用函数中输出,可以看到结果并非是原来内容(当然你的电脑输出可能还不是这个样子)
如下:
原因大家可以从str的属性入手,str本身是一个自定义函数中的局部变量,是一个数组有一百个字节,它的生命周期当然也随着它所在的函数一起,正所谓“一招天子一朝臣”,随着fun函数调用的结束,其中的各种局部变量也将被系统收回,理所当然的str数组这一百个字节也将被收回,所以”Hello www.dotcpp.com”这串字符串也就灰飞烟灭了!自然你在main函数里再输出肯定已经不是原来的内容了!
怎么样,可以理解吧!
不过,还没有结束,依然有同学继续问,可为什么我换成下面这种写法就可以了呢?
如下图:
答曰:这种写法情况下,str虽也属于是局部变量,但不是一个数组,而是一个指针,只有四个字节,存的是在常量区的字符串” Hello www.dotcpp.com”,但请注意,这个字符串在常量区,而不属于fun函数里的部分,全程序都可读,所以return之后依旧存在,返回的是str里的值,也就是字符串“Hello www.dotcpp.com”的首地址,是一个数,其实相当于把这个字符串的地址在str手里通过返回值转交到p里。
也可以打个比方:之前只有fun函数知道这个字符串,但现在已经马上不行了,临终前,交代:“我快不行了,赶紧把‘Hello www.dotcpp.com’的藏宝地址(字符串首地址)转交到main函数里!”
然后就return 快马加鞭的返回到main函数手里了!随后消失…
而后,main函数获得之后,你们也就知道了…
这样讲,大家能理解吗?
后期C语言逆向分析部分,也会有涉及到此处的原理,大家可以再深入学习理解。
同时,下篇我们将为大家讲解如何实现自定义函数的数组传递问题! 原来是这样啊,,那没的编译器,结果都一样吗??? 我在工作中写的代码,经常需要返回结构体数组。我的套路是,弄一个OUT参数,返回一个申请的内存。//函数:
long foo(struct XXXX **CallerFree)
{
*CallerFree = malloc(1234);
return 1234;
}
//调用:
struct XXXX *ps = NULL;
long i,c = foo(&ps);
if(c)
{
for(i=0;i<c;i++){use((*ps).XXXX);}
free(*ps);
}DEMO代码比较凌乱,可能有误,但大概就是这么个意思。 所谓返回数组,其实是想生成一堆数据然后把它返回给调用者吧?这里有两种情况,一种是你静态分配内存存储你的数组(所谓静态分配内存,指的是你的数据由编译器在你的可执行文件的数据段里面分配。典型情况是使用全局数组变量,或者使用static修饰符定义局部的数组变量),另一种是动态分配内存存储你的数组(也就是用malloc等函数从内存里分配一块区域用于存储你的数组,然后你把数据写入到这片内存里)。
直接从栈上声明变量数组然后返回地址的方法是不行的。因为非静态变量的生命周期在你的函数返回后结束,你返回的地址实际上是一块不可用的内存区域。
想要把一定数量的数据返回给调用者方法很多,除了用return返回数组的地址以外,还可以在参数里提供一个变量用于指定接收数组地址的变量的地址。
此外,一般情况下你也需要把数组的长度,或者数组的元素个数,也返回给调用者。除非你的数组是字符数组,也就是字符串。这种情况下你可以使用'\0'字符作为字符串结尾,让调用者自己去统计字符个数。
动态分配的内存返回给调用者之后,调用者还需要在用完后,将这块内存交还给内存管理器,通常用malloc或者realloc分配的内存,用free来释放。而静态分配的内存无需释放,或者说,你不能将其释放,因为它已经融入到你的可执行文件里面去了。此时调用free去释放一个静态分配的内存,你会把你的程序搞炸。而如果对于动态分配的内存,你不去释放的话,那你每次调用函数返回一个数组,它就要多占用一块内存区域,时间长了,你的程序就会吃光你的所有内存,这不仅会让你的程序崩溃,也会严重影响你的系统的运行。所以必须严格区分这两种情况。
如果你需要写一个组件给别的开发者用(或者给自己用),你需要提示使用者,这个需不需要释放,以及怎么去释放。此时建议将分配和释放的函数写成配套的,以便于用户翻阅你的文本的时候,能第一时间注意到某个函数有配套的销毁函数可用。典型例子,CreateWindowEx对应的函数是DestroyWindow。
建议学习C语言的同时也要了解可执行文件的结构,包括代码段、数据段、PE头等。PE头、ELF头等结构你可以不用详细掌握,但你需要知道这个概念的存在。并且你需要知道你定义的变量在什么情况下会被分配到栈上,然后在什么情况下会被分配到数据段上。 :L:L:L:L:L:L:L 不错的,学习到一个知识点。
页:
[1]