动态分配内存:
前一天的笔记里记录了申请动态内存的一种方法,通过malloc(int);函数。
今天再介绍两种申请分配动态内存的方法。
1、calloc(int,int);
calloc(10,sizeof(int));
calloc函数也可以动态申请内存。上述例子中表示,申请10个int类型所占字节大小的内存空间,所以一共是需要40Byte。
除了参数不同,通过这函数申请的内存空间,会被全部初始化成0.
2、realloc();
这个函数的作用是对已经动态分配好的内存进行调整。
如果用这个函数去对一个动态分配好的10Byte内存进行扩充至20Byte,扩充的10Byte内存空间是连续在之前申请好的那块10Byte内存的后面。假设原先申请好的动态内存空间之后的空间已经被使用,那么这个函数会在内存里找一块连续的20Byte空间,然后把原先10Byte的内存中的数据拷贝过来,再销毁原先的10Byte空间。
这样的做法是比较消耗资源的,所以尽量不要使用这个函数。
文件
C语言中将文件看作两种,一种是文本文件,一种是二进制文件。
所以对文本的操作也分为两种:
1、第一种是通过二进制方式来读写文件,由于文本文件也可以看作是二进制的文件,所以这种方法,也可以对二进制文件操作。
2、第二种是通过文本方式来读写文件,只能读写文本文件。
操作文件的函数:
fopen();
用于打开一个文件。有两个参数,第一个参数表示了文件的位置,第二个参数表示了文件的打开方式。
该函数调用结束后,会返回一个文件指针类型(FILE*)的返回值。
文件位置的表示方式可以采用绝对路径,也可以采用相对路径。
文件打开方式分为以下几种:
“w”:只能对文件进行写入,不能读取。如果路径上文件不存在,将会创建一个该路径上的文件。如果路径上的文件存在,它会清空文件内原来的内容。
“w+”:比上述方式多了可读取的操作。
“r”:只能对文件读取,不能写入。如果路径上的文件不存在,将会返回一个NULL。如果存在将会从文件的开头开始读取。
“r+”:比上述方式,多了可写入的操作。
“a”:只能对文件写入。如果路径上的文件不存在,则会创建一个文件。如果存在,也不会清空它原先的内容,而是会在原先的内容后继续追加写入。
“a+”:比上述方式,多了读取的操作。
“b”:二进制形式。这个选项可以和上述任意一个选项一起使用,表示用二进制的方式打开文件。如果不加,就是以文本形式打开文件。
fclose
fclose(FILE);
用fopen函数打开一个文件,对文件的操作结束之后一定要关闭文件。因为打开文件的时候fopen的内部实现会为这次操作申请动态内存,如果不用fclose关闭的话,会造成内存泄漏。
该函数只有一个参数,就是fopen函数返回的文件指针。
fwrite
fwrite(,int,int,FILE*)
fwrite(num,sizeof(int),10,p_file);
对文件执行写入操作的函数。
这个函数有四个参数:
第一个参数,是一个内存地址,表示写入文件的内容在内存空间的首字节地址。
第二个参数,是一个整型参数,表示这次写入文件的单位。
第三个参数,是一个整型参数,表示要连续写入多少个单位的内容
第四个参数,是文件指针,表示写入哪个文件。
fread
fread(num,sizeof(int),10,p_file);
对文件执行读取操作的函数。
函数也有4个参数,很fwrite一致
下面通过一个例子来演示上述函数,代码如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct{
int ID;
char name[20];
float gold;
}People;
int main(int argc,char** argv){
People peo = {0};
People one = {0};
int size = 0;
FILE* p_wfile = fopen("People.txt","ab");
FILE* p_rfile = fopen("People.txt","rb");
if(p_wfile){
int flag = 1;
while(1){
printf("please enter a ID:\n");
scanf("%d",&(peo.ID));
scanf("%*[^\n]");
scanf("%*c");
printf("please enter a name:\n");
fgets(peo.name,20,stdin);
printf("please enter a gold:\n");
scanf("%g",&(peo.gold));
fwrite(&peo,sizeof(peo),1,p_wfile);
printf("do you enter again ? yes = 1;no = 0;\n");
scanf("%d",&flag);
if(!flag)break;
}
fclose(p_wfile);
p_wfile = NULL;
}
if(p_rfile){
while(1){
size = fread(&one,sizeof(one),1,p_rfile);
if(!size) break;
printf("%d\n",one.ID);
printf("%s",one.name);
printf("%g\n",one.gold);
}
fclose(p_rfile);
p_rfile = NULL;
}
return 0;
}
上述代码,创建了一个结构体,向文件写入一个结构体类型,然后再读取出来。用的都是二进制方式来操作的。
在二进制方式下读写文件,是要按照读写内容本身的类型来做的,因为每个类型的字节数不同,一旦写入和读取用的类型不同时,读取出来的文件是不能用的。
下面再介绍两个函数,是用于文本文件读写的。
fprintf&fscanf
fprintf(FILE*,”占位符”,);
这个函数和printf函数是很像的,只比它多一个参数,用于指明把内容写入到哪个文件。
fscanf(FILE*,”占位符”,);
这个函数和scanf函数很像,多余的参数是用来表示从哪个文件里读取数据的。
下面用一段代码演示一下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc,char** argv){
int num[] = {123,4567,891011,12131415};
int number = 0;
FILE* p_file = fopen("wenben.txt","w");
FILE* p_rfile = fopen("wenben.txt","r");
if(p_file){
for(int i = 0;i < 4;i++)
fprintf(p_file,"%d ",num[i]);
}
fclose(p_file);
p_file = NULL;
if(p_rfile){
for(int i = 0;i < 4;i++){
fscanf(p_rfile,"%d ",&number);
printf("%d\n",number);
}
}
return 0;
}
将一个整型数组通过文本写入的方式写入到文本文件。
再用文本的方式读取出来。
位置指针
当打开一个文件的时候,计算机会为它用一个整数类型的值来记录下一次读写开始的位置。叫做位置指针。
位置指针,一定是在两个字节中间。
每当向文件获取N个字节或者写入N个字节的时候,位置指针都会向后移动N。
ftell&rewind&fseek
ftell(FILE*);
可以通过ftell函数来获取文件当前的位置指针数值。
rewind(FILE*);
可以通过rewind函数,将位置指针设置到文件的开头。
fseek(FILE*,int,SEEK_SET);
可以通过fseek函数,把位置指针设置到文件的任意位置。
在调用函数的时候需要提供一个基准位置和一个基准位置与目标位置的偏移量。
规定了以下三种基准地址:
SEEK_SET 0 将文件开头设置为基准地址
SEEK_CUR 1 将位置指针的当前位置设置成基准地址
SKKE_END 2 将文件的结尾设置为基准地址
如果目标地址在基准地址的前方,那么偏移量就是一个负数
如果目标地址在基准地址的后方,那么偏移量就是一个非负数
用以下代码验证:
test.txt
abcdefghijklmn
------------------------
#include<stdio.h>
int main(int argc,char** argv){
char num = 0;
FILE* p_file = fopen("test.txt","rb");
if(p_file){
ftell(p_file);
fread(&num,sizeof(char),1,p_file);
printf("%c\n",num);
ftell(p_file);
fread(&num,sizeof(char),1,p_file);
printf("%c\n",num);
rewind(p_file);
ftell(p_file);
fread(&num,sizeof(char),1,p_file);
printf("%c\n",num);
fseek(p_file,3,SEEK_SET);
ftell(p_file);
fread(&num,sizeof(char),1,p_file);
printf("%c\n",num);
fseek(p_file,-3,SEEK_END);
ftell(p_file);
fread(&num,sizeof(char),1,p_file);
printf("%c\n",num);
fseek(p_file,-2,SEEK_CUR);
ftell(p_file);
fread(&num,sizeof(char),1,p_file);
printf("%c\n",num);
fclose(p_file);
p_file = NULL;
}
------------------------
a
b
a
d
m
l
在测试文件中放置了一串英文字符,通过用函数调整当前位置指针的位置,会打印出预期中的字符。