2014.3.11-C语言学习小结

链表:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
知识点:
    1.链表基础
    2.节点的创建和添加      llist_append_node
    3.链表的遍历     llist_print_each
    4.链表的查找与修改
    5.链表的插入与删除
    6.链表的销毁
    7.链表逆序
 
 
==========================
回顾数组
    1.数组的常用操作
      1)插入
      2)修改
      3)遍历
      4)删除
      5)逆序
    2.数组操作的问题
      1)插入和删除的效率低
            1 2 3 5 6 0 0
            1 2 3 4 9 5 6
            1 2 3 4 9 5 6 0
      2)当数组空间不足时需要重新申请内存空间
      3)但是遍历速度快
==========================
链表基础
    1.什么是链表
       链表(Linked list)是一种常见的基础数据结构,是一种线性表
    2.链表的作用
      一种数据结构,保存数据
    3.如何创建链表
==========================
链表节点的创建和添加
    1.如何创建和添加一个节点
    2.如何插入一个节点
    4.处理链表的框架
void llist_append_node
            (struct node *head,
                  struct node *new)
void llist_change_node(struct node *head,
                         int id,
                         char *name)
        append  *
        insert  *
        search  *
        change
        delete
        destory
        print_all  *
        print_node
 
    5.添加节点模块append
    练习:添加一个节点到头结点后面
==========================
链表的遍历
    1. llist_print_each函数
    void llist_print_each(struct node *head);
     练习:
          1.遍历输出链表内容
          2.向链表添中加多个节点
==========================
链表的查找与修改
    1. llist_search_node函数
struct node *llist_search_node(struct node *head, int id)
void llist_print_node(struct node *nd)
      1)遍历链表
      2)比较要搜索的内容是否和节点数据内容匹配
      3)返回节点地址
      练习:
        1.查找指定id的学生信息,并输出该信息
    2.change函数
      1)搜索要修改的节点空间
      2)修改节点内的数据
        1.修改指定id的学生性别
==========================
链表的插入和删除
    1. llist_insert_node函数
void llist_insert_node(struct node *head,
                        struct node *nd, int id)
      1)创建一个新节点
      2)插入到指定位值
      练习:
            链表包含10个节点
            id=3,id=4 <== tmp
                   id=1
           1.创建一个新节点并且插入到第一个节点的前面
           2.创建一个节点并且插入到第三和第四个节点之间
    2.delete函数
void llist_delete_node(struct node *head, int id);
      1)修改该节点上一个节点的指向
      2)释放当前节点
      练习:
        1.删除id为1节点
        2.删除id为10节点
        3.删除id为5节点
==========================
链表销毁
    1.destory函数
    int llist_destory(struct node *head);
     1)销毁和清空是两种不同的操作
       例如:倒空杯子的水和砸碎杯子两个操作
     练习:
         销毁上面创建的链表
==========================
链表逆序
    H->A->B->C->D->E
       ^  ^  ^ 
       p  pp  t
    1.inverse函数
void llist_inverse(struct node *head);
     练习:
         1.按照上述顺序实现一个链表的逆序,并输出逆序的结果
==========================
多文件封装
    1.头文件
    2.实现文件
==========================
创建一个班级链表,该链表包含10个学生信息
1.每个学生包含信息有
        姓名,年龄,身高,性别,语数英三门成绩
2.实现:
    1)添加学生信息
    2)输出所有的学生信息
    3)搜索指定学生的信息,并且输出
    4)将指定学生插入到指定学生的前面
    5)删除指定学生信息
    6)销毁班级链表
    ========================
    enume menu{
            EXIT, ADD, SONE, SALL,
                 INSERT, DEL, DELALL};
    1.添加学生
    2.查询指定学生信息
    3.查询所有学生信息
    4.学生插队
    5.删除指定学生信息
    6.删除班级
    0.退出系统

  

 

预处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
知识点:
    1.宏的定义      #define    #undef
    2.宏与函数的区别
    3.文件包含和多文件编译    #include <> “”    #import
    3.条件编译      #if  #elif #else #endif
                #ifdef  #ifndef
    4.typedef关键字
 
