函数指针可以作为形式参数使用,会作为实际参数使用的函数叫回调函数
/* * 回调函数演示 * */ #include <stdio.h> void print_cb(int *p_num) { printf("%d ", *p_num); } void neg_cb(int *p_num) { *p_num = 0 - *p_num; } void for_each(int *p_num, int size, void (*p_func)(int *)) { int num = 0; for (num = 0;num <= size - 1;num++) { p_func(p_num + num); } } void print(int *p_num, int size) { int num = 0; for (num = 0;num <= size - 1;num++) { printf("%d ", *(p_num + num)); } } int main() { int arr[] = {1, 2, 3, 4, 5}; print(arr, 5); printf("\n"); for_each(arr, 5, print_cb); printf("\n"); for_each(arr, 5, neg_cb); for_each(arr, 5, print_cb); printf("\n"); return 0; }
可以在程序运行的时候临时决定需要分配的存储区个数,这种分配存储区的方法叫动态内存分配,为了管理动态分配内存需要使用一组标准函数,为了使用这组标准函数需要包含stdlib.h头文件
malloc函数可以动态分配一组连续的字节,这个函数需要一个整数类型的参数表示希望分配的字节个数.这个函数的返回值表示分配好的第一个字节的地址,如果分配失败则返回值是NULL,函数把返回值记录在无类型指针存储区里,使用前必须首先转换成有类型指针
计算机不会主动回收动态分配存储区,程序不再使用动态分配存储区之后必须主动把这些存储区还给计算机.free函数可以用来把动态分配内存还给计算机(释放内存),一起分配的内存必须一起释放,这个函数需要第一个存储区的地址作为参数,如果用指针作为参数调用free函数则函数结束后指针成为野指针,必须恢复成空指针
调用函数可以使用被调用函数动态分配的存储区
/* * 动态分配内存演示 * */ #include <stdio.h> #include <stdlib.h> int main() { int num = 0; int *p_num = (int *)malloc(5 * sizeof(int)); /*if (p_num) { //使用动态分配存储区 free(p_num); p_num = NULL; }*/ if (!p_num) { return 0; } //使用动态分配内存 for (num = 0;num <= 4;num++) { *(p_num + num) = num; } for (num = 4;num >= 0;num--) { printf("%d ", *(p_num + num)); } printf("\n"); free(p_num); p_num = NULL; return 0; }
calloc函数也可以动态分配存储区,这个函数可以把动态分配存储区的内容都设置成0,为了使用这个函数也需要包含stdlib.h头文件.这个函数需要两个参数,第一个参数表示希望分配的存储区个数,第二个参数表示单个存储区的大小.这个函数的返回值也是第一个存储区的地址,这个函数也可能失败,如果失败则返回值是NULL
realloc函数可以调整动态分配存储区的个数,尽量少使用这个函数
文件里必须采用二进制方式记录数字,如果文件里的所有二进制数字都对应字符这种文件就叫做文本文件,文本文件以外的文件都叫做二进制文件
C语言里提供了两套操作文件的方法,一套方法只能操作文本文件,另外一套方法可以操作所有文件,第一套方法叫做文本方式,第二套方法叫做二进制方式
文件操作基本步骤
1.打开文件(fopen)
2.操作文件(fread/fwrite)
3.关闭文件(fclose)
fopen函数需要两个参数
1.要打开文件的路径
2.打开文件的方式(决定程序里可以对文件做什么操作)
打开方式有如下选择
"r" 只能察看文件内容不能修改,只能从文件头开始察看,如果文件不存在打开会失败
"r+" 比"r"多了修改文件内容的功能
"w" 只能修改文件内容不能察看,只能从文件头开始修改,如果文件还不存在就创建文件,如果文件已经存在就删除文件的所有内容,"w+" 比"w"多了察看文件内容的功能,"a" 只能修改不能察看,修改方式是在文件末尾追加新内容,如果文件不存在就创建文件,如果文件存在不会改变文件原有内容,"a+" 比"a"多了察看功能
/* * 文件操作代码框架 * */ #include <stdio.h> int main() { FILE *p_file = fopen("a.txt", "w"); /*if (p_file) { //操作文件 fclose(p_file); p_file = NULL; }*/ if (!p_file) { return 0; } //操作文件 fclose(p_file); p_file = NULL; return 0; }
"b"也是一种打开方式,这种打开方式可以和上面的任何一种方式混合使用,如果程序中希望以二进制方式操作文件就应该在打开方式里加上"b"
文件操作主要有两种方式
1.把内存里一组连续存储区的内容拷贝到文件里(写文件操作)
2.把文件里一组连续存储区的内容拷贝到内存里(读文件操作)
fread函数以二进制方式对文件进行读操作
fwrite函数以二进制方式对文件进行写操作
/* * fread函数演示 * */ #include <stdio.h> int main() { int arr[5] = {0}, size = 0, num = 0; FILE *p_file = fopen("a.bin", "rb"); if (p_file) { size = fread(arr, sizeof(int), 5, p_file); printf("size是%d\n", size); for (num = 0;num <= 4;num++) { printf("%d ", arr[num]); } printf("\n"); fclose(p_file); p_file = NULL; } return 0; }
/* * fwrite函数演示 * */ #include <stdio.h> int main() { int arr[] = {1, 2, 3, 4, 5}, size = 0; FILE *p_file = fopen("a.bin", "wb"); if (p_file) { size = fwrite(arr, sizeof(int), 5, p_file); printf("size是%d\n", size); fclose(p_file); p_file = NULL; } return 0; }
这两个函数都需要四个参数
1.内存里第一个存储区的地址
2.内存里单个存储区的大小
3.希望操作的存储区个数
4.文件指针
/* * 文件操作练习 * */ #include <stdio.h> int main() { int arr[5][5] = {0}, num = 0; int row = 0, col = 0; FILE *p_file = fopen("b.bin", "rb"); if (p_file) { for (num = 4;num >= 0;num--) { fread(arr[num], sizeof(int), 5, p_file); } fclose(p_file); p_file = NULL; } for (row = 0;row <= 4;row++) { for (col = 0;col <= 4;col++) { printf("%d", arr[row][col]); } printf("\n"); } return 0; }
它们的返回值表示实际操作的存储区个数
以下两个函数以文本方式操作文件
fprintf函数可以把数据按照指定的格式记录到文本文件里
fprintf函数的第一个参数是一个文件指针,后面的参数就是printf函数的参数
/* * fprintf函数演示 * */ #include <stdio.h> int main() { int arr[] = {4, 23, 987, 42, 18}, num = 0; FILE *p_file = fopen("abc.txt", "w"); if (p_file) { for (num = 0;num <= 4;num++) { //printf("%d ", arr[num]); fprintf(p_file, "%d ", arr[num]); } fclose(p_file); p_file = NULL; } return 0; }
fscanf函数可以从文本文件里获得数字并记录到存储区里,这个函数的第一个参数是文件指针,后面的参数就是scanf函数的参数
/* * fscanf函数演示 * */ #include <stdio.h> int main() { int num = 0, val = 0; FILE *p_file = fopen("abc.txt", "r"); if (p_file) { for (num = 0;num <= 4;num++) { //scanf("%d", &val); fscanf(p_file, "%d", &val); printf("%d ", val); } printf("\n"); fclose(p_file); p_file = NULL; } return 0; }
这两个函数执行速度比较慢,不适合用来操作大量数据
计算机里为每个文件保留了一个整数,这个整数表示下一次文件读写的开始位置,这个位置一定在两个相邻字节之间,这个整数就是文件头到这个位置之间包含的字节个数,这个整数叫做文件的位置指针,每当从文件中得到n个字节或向文件里写入n个字节后位置指针的数值都会加n
ftell函数可以获得当前位置指针的数值
rewind函数可以把位置指针的数值设置成0
/* * 位置指针演示 * */ #include <stdio.h> int main() { char ch = 0; FILE *p_file = fopen("def.txt", "rb"); if (p_file) { //rewind(p_file); fseek(p_file, 2, SEEK_SET); printf("%ld\n", ftell(p_file)); fread(&ch, sizeof(char), 1, p_file); printf("%c\n", ch); //rewind(p_file); fseek(p_file, 7, SEEK_CUR); printf("%ld\n", ftell(p_file)); fread(&ch, sizeof(char), 1, p_file); printf("%c\n", ch); //rewind(p_file); fseek(p_file, -3, SEEK_END); printf("%ld\n", ftell(p_file)); fread(&ch, sizeof(char), 1, p_file); printf("%c\n", ch); fclose(p_file); p_file = NULL; } return 0; }
fseek函数可以把位置指针设置到文件里的任何位置
fseek函数里需要设置基准位置并且指定目标位置到基准位置之间的距离
/* * 文件练习 * */ #include <stdio.h> typedef struct { int id; float salary; char name[10]; } person; int main() { int id = 0, size = 0; FILE *p_file = fopen("person.bin", "rb"); if (p_file) { while (1) { size = fread(&id, sizeof(int), 1, p_file); if (!size) { break; } printf("id是%d\n", id); fseek(p_file, sizeof(person) - sizeof(int), SEEK_CUR); } fclose(p_file); p_file = NULL; } return 0; }
SEEK_SET 0 把文件头作为基准位置
SEEK_CUR 1 把当前位置作为基准位置
SEEK_END 2 把文件尾作为基准位置
如果基准位置在目标位置前面则距离用正数表示,如果基准位置在目标位置后则距离用负数表示
距离的绝对值就是基准位置和目标位置之间包含的字节个数
cp命令可以实现文件拷贝功能,命令使用方法如下
cp 路径一 路径二
cp命令里使用-R选项可以实现目录的拷贝
fopen函数的返回值必须记录在文件指针里,程序里只能使用文件指针代表文件,fopen函数有可能失败,如果失败返回值是NULL
完成对文件的所有操作之后必须使用fclose函数关闭文件.使用fclose函数的时候应该把文件指针作为参数,关闭文件之后文件指针会成为野指针,必须恢复成空指针