第九章内存的堆和栈
c使用的内存分为:静态区和动态区,静态区
静态区:只读数据区,初始化数据区,未初始化数据区
动态区:堆区,栈区
栈:
1.使用依赖硬件机制,有两种增长方向。有空栈和满栈。空栈:栈指针指向未使用的数据区。满栈:栈指针指向没使用的数据区。
2.由编译器管理。函数退出内容释放,栈上的内存不能被别的函数使用(不能返回站内变量的地址)。
3.使用线性存储方式
4.主要特性:FILO,先进后出
5.有一个指针,通过指针+偏移量来访问
6.
堆:
1.堆的增长方向和栈相反。(大体上如此)
2.堆由程序员管理,调用和释放由程序的库函数完成。每次分配返回一个指针,可多次分配,得到多个指针,可用每个指针来访问。
3.用链表实现
4.四个分配和释放的函数:malloc,free,calloc,reallooc
5.可以再一个函数中开辟,另一个函数中释放。
堆内存管理容易出现的问题:
1. 内存泄露
2. 野指针的使用和释放
3. 非法释放指针。
正确的使用方法:在内存释放后,将内存指针置为NULL,在使用时判断指针释放为NULL
正确使用堆
|
堆,栈的使用比较:
1. 利用返回值传递信息
(1)返回值可以是任何内存的地址,但不能返回内部栈区的地址。
当希望返回栈上较多的内容时,不能用指针,可以用结构体(结构体在函数外定义),但开销比较大。
(2)返回结构体是,要从被掉函数的栈空间中将结构体复制的调用函数的栈空间上,push和pop开销大。
2.利用参数传递信息
(1)参数是变量的情况,swap函数,不能交换
(2)参数是指针的情况,swap可以交换
(3)参数是结构体的情况和变量类似。开销大,可以定义结构体指针,来传递参数。
(4)参数是数组的情况,当做指针来处理。实际入栈的是数组地址的指针。
第十章 函数指针的使用
函数指针是指向函数代码地址的指针。C语言中,函数名表示函数代码在内存中的地址。
例如:函数foo(),&foo和foo的含义相同。和数组名类似。
1.函数指针的声明:int (*pf)() 因为()的结合优先级高于*,所以用括号,
否则为*g(),意为返回值为指针的函数。
简单函数指针的定义:
Void (*pf) (void);
然后复制: pf=foo;
2. 函数指针的类型转换
类型转换只需要将声明中的变量名和声明末尾的分号去掉,然后用括号括起来即可。
如 int (*fp) (); 表示fp是个指向返回值为整形的函数的指针。因此
( int (*) () ) 表示一个“指向返回值为整形的的函数的指针”的类型转换符。
注:函数的声明和调用不同。
第十四章 嵌入式c语言常用语法
1.使用指针操作内存
向地址0x0040处写一个字节的数据0xf0
Unsigned char *p = (unsigned char *)0x0040;
*p = 0x40;
或:
*(unsigned char *)0x40; //注意unsigned的使用,思考读?16位的读?32位的读?
3. 结构体成员的对齐问题
typedef struct _s1
{
char m1;
int m2;
char m3;
shaort m4;
}S1;
sizeof(S1)不等于8个字节,等于12个字节,故在定义结构体时,注意结构体成员的排列顺序,使结构体最小。
4. 变量的初始化技巧
//数组的初始化
char a[10] = "abcde"
//编译器做了很多事情才完成,先在栈上开辟10个字节空间,然后从内存中复制。
static const rodata[6] = "abcde";
char b[10];
strcpy(b,rodata);
//使用函数完成赋值,在函数运行时完成
//两者依赖的库不通,效率和规模类似。
结构体的初始化
使用每个赋值的方式比使用列表赋值的方式开销小。
struct S
{
int a;
int b;
int c;
}s1;
//列表方式,开销大
fun()
{
s1 = {1,2,3};
}
//成员分别赋值开销小
fun()
{
s1.a=1;
s1.b=2;
s1.c=3;
}
http://blog.chinaunix.net/uid-24194439-id-90753.html