> gcc -E  源代码文件.c -o 预处理结果文件.i //预处理
> gcc -S   预处理结果文件.i -o 汇编结果文件.s //编译  翻译为汇编  
> gcc -c 汇编结果文件.s -o 目标文件.o //汇编
> gcc 目标文件.o -o a.out         //链接   ld
=================================
宏定义
    0.什么是宏定义
      1)宏定义是C提供的三种预处理功能中的一种,预处理包括宏定义、文件包含、条件编译
    1.宏定义的作用
      1)使用标识符来替换一些常用的代码
        for (i = 0; i < 100; ++i)
   
        LOOP100
        {
            printf(“i”);
        }
        WALK  小明---nickname 别名
    2.宏定义的本质
      1)一种占位符,用来代替一些常用代码
      2)一切以转换为前提,做任何事情之前先要替换
    2.基本的宏定义
      0)#define指令语法!!!!
        宏指令   宏名        宏体
      1)标识符
      2)大写,不加分号结束
      3)使用
      示例:定义常量PI的宏
      练习:
          定义数组大小的宏
              定义重力加速度宏  9.8 G
    3.带有参数的宏定义
      1)示例:计算两数最大值的宏
        练习:
         1.计算两数最小值的宏    ?:
         2.计算两数之和的宏,两数之积
 
 
    思考:ADD(1,2)*ADD(1,2)结果
       
        
 
 
    4.宏替换的问题
      1)宏替换作用的演示,gcc编译参数   
      2)思考:能否嵌套定义或调用
 
 
 
 
    5.常用宏 
      2)字母大小写转换
        TOLOWER     ch + 32
        TOUPPER     ch - 32
     
      4)设置指定数某位为1或0
        SET1, SET0
 
      5)获取某一位的值
        GETBITS
      6)取得一个short的高1个字节和低1个字节
        SLOW
        SHIGH
      7)将short的高字节和低字节互换   
      8) 交换两数宏 
      9)安全释放内存宏  SAFTY_FREE
         
    6.宏和函数的区别
      1)思考:宏的本质和函数的本质
      2)思考:宏和函数调用的速度,安全性和空间
      3)回忆函数调用的过程
        函数调用需要开辟栈空间,保存参数和局部变量
      4)本质:宏只是替换,并不会产生函数调用
      5)速度:宏不占运行时间,只占编译时间,函数调用占运行时间
      6)安全:宏不会检查参数类型,函数会检查参数类型
      7)空间:宏的参数不占用空间,函数的用空间
      8)能否调用自身:宏不能进行递归调用,函数可以
       思考:如何结合宏与函数的优势
        1.代码非常简单而又十分常用的时候使用宏
        2.代码非常复杂,一般使用函数
==================================
文件包含和多文件编译
    1.思考:如何实现多人合作项目
        接口---->函数原型  .h  //head
        实现---->函数定义  .c
         
    cvs git svn
         
    2.回忆函数定义和声明
    3.头文件和源文件
    4.#include指令语法!!!!
      1)本质:头文件包含实际是替换文件内容
      2)作用:实现声明和实现相分离,进一步使程序更加的模块化 
 
        #include <stdio.h>  尖括号表示系统标准目录      
        双引号表示自定义路径     
            add,  sub, mut, div
    5.示例:链表的实现的声明相分离
      练习:
        1.实现加减乘除四则运算,并将函数的声明与实现相分离
          并编写测试函数测试该些函数
 
        A B C D     200     100
 
         
===================================
条件预编译
    需求:现在用户只购买系统中的某些模块
    1.思考:如何可以简单快速的在编译的过程中满足用户的需求
    2.#ifdef 条件编译语法!!!!
         #ifndef
        1)作用:模块选择
      示例:判断是否定义过PI宏
      练习:判断是否有定义上述的常用宏
    思考:
       1.如何可以安全,快速的注释代码
       2.// 和 /**/注释是否可以嵌套使用
    3.#if 条件编译语法!!!!
      1)作用
         快速安全的注释代码
    4.安全注释
    思考:如果重复包含头文件会如何
    5.防止头文件重复包含
===================================
调试宏
        NSLog
    思考:如何使用printf调试代码,是否方便移出
    1.调试宏定义
      INFO, WARN, ERROR, DEBUG
    2.调试开关
    3.预定义宏
        printf("line = %d, file = %s, DATA = %s, TIME = %s",
                __LINE__, __FILE__, __DATE__, __TIME__);
      __LINE__:行号
      __FILE__:文件名
      __DATE__:日期       %s
      __TIME__:时间
      __FUNCTION__, __func__:函数名
===================================
typedef关键字              int4        int32       int64
    思考:程序的跨平台性      64  32  16  8
                    int    int     int2
                    long  long     long
 
            size_t
 
            long long   int64
            long
 
    1.typedef作用
       1)typedef常用来定义一个标识符和及关键字的别名,并不分配实际的内存
       2)typedef可以增强程序的可读性
       3)typedef可以增强标识符的灵活性
    2.typedef本质
       typedef本质为类型的别名
    3.typedef语法使用!!!!
    4.重定义结构体
    5.重定义类型
    6.typedef与define的区别
      1)typedef是为了程序的可读性而为标识符另起的别名,而
        define在c语言中是为了定义常量,常用代码替换
      2)define可以使用#ifdef和#ifndef来进行逻辑判断

  

