《嵌入式linux上的c语言编程实践》(亚嵌教材)学习笔记

2019-07-13 06:41发布

第九章内存的堆和栈   c使用的内存分为:静态区和动态区,静态区 静态区:只读数据区,初始化数据区,未初始化数据区 动态区:堆区,栈区   栈: 1.使用依赖硬件机制,有两种增长方向。有空栈和满栈。空栈:栈指针指向未使用的数据区。满栈:栈指针指向没使用的数据区。 2.由编译器管理。函数退出内容释放,栈上的内存不能被别的函数使用(不能返回站内变量的地址)。 3.使用线性存储方式 4.主要特性:FILO,先进后出 5.有一个指针,通过指针+偏移量来访问 6.   堆: 1.堆的增长方向和栈相反。(大体上如此) 2.堆由程序员管理,调用和释放由程序的库函数完成。每次分配返回一个指针,可多次分配,得到多个指针,可用每个指针来访问。 3.用链表实现 4.四个分配和释放的函数:mallocfreecallocreallooc 5.可以再一个函数中开辟,另一个函数中释放。   堆内存管理容易出现的问题: 1.       内存泄露 2.       野指针的使用和释放 3.       非法释放指针。 正确的使用方法:在内存释放后,将内存指针置为NULL,在使用时判断指针释放为NULL 正确使用堆 /* how to use malloc correctly */ #include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
        char *pa;
        pa = (char *)malloc(sizeof(char)*20);
        if(NULL != pa)
        {
                strcpy(pa, "memory leak");
                printf("pa = %x ", (unsigned int)pa);
                printf("pa = %s ", pa);
        }
        free(pa);
        pa = NULL;
        if(NULL != pa)
        {
                printf("pa = %s ", (unsigned int)pa);
        }
        return;
}
堆,栈的使用比较: 1.       利用返回值传递信息 1)返回值可以是任何内存的地址,但不能返回内部栈区的地址。 当希望返回栈上较多的内容时,不能用指针,可以用结构体(结构体在函数外定义),但开销比较大。 2)返回结构体是,要从被掉函数的栈空间中将结构体复制的调用函数的栈空间上,pushpop开销大。 2.利用参数传递信息 1)参数是变量的情况,swap函数,不能交换 2)参数是指针的情况,swap可以交换 3)参数是结构体的情况和变量类似。开销大,可以定义结构体指针,来传递参数。 4)参数是数组的情况,当做指针来处理。实际入栈的是数组地址的指针。 第十章 函数指针的使用        函数指针是指向函数代码地址的指针。C语言中,函数名表示函数代码在内存中的地址。 例如:函数foo()&foofoo的含义相同。和数组名类似。 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