段、栈与局部变量、全局变量、静态变量
很多时候,我们会遇到自己写的程序代码在编译时报一些段地址等相关的错误,主要是对几个概念不清楚,下面通过栗子理解下。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int *fun()
{
int p = 100;
return &p;
}
int main(void)
{
int *p = fun();
printf("%d\n", *p);
return 0;
}
上面代码编译时会报错“函数返回变量地址 -Wreturn-local-addr",有些编译器可能将这个错当成warning,但最终执行文件时,就会出现段错误:Segementation fault.
这是因为函数fun里的变量p是局部变量,局部变量是在栈中分配的,当fun返回,栈里的内容就被释放给别人使用了,所以这里再return这个被释放的地址,自然就不允许了。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int *fun()
{
int *p = malloc(4);
memset(p, 0, 4);
*p = 100;
return p;
}
int main(void)
{
int *p = fun();
printf("%d\n", *p);
return 0;
}
这里fun函数里定义了一个局部int类型指针,指向malloc分配的空间,这个程序编译以及执行都不会有问题,可以正常输出100.这里malloc它是在堆上面分配空间,堆上分配不会自动释放,需要用free来手动释放。这也是很多程序中有时忘记这点而导致crash的原因之一。
在第一个程序中,如果我把局部变量声明成static,或者直接把局部变量改成全局变量,第一个程序也可以正常编译与执行,道理是一样的,static, 全局都是在静态空间分配内存,在程序退出才会释放,不同的是在堆上分配空间需要申请空间者自己释放,比如free。
下面再来一个关于结构体的用法:
typedef struct
{
char *p;
}st;
st *fun()
{
static st t;
t.p = (char*)malloc(10);
memset(t.p, 0, 10);
memcpy(t.p, "abcd", 4);
return &t;
}
int main()
{
st *p;
p = malloc(sizeof(st));
p=fun();
printf("%s\n", p->p);
free(p);
}