动态内存分配:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
知识点:   
    动态内存管理
    1.数据在内存中的存储
    2.内存分配malloc和realloc和calloc函数使用和注意事项
    3.free函数使用
    4.堆和栈的区别      .heap  .stack  .bss   .data   .rodata
    5.常用内存操作函数 
==============================
内存使用
    1.回顾函数在使用时候所开辟的内存栈
    2.变量所在的内存空间
    3.栈空间的限制    stack 
      1)栈大小:一般在2M左右
    4.栈数据的特点
      1)回顾局部变量的生命周期
      2)每个变量的内存大小均在编译时候确定,空间由操作系统分配
      3)数据由系统自动释放
      4)数据分配在栈段
    思考:
            int var;
            return &var;
20000 / 1000 == 20
        0.是否可以返回函数执行过程中局部变量的内存地址
        1.如果需要的内存栈无法提供足够的内存容纳我们的数据怎么办
        2.如果需要将函数内的数据保存到程序结束再销毁,是否可以
    5.堆空间的使用        heap
      1)堆空间的特点
        1>大小由程序员决定,空间由程序员分配
        2>大小在运行时候确定
        3>由程序员手动释放
        4>数据分配在堆段
==============================
动态内存分配函数
    1.malloc  内存分配
      1)函数原型
        void *malloc(size_t size)
        void *calloc(int n, size_t size)
            申请size个字节的内存
      2)函数使用
          void *p = malloc(4096 * 1024 * 1024);
      3)分配内存注意 
         1)函数执行完后如果成功,返回该size大小内存的首地址
         2)函数执行失败返回NULL
         3)malloc会在堆上寻找一块size个字节的内存返回给用户
         4)使用之前一定要判断是否分配成功,因为malloc函数执行有可能会失败(内存不足)
            1.内存不足
            2.没有足够大的连续内存空间
     
             
        练习:
        1.分配一能足够保存double              数据的内存空间,并且赋值输出
            2.分配一个足够保存n个double类型数据        的内存空间,并且赋值输出
 
 
    思考:如果现在所使用的内存空间不足,想要重新分配一块内存,但是又不想丢失原来的数据,么办
    2.realloc  重新分配内存
      1)函数原型
          void *realloc(void *ptr, size_t size)
          在ptr指针后再分配size个字节的内存空间
      2)函数使用
        realloc(ptr, 40);
      3)函数使用注意
        1)思考:如果ptr执行NULL会如何
        2)思考:如果在ptr后没有size个字节的内存会如何
        3)思考:函数返回值是什么
        练习:使用realloc函数为malloc分配的内存向后扩展40个字节的空间
            0.比较返回地址是否为原理的内存地址
            1.输出新空间中的所有内容
            2.对新的内存空间进行赋值
            
================================
内存释放函数
    思考:申请的内存是否需要释放,不释放是否可以,会造成怎样的结果
    1.free 内存释放
      1)函数原型
         void free(void *ptr)
      2)函数使用
        free(ptr)
      3)函数使用注意
        思考:释放后的内存是否可以继续使用
        1>只能对有效分配的内存进行释放
        思考: 被释放的内存还可以引用吗
        2>思考:如果对一个指针连续释放两次会如何
             3>不能释放栈上的空间
        3>如何避免上述情况
        练习:释放malloc和realloc申请的内存空间
================================
堆和栈的区别
    1.分配大小
        栈   不能超过2M
        堆   可以任意分配,只要系统有内存
    2.分配速度
        栈   快
        堆   慢
===============================
数据在内存中的存储与分布
    1.数据区:栈,堆,数据段
    2.栈
      1)进入函数时分配空间,函数结束时释放空间
      2)局部变量,函数参数均在此段中
      3)此段中的初始值均为随机数
    3.堆
      1)malloc申请,free释放
      2)初始值
    4.数据段
      1)全局变量    bss 没有初始化的全局变量
      2)static静态变量
      3)字符串常量(只读静态存储取)   rodata
================================
常用内存处理函数
 
    1.memset 将指定地址指定大小设置为指定内容
      1)函数原型
        void *memset(void *ptr, int c, size_t len)
      2)函数使用
      3)函数使用注意
        练习:分配10个字节的内存空间
        1.输出该空间中的内容
        2.将该内存空间上的内容全部设置为1 
    2.memmove  内存拷贝,从s2拷贝len的字节内容到s1中
       1)函数原型
        void *memmove(void *dst, const void *src, size_t  len)
        void *memcpy(void *dst, const void *src, size_t  len)
       2)函数使用
       3)函数使用注意
===========================================

  

2014.3.11-C语言学习小结,布布扣,bubuko.com

2014.3.11-C语言学习小结

上一篇:HTML5常用标签


下一篇:C++基础分析(2)