20170507
动态内存分配可以在程序运行的时候随时分配存储位置
动态分配的存储位置一定来自于堆这个段落
堆中的所有存储位置需要使用语句分配和回收
c语言中提供几个标准函数用来分配和回收堆中的存储位置
为了使用这些函数需要包含stdlib.h文件
malloc标准函数用来动态分配多个连续的字节存储位置
malloc把分配后第一个字节的地址赋值给返回值变量
malloc返回值是void*指针,可以转换成任何类型的指针使用
malloc在失败的时候会把NULL赋值给返回值变量
free标准函数用来回收不再使用的动态分配存储位置
释放内存时需要使用第一个字节的地址作为参数
一次分配得到的所有存储位置必须统一释放(不能释放一半留一半)
一段动态分配的内存智能释放一次,释放后记录它的地址的指针将变成野指针
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main() {
5 int num = 0;
6 int *p_num = (int *)malloc(3 * sizeof(int));
7 if(p_num) {
8 for(num = 0; num <= 2; num++) {
9 *(p_num + num) = num + 1;
10 }
11 for(num = 0; num <= 2; num++) {
12 printf("三个数依次是%d ", *(p_num + num));
13 }
14 printf("\n");
15 free(p_num);
16 p_num = NULL;
17 }
18 return 0;
19 }
求中点(动态分配内存)
1 #include <stdio.h>
2 #include <stdlib.h>
3 typedef struct pt {
4 int x, y;
5 } pt;
6 pt *midpt(const pt *p_start, const pt *p_end) {
7 pt *p_ret = (pt *)malloc(sizeof(pt));
8 if(p_ret) {
9 p_ret->x = (p_start->x + p_end->x) / 2;
10 p_ret->y = (p_start->y + p_end->y) / 2;
11 }
12 return p_ret;
13 }
14 int main() {
15 pt start = {}, end = {}, *mid = NULL;
16 printf("请输入第一个点的位置:");
17 scanf("%d%d", &start.x, &start.y);
18 printf("请输入第二个点的位置:");
19 scanf("%d%d", &end.x, &end.y);
20 mid = midpt(&start, &end);
21 if(mid) {
22 printf("中点(%d, %d)\n", mid->x, mid->y);
23 }
24 free(mid);
25 mid = NULL;
26 return 0;
27 }
二级指针形参可以把被调函数动态分配的存储位置交给调用函数使用
这个二级指针形参对应的一级指针存储位置必须由调用函数提供
calloc同样可以动态分配连续的存储位置
calloc会把分配好的所有存储位置都清0
calloc分配时需要考虑存储位置的类型
realloc函数调整一段动态分配内存的大小
函数指针可以用来记录函数的地址(函数里面第一条语句的地址)
函数指针可以用来调用函数
函数名称可以用来表示函数的地址
1 #include <stdio.h>
2 int add(int x, int y) {
3 return x + y;
4 }
5 int main() {
6 int (*p_func)(int, int) = NULL;
7 printf("add是%p\n", add);
8 p_func = add;
9 printf("计算结果是%d\n", p_func(3, 6));
10 printf("计算结果是%d\n", (*p_func)(3, 6));
11 printf("p_func是%p, *p_func是%p\n", p_func, *p_func);
12 return 0;
13 }
1 #include <stdio.h>
2 int add(int x, int y) {
3 return x + y;
4 }
5 int sub(int x, int y) {
6 return x - y;
7 }
8 int mul(int x, int y) {
9 return x * y;
10 }
11 int div(int x, int y) {
12 return x / y;
13 }
14 int main() {
15 int num = 0, num1 = 0, sum = 0;
16 char opr = 0;
17 int (*p_func)(int , int);
18 printf("请输入一个表达式:");
19 scanf("%d%c%d", &num, &opr, &num1);
20 if(opr == '+') {
21 // sum = add(num, num1);
22 p_func = add;
23 }
24 else if (opr == '-') {
25 //sum = sub(num, num1);
26 p_func = sub;
27 }
28 else if (opr == '*') {
29 //sum = mul(num, num1);
30 p_func = mul;
31 }
32 else {
33 //sum = div(num, num1);
34 p_func = div;
35 }
36 printf("%d\n", p_func(num, num1));//具有更好的扩展性,将来可能加入新函数
37 return 0;
38 }
函数指针可以用来代表未来扩展的新函数
使用函数指针可以编写出更灵活,更有扩展性的程序
1 #include <stdio.h>
2 typedef struct expr {
3 int num, num1;
4 int (*p_func)(int, int);
5 } expr;
6 int add(int x, int y) {
7 return x + y;
8 }
9 int sub(int x, int y) {
10 return x - y;
11 }
12 int mul(int x, int y) {
13 return x * y;
14 }
15 int div(int x, int y) {
16 return x / y;
17 }
18 int main() {
19 int num = 0;
20 char opr = 0;
21 expr expr[3] = {};
22 for(num = 0; num <=2; num++) {
23 printf("请输入一个表达式:");
24 scanf("%d%c%d", &expr[num].num, &opr, &expr[num].num1);
25 if(opr == '+') {
26 expr[num].p_func = add;
27 }
28 else if(opr == '-') {
29 expr[num].p_func = sub;
30 }
31 else if(opr == '*') {
32 expr[num].p_func = mul;
33 }
34 else {
35 expr[num].p_func = div;
36 }
37 }
38 for(num = 0; num <= 2; num++) {
39 printf("结果是%d\n", expr[num].p_func(expr[num].num, expr[num].num1) );
40
41 }
42 return 0;
43 }
1 #include <stdio.h>
2 int main() {
3 int arr[] = {4, 9, 2, 6, 7};
4 int *p_num = NULL;
5 for(p_num = arr; p_num <= arr + 4; p_num+ +) {
6 printf("%d ", *p_num);
7 }
8 printf("\n");
9 return 0;
10 }
atoi函数可以把字符串中的整数提取出来得到整数数值
atof函数可以把字符串中带小数点的数字提取出来得到double类型数值
为了使用这两个函数需要包含stdlib.h文件
1 #include <stdio.h>
2 #include <stdlib.h>
3 int main() {
4 int num = atoi("123");
5 double dnum = atof("4.56");
6 printf("num是%d\n", num);
7 printf("dnum是%lg\n", dnum);
8 return 0;
9 }
sprintf函数可以把数据按照格式打印在字符串中
sscanf函数可以按照格式从字符串中把数字读出并存储在存储位置里
fprintf/fscanf是对文件进行格式化操作的标准函数
sleep函数可以让进城等待一定时间,时间用秒为单位表示
等待时间不精确,需要包含unistd.h文件
输出缓冲区内容显示在屏幕上的条件:
1.输出缓冲区中遇到'\n'
2.执行打印任务的函数结束了
3.输出缓冲区里满了
4.使用fflush(stdout)强制显示