warning: function returns address of local variable【解决函数返回首地址出错】
文章目录
1- 报错展示
这个提示就是告诉我,我定义的这个tmp_data这个是局部变量(在自定义函数里面定义的),不能返回他的地址,返回给主函数地址没用的,因为我这个函数用完就释放啦,你拿着我的地址找不到我的啊!~
对比分析更好理解:
311行自定义函数返回结构体中的 buf (首地址)失败。
304 char* get_first_data(sqlite3 *db)
305 {
306 package tmp_data;
307 int rc = -1;
308 char *sql_select;
309 sql_select = "select *from temper limit 1";
310 rc = sqlite3_exec(db, sql_select, callback, &tmp_data, NULL);
311 return tmp_data.sed_del_buf;
312 }
但是286行能够返回结构体中int类型的数据。
279 int get_line_count(sqlite3 *db)
280 {
281 package tmp_count;
282 int rc = -1;
283 char *sql_count;
284 sql_count = "select count(*) from temper";
285 rc = sqlite3_exec(db, sql_count, callback_count, &tmp_count, NULL);
286 return tmp_count.count;
287 }
结构体:
typedef struct
{
char sed_del_buf[512];
int count;
}package;
先找原因:
在c程序内存布局中可以知道,我们自定义的函数中的局部变量都是存放在栈区的,并且是自动分配,{}有效,离开后{}中自动释放。上述两个函数中我都是在函数内定义的结构体变量。导致这个结构体变量在函数用完之后就释放了。函数返回后该函数的栈空间消失,所以函数中返回局部变量的地址都是非法的。因为人家消失了,你凭借地址是找不到的。
上述中结构体变量都是在函数内声明的,所以创建的结构体变量就是局部变量,返回结构体的值的时候其实是返回结构体,没有返回结构体的地址;如果返回结构体的地址,就是错误的。
回到问题:
我们返回数值,那肯定可以啊,传过去那边就接收到了,实实在在的数据
我们返回地址,那边可以收到,但是这个地址指向的内容已经被清理了,咋搞?所以指向的内容啥都没有,就是NULL,会提示错误,但是可以运行,只是啥都没有
所以可以获取结构体中int类型的数据,但是不能获取地址,因为地址指向的内容已经消亡了,如下结果:
2- malloc开辟空间解决
C语言内存布局中我们看到在堆区是可以利用malloc自己来管理内存的,用完释放掉就可以了,于是我们利用malloc来解决。
简单来说,malloc函数的作用是开辟一个空间来给你使用,用完free就可以了。
这个方法适合返回的内容是改变的,每次调用函数返回的内容都不一样。
第306行malloc分配空间:
304 char* get_first_data(sqlite3 *db)
305 {
306 package *tmp_data = (package*)malloc(sizeof (package));
307 int rc = -1;
308 char first_data_buf[512];
309 char *sql_select;
310 sql_select = "select *from temper limit 1";
311 rc = sqlite3_exec(db, sql_select, callback, tmp_data, NULL);
312 return tmp_data -> sed_del_buf;
313 }
成功执行:
3- static静态局部变量解决
函数的返回值可以是一个static类型的局部变量的地址。
如果你返回的内容是不变的,就可以用这个方法。
所以在306行定义结构体变量的时候定义为静态局部变量尝试,每次获取到的数值都是一样的,这是因为静态局部变量赋初值是在编译时进行值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。
304 char* get_first_data(sqlite3 *db)
305 {
306 static package tmp_data;
307 int rc = -1;
308 char *sql_select;
309 sql_select = "select *from temper limit 1";
310 rc = sqlite3_exec(db, sql_select, callback, &tmp_data, NULL);
311 return tmp_data.sed_del_buf;
312 }
总体就是这样,理解还是不怎么到位,还需要慢慢加深~