精华内容
下载资源
问答
  • 最后的结果显示在屏幕上。 输入格式: 输入首先在第一行给出正整数 N(1<N≤10​3​​), S​1​​ 中数字的个数。 第二行给出 N 个绝对值超过 100 的整数;第三行...
  • 结果输出正常: ``` ==26627== Memcheck, a memory error detector ==26627== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==26627== Using Valgrind-3.16.1 and LibVEX; rerun with -h...
  • 进去了,结果编译运行什么也没有显示。但编译通过没问题,知道代码哪里 出来问题,想请教各位大神们帮忙看看代码,看看哪里有什么问题。时间有点 急!!在此谢谢大家啦!!!! ```#include #include #...
  • 为什么我这个程序,计算正确与否都只显示0或1,不显示right wrong #include int Addtest(int a,int b) { int answer; printf("%d+%d=",a,b); scanf("%d",&answer); if(a+b==answer) return 1; ...
  • 数据中的名称全是英文,看了好半天才明白是怎么一回事想到定义数组发现定了那么大,从网上学了malloc可是完全知道引入文件后怎么将其导入数组内,试着将网上的程序拼接结果不行。////这时得到了堆空间这个名词,...
  • C语言编程要点

    2017-09-18 00:10:37
    17.1. 为什么直到程序结束时才看到屏幕输出? 220 17.2. 怎样在屏幕上定位光标? 220 17.3. 向屏幕上写数据的最简单的方法是什么? 221 17.4. 向屏幕上写文本的最快的方法是什么? 221 17.5. 怎样防止用户用Ctrl+Break键...
  • C语言,前台传过来一个图片base64编码后的字符串,我解码后把解码后的图片存到了一个char*类型的动态空间,然后上传到数据库的blob字段,结果上传成功后,相应的blob字段只显示两个问号。这是为什么?我在vs里试了试...
  • 你必须知道的495个C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    1.2 为什么不精确定义标准类型的大小? 1.3 因为C语言没有精确定义类型的大小,所以我一般都用typedef定义int16和int32。然后根据实际的机器环境把它们定义为int、short、long等类型。这样看来,所有的问题都解决...
  • c语言循环练习题

    千次阅读 2018-03-22 17:01:12
    //结果为0,因为是int类型的变量,所以不显示小数点后面的数字。quack%=3;//结果为2,如果除数比被除数小,则余数除数本身。二、value是一个int类型的值,循环出产生什么输出for(value = 36;value &gt;0;value...

    一、输出变量的值。

    int quack = 2;

    quack -=6;//结果为-4,即使加上无符号的定义,结果也为负数。

    quack /=8;//结果为0,因为是int类型的变量,所以不显示小数点后面的数字。

    quack%=3;//结果为2,如果除数比被除数小,则余数为除数本身。


    二、value是一个int类型的值,循环出产生什么输出

    for(value = 36;value >0;value /2)

    {

      printf("%3d",value);//输出的结果为36,18.9.4.2.1,因为是int类型,只读取正整数,小数点后的数字被砍掉了,所以除到0.                                      //  几的时候,默认为0,所以结束循环。

    }

    如果类型为double会出现什么错误? //会一直除到double的最小值,然后溢出为负数,后结束循环。

    三、判断scanf()输入是否正确。

    int x;

    scanf_s("%d", &x);
    while (scanf_s("%d", &x)!=EOF)
    {
    printf("输入出错");
    break;

    }

    1.scanf()函数有返回值且为int型。scanf返回值表示成功读入的数据个数。

    2.scanf()函数返回的值为:正确按指定格式输入变量的个数;也即能正确接收到值的变量个数。

    例如,scanf("%d%d", &a, &b); 如下为返回值的四种情况

    (1) 如果a和b都被成功读入,那么scanf的返回值就是2

    (2) 如果只有a被成功读入,返回值为1

    (3)如果a和b都未被成功读入,返回值为0(即scanf函数遇到非法输入时,返回值为0)

    (4)如果遇到错误或遇到文件结束符(end of file,EOF,控制台下用Ctrl+Z输入)则返回EOF(stdio.h中定义符号常量:#define EOF -1)。

    由此例可见因此可利用scanf函数的返回值判断数据是否正确读入。

    四、

    void Hi()
    {
    int i;
    char ch;
    for (i = 0, ch = 'A'; i < 4; i++, ch += 2 * i)
    {
    printf("%c\n", ch);
    }


    }

    先算i++,再算ch+=2*i;这里ch加的是ASCII码值。




    展开全文
  • C语言-文件操作

    2021-03-22 15:23:45
    什么是文件 磁盘上的文件是文件。 但是在程序设计中,我们一般谈的...在以前各章所处理数据的输入输出都是以终端对象的,即从终端的键盘输入数据,运行结果显示到显示器上。 其实有时候我们会把信息输出到磁盘上,当

    什么是文件

    磁盘上的文件是文件。

    但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件

    程序文件

    包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

    数据文件

    文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

    本章讨论的是数据文件。

    在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。

    其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件。

    文件名

    一个文件要有一个唯一的文件标识,以便用户识别和引用。

    文件名包含3部分:文件路径+文件名主干+文件后缀

    例如:c:\code\test.txt
    为了方便起见,文件标识常被称为文件名。

    文件类型

    根据数据的组织形式,数据文件被称为文本文件或者二进制文件

    数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件

    一个数据在内存中是怎么存储的呢?

    字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。

    如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2017测试)。

    #include <stdio.h>
    int main()
    {
    	int a = 10000;
    	FILE* pf = fopen("test.txt", "wb");
    	fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    文件缓冲区

    ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。

    在这里插入图片描述

    文件指针

    缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。

    每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.

    struct _iobuf {
            char *_ptr;
            int   _cnt;
            char *_base;
            int   _flag;
            int   _file;
            int   _charbuf;
            int   _bufsiz;
            char *_tmpfname;
           };
    typedef struct _iobuf FILE;
    

    不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。

    每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。

    一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
    下面我们可以创建一个FILE*的指针变量:

    FILE* pf;//文件指针变量
    

    定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。
    比如:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-boM01Dmw-1616397800074)(…/img/14/文件信息区.png)]

    文件的打开和关闭

    文件在读写之前应该先打开文件,在使用结束之后应该关闭文件

    在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。

    ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。

    FILE * fopen ( const char * filename, const char * mode );
    int fclose ( FILE * stream );
    

    打开方式如下:

    使用方式 含义 如果指定文件不存在
    "r”(只读) 为了输入数据,打开一个已经存在的文本文件 出错
    "w”(只写) 为了输出数据,打开一个文本文件 建立一个新的文件
    "a”(追加) 向文本文件尾添加数据 出错
    "rb”(只读) 为了输入数据,打开一个二进制文件 出错
    "wb”(只写) 为了输出数据,打开一个二进制文件 建立一个新的文件
    "ab”(追加) 向一个二进制文件尾添加数据 出错
    "r+”(读写) 为了读和写,打开一个文本文件 出错
    "w+”(读写) 为了读和写,建议一个新的文件 建立一个新的文件
    "a+”(读写) 打开一个文件,在文件尾进行读写 建立一个新的文件
    "rb+”(读写) 为了读和写打开一个二进制文件 出错
    "wb+”(读写) 为了读和写,新建一个新的二进制文件 建立一个新的文件
    "ab+”(读写) 打开一个二进制文件,在文件尾进行读和写 建立一个新的文件
    #include <errno.h>
    #include <string.h>
    
    int main()
    {
    	//打开文件test.txt
    	//相对路径
    	//.. 表示上一级路径
    	//.  表示当前路径
    	//fopen("../../test.txt", "r")
    	//fopen("test.txt", "r");
    	
    	//绝对路径的写法
    	//fopen("D:\\A-yan\\C\Project1\\Project1\\test.txt", "r");
    
    	FILE* pf = fopen("test.txt", "w");
    	if(pf == NULL)
    	{
    		printf("%s\n", strerror(errno));
    		return 0;
    	}
    	//打开成功
    	//读文件
    
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    
    	return 0;
    }
    

    在这里插入图片描述

    文件的顺序读写

    功能 函数名 适用于
    字符输入函数 fgetc 所有输入流
    字符输出函数 fputc 所有输出流
    文本行输入函数 fgets 所有输入流
    文本行输出函数 fputs 所有输出流
    格式化输入函数 fscanf 所有输入流
    格式化输出函数 fprintf 所有输出流
    二进制输入 fread 文件
    二进制输出 fwrite 文件

    对比一组函数

    scanf/fscanf/sscanf
    printf/fprintf/sprintf
    
    scanf/printf 是针对标准输入流/标准输出流 格式化输入/输出语句
    fscanf/fprintf 是针对所有输入流/所有输出流 格式化输入/输出语句
    sscanf/sprintf 是从字符串中读取格式化数据/把格式化数据输出成(存储成)字符串
    

    fputc

    FILE* pfWrite = fopen("test.txt", "w");
    if(pfWrite == NULL)
    {
      printf("%s\n", strerror(errno));
      return 0;
    }
    //写文件
    fputc('H', pfWrite);
    fputc('I', pfWrite);
    fputc('!', pfWrite);
    //关闭文件
    fclose(pfWrite);
    pfWrite = NULL;
    

    fgetc

    FILE* pfRead = fopen("test.txt", "r");
    if(pfRead == NULL)
    {
      printf("%s\n", strerror(errno));
      return 0;
    }
    //读文件
    printf("%c", fgetc(pfRead));//b
    printf("%c", fgetc(pfRead));//i
    printf("%c", fgetc(pfRead));//t
    
    //关闭文件
    fclose(pfRead);
    pfRead = NULL;
    

    注:

    从键盘输入、输出到屏幕. 键盘&屏幕都是外部设备

    键盘-标准输入设备- stdin
    屏幕-标准输出设备- stdout
    

    是一个程序默认打开的两个流设备

    stdin FILE*
    stdout FILE*
    stderr FILE*
    

    fgets

    int ch = fgetc(stdin);
    fputc(ch, stdout);
    
    char buf[1024] = { 0 };
    
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
      return 0;
    }
    //读文件
    fgets(buf, 1024, pf);
    puts(buf);//自动换行 ==printf("%s\n", buf);
    
    fclose(pf);
    pf = NULL;
    

    fputs

    char buf[1024] = { 0 };
    FILE* pf = fopen("test.txt", "w");
    if (pf == NULL)
    {
      return 0;
    }
    //写文件
    fputs("hello\n", pf);
    fputs("world\n", pf);
    
    
    fclose(pf);
    pf = NULL;
    

    fscanf

    struct S
    {
    	int n;
    	float score;
    	char arr[10];
    };
    
    int main()
    {
    	struct S s = {0};
    
    	FILE* pf = fopen("test.txt", "r");
    	if (pf == NULL)
    	{
    		return 0;
    	}
    	//格式化的输入数据
    	fscanf(pf, "%d %f %s", &(s.n), &(s.score), s.arr);
    	printf("%d %f %s\n", s.n, s.score, s.arr);
    
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    fprintf

    struct S
    {
    	int n;
    	float score;
    	char arr[10];
    };
    
    int main()
    {
    	struct S s = { 100, 3.14f, "bit" };
    	FILE* pf = fopen("test.txt", "w");
    	if (pf == NULL)
    	{
    		return 0;
    	}
    	//格式化的形式写文件
    	fprintf(pf, "%d %f %s", s.n, s.score, s.arr);
    
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    sscanfsprintf

    struct S
    {
    	int n;
    	float score;
    	char arr[10];
    };
    
    
    int main()
    {
    	struct S s = { 100, 3.14f, "abcdef" };
    	struct S tmp = {0};
    	char buf[1024] = { 0 };
    	//把格式化的数据转换成字符串存储到buf
    	sprintf(buf, "%d %f %s", s.n, s.score, s.arr);
    	//printf("%s\n", buf);
    	//从buf中读取格式化的数据到tmp中
    	sscanf(buf, "%d %f %s", &(tmp.n), &(tmp.score), tmp.arr);
    
    	printf("%d %f %s\n", tmp.n, tmp.score, tmp.arr);
    
    	return 0;
    }
    

    fwrite

    struct S
    {
    	char name[20];
    	int age;
    	double score;
    };
    
    int main()
    {
    	struct S s = { "张三", 20, 55.6 };
    
    	FILE* pf = fopen("test.txt", "wb");
    	if (pf == NULL)
    	{
    		return 0;
    	}
    	//二进制的形式写文件
    	fwrite(&s, sizeof(struct S), 1, pf);
    
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    fread

    struct S
    {
    	char name[20];
    	int age;
    	double score;
    };
    
    int main()
    {
    	//struct S s = { "张三", 20, 55.6 };
    	struct S tmp = { 0 };
    
    	FILE* pf = fopen("test.txt", "rb");
    	if (pf == NULL)
    	{
    		return 0;
    	}
    	//二进制的形式都文件
    	fread(&tmp, sizeof(struct S), 1, pf);
    	printf("%s %d %lf\n", tmp.name, tmp.age, tmp.score);
    
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    文件的随机读写

    fseek

    根据文件指针的位置和偏移量来定位文件指针。

    int fseek ( FILE * stream, long int offset, int origin ); 
    //offset 偏移量
    // origin 文件指针当前位置
    
    Constant Reference position
    SEEK_SET 文件开头
    SEEK_CUR 文件指点的当前位置
    SEEK_END 文件结束
    FILE* pf = fopen("test.txt", "r");//abcdefg
    if (pf == NULL)
    {
      return 0;
    }
    //1.定位文件指针
    fseek(pf, -2, SEEK_END);//f
    //2.读取文件
    int ch = fgetc(pf);
    printf("%c\n", ch);
    
    fclose(pf);
    pf = NULL;
    

    ftell

    返回文件指针相对于起始位置的偏移量

    long int ftell ( FILE * stream );
    
    FILE* pf = fopen("test.txt", "r");//abcdef
    if (pf == NULL)
    {
      return 0;
    }
    //1.定位文件指针
    //fseek(pf, -2, SEEK_END);
    int ch = fgetc(pf);//
    printf("%c\n", ch);//a
    int pos = ftell(pf);//
    printf("%d\n", pos);//1
    fclose(pf);
    pf = NULL;
    

    rewind

    让文件指针的位置回到文件的起始位置

    FILE* pf = fopen("test.txt", "r");//abcdefg
    if (pf == NULL)
    {
      return 0;
    }
    //1.定位文件指针
    //fseek(pf, -2, SEEK_END);
    int ch = fgetc(pf);
    printf("%c\n", ch);//a
    rewind(pf);
    ch = fgetc(pf);
    printf("%c\n", ch);//a
    
    fclose(pf);
    pf = NULL;
    

    文件结束的判定

    被错误使用的 feof

    //EOF
    //feof();//EOF - end of file - 文件结束标志
    FILE* pf = fopen("test.txt", "r");//空文件
    if (pf == NULL)
      return 0;
    int ch = fgetc(pf);
    printf("%d\n", ch);//-1
    
    fclose(pf);
    pf = NULL;
    

    牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
    而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束

    1. 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或者NULL(fgets)

      例如:

      fgetc判断是否为EOF.
      fgets判断返回值是否为NULL.
      
    2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。

      例如:

      fread判断返回值是否小于实际要读的个数。
      

    正确的使用

    文本文件的例子:

    #include <stdio.h>
    #include <stdlib.h>
    int main(void)
    {
      //strerror - 把错误码对应的错误信息的字符串地址返回
        int c;
         // 注意:int,非char,要求处理EOF
        FILE* fp = fopen("test.txt", "r");
        if(!fp) {
            perror("File opening failed");
            return EXIT_FAILURE;
       }
     //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
        while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
       { 
           putchar(c);
       }
     //判断是什么原因结束的
        if (ferror(fp))
            puts("I/O error when reading");
        else if (feof(fp))
            puts("End of file reached successfully");
        fclose(fp);
    }
    

    二进制文件的例子:

    #include <stdio.h>
    enum
    {
        SIZE = 5
    };
    int main(void)
    {
        double a[SIZE] = {1.0, 2.0, 3.0, 4.0, 5.0};
        double b = 0.0;
        size_t ret_code = 0;
        FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
        fwrite(a, sizeof(*a), SIZE, fp);    // 写 double 的数组
        fclose(fp);
        fp = fopen("test.bin", "rb");
        // 读 double 的数组
        while ((ret_code = fread(&b, sizeof(double), 1, fp)) >= 1)
        {
            printf("%lf\n", b);
        }
        if (feof(fp))
            printf("Error reading test.bin: unexpected end of file\n");
        else if (ferror(fp))
        {
            perror("Error reading test.bin");
        }
        fclose(fp);
        fp = NULL;
    }
    

    参考链接:https://zh.cppreference.com/w/c

    展开全文
  • C语言】-文件操作

    2021-01-30 12:42:38
    什么是文件 磁盘上的文件就是文件。 但是在程序设计中,我们一般谈的文件有两种:程序文件、...我们通常C语言所处理数据的输入输出都是以终端对象的,即从终端的键盘输入数据,运行结果显示到显示器上。 其实有时候

    什么是文件

    磁盘上的文件就是文件。

    但是在程序设计中,我们一般谈的文件有两种:程序文件数据文件

    1.程序文件

    包括源程序文件(后缀为.c),目标文件(Windows环境后缀为.obj),可执行程序(Windows环境后缀为.exe)。

    2.数据文件

    文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

    本篇讨论的是全是数据文件。

    我们通常C语言所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。

    其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上的文件。

    文件名

    一个文件要有一个唯一的文件标识,以便用户识别和引用。

    文件名包括3部分:文件路径+文件名主干+文件后缀

    例如:

    c:\code\text.txt

    • c:\code\为文件路径
    • text为文件名主干
    • .txt为文件后缀

    为了方便起见,文件标识常被称为文件名。

    文件类型

    根据数据的组织形式,数据文件被称为文本文件或者二进制文件

    简单的理解就是文本文件可以用记事本打开查看,而二进制文件不能用记事本打开查看,如果打开查看看到的将是一堆乱码。 这是因为记事本就是以文本的形式打开文件的。

    数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。

    如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。

    一个数据在内存中是怎么存储的呢?

    字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。

    如有整数10000,如果以ASCII码的形式输出到磁盘,则在磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2013测试)。

    代码如下:

    #include <stdio.h>
    
    int main()
    {
    	int a = 10000;
    	FILE* pf = fopen("test.txt", "wb");
    	fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    这段代码我们将10000以二进制的形式存储到文件text.txt中。前面我刚提到过,二进制文件是不能用记事本打开来看的,下面我们用记事本将这个文件打开看看会看到什么。
    在这里插入图片描述

    可以看到这个文件打开后看到的是一个乱码,所以说二进制文件是不能用记事本来查看的的。

    那么难道我们就真的不能看看这个文件的二进制信息吗?当然是可以的,我们的编译器就可以很好的帮我们解决这个问题。

    第一步:打开源文件添加现有项
    在这里插入图片描述
    第二步:选中我们输出到磁盘的文件test.txt,点击添加到我们的项目中去。
    在这里插入图片描述
    第三步:点击打开方式,选中以二进制编辑器的形式打开,就可以打开我们的二进制文件了。
    在这里插入图片描述
    如下图:
    在这里插入图片描述
    可以看到10000的二进制形式被我们看见到了,只不过这里是以16进制的形式再根据小端字节序打印的。前面的一串0可以假想成一个地址,这里不必深究。

    下面我们看看十进制10000在内存中存储形式:
    在这里插入图片描述

    文件缓冲区

    ANSIC 标准采用缓冲文件系统处理的数据文件。

    所谓缓冲文件系统是指:系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。

    从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。

    如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。

    缓冲区的大小根据C编译系统决定的。
    在这里插入图片描述

    文件指针

    缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。

    每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及 文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE(可以转到定义来查看)。

    例如,VS2013编译环境提供的<stdio.h>头文件中有以下的文件类型申明:

    struct _iobuf {
    	char *_ptr;
    	int   _cnt;
    	char *_base;
    	int   _flag;
    	int   _file;
    	int   _charbuf;
    	int   _bufsiz;
    	char *_tmpfname;
    };
    typedef struct _iobuf FILE;
    

    不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异,所以这个不用深究。

    每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。

    一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便

    下面我们可以创建一个FILE*的指针变量:

    FILE* pf;//文件指针变量
    

    定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。

    比如:
    在这里插入图片描述

    文件的打开和关闭

    文件在读写之前应该先打开文件,在使用结束之后应该关闭文件

    编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向改文件,也相当于建立了指针和文件的关系。

    ANSIC规定使用fopen函数来打开文件,fclose来关闭文件。

    1.fopen

    FILE * fopen ( const char * filename, const char * mode );
    
    • filename 指的是文件名。
    • mode 指的是打开方式。
    • FILE *函数的返回值是一个文件指针,是指是一个结构体,存放文件信息。

    例:

    pfile = fopen("myfile.txt", 'w');
    

    打开文件进行写的操作

    2.fclose

    int fclose ( FILE * stream );
    
    • stream:打开文件时返回的文件指针。

    例如:

    fclose(pfile);
    

    将打开的文件关闭。

    3.打开方式

    在这里插入图片描述
    注意:这里的"w"是指将该文件的内容清空,然后再进行写操作,如果项目中没有这个文件,这个函数就会自动在这个项目中创建一个文件(这就是建立一个新文件的含义)。

    文件的读写

    在这里插入图片描述

    1.fputc(字符输出函数)

    函数定义

    在这里插入图片描述

    将一个字符写到一个流里去。

    “流”的概念

    这里就引出了一个流的概念,下面来解释一下。

    电脑上有很多的设备,鼠标,键盘、屏幕,有输入设备有输出设备。比如说我想把我们的相关数据进行输出,可以显示到屏幕上,叫做把数据输出到屏幕上;比如电脑上有硬盘,我把数据输出到硬盘上去,这叫写到硬盘上去,比如电脑上还插了一个U盘,我们还可以把数据写到U盘上去;比如这里放了一个光驱,我们可以把数据写到光驱上去。大家想象一下,这个时候如果我们要通过一定的手段把我们的数据写到外部设备上去,比如U盘,硬盘,屏幕,包括光驱等,这些设备的读写方式一样不一样?肯定不一样,设备不一样,读写方式肯定也不一样。但是C语言操作的话,如果我们给每一种设备都给一个读写方式的话,这个C语言写起来也太复杂了,所以后来做了一件什么事情呢?就是这样,抽象出来一个流的概念,流是一个中间层,我们程序员在写数据的时候统统把它放到流里面去,就像水流一样,把流想象成一个水渠,我们可以从里面舀东西,也可以往里面倒东西,我要输出数据的时候就往流里面放,我要读数据的时候就从流里面读。流自己知道我要怎么往硬盘放东西,怎么往屏幕放东西,我把他写到光驱上又是怎么写数据的。如果C语言把流以下的操作方式处理好,程序员写代码就只关心怎么把数据放到流里面去,这样程序员写代码就会变得更加简单,所以我们在写C语言代码的时候操作的就是流的概念。流是一个高度抽象的概念,是抽象出来的理解方式,需要自己慢慢地感受。

    下面介绍三种标准流:

    • 标准输入流:stdin
    • 标准输出流:stdout
    • 标准错误流:stderr

    函数声明

    int fputc( int c, FILE *stream );
    
    • c:为输入字符的ASCII码值
    • stream :为一个文件流
    • 返回值:返回写入的字符,如果返回EOF表示输出错误

    举例

    使用fputc函数,将一组字符写到一个文件中去:

    #include <stdio.h>
    
    int main()
    {
    	//打开文件
    	FILE* pf = fopen("test.txt", "w");	
    	if (pf == NULL)
    	{
    		perror("fopen");
    		return 1;
    	}
    	//写文件
    	fputc('a', pf);
    	fputc('b', pf);
    	fputc('c', pf);
    	fputc('d', pf);
    	fputc('e', pf);
     
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    写之前首先要打开文件进行写的操作,然后调fputc函数来给文件中写数据,最后再将文件关闭,运行结果:
    在这里插入图片描述
    打开text.c文件可以看到,我们将五个字符abcde成功输入到了该文件中去了。

    刚才我们提到了标准输出流,标准输出流就是把数据输出到屏幕上去,平常我们在屏幕上打印数据用的都是printf函数,这次我们用fputc函数操作标准输出流来尝试一下。

    #include <stdio.h>
    
    int main()
    {
    	fputc('q', stdout);
    	return 0;
    }
    

    运行结果:
    在这里插入图片描述
    可以看到我们通过fputc函数也可以将字符打印到屏幕上。

    2.fgetc(字符输入函数)

    函数定义

    从流中读取一个字符

    函数声明

    int fgetc( FILE *stream );
    
    • stream :所要读取的文件流
    • 返回值:返回读取为int的字符或返回EOF以指示错误或文件结束。

    这里可能会有人疑惑,为什么返回的既然是字符,那么为什么我们不用字符型参数来接收,而要用整型的参数来接收。是这样的,上面函数的返回值我们也看到了,如果获取错误或者文件结束会返回EOF。而这里的EOF大家可能不知道它是什么,转到定义我们来看看:
    在这里插入图片描述
    可以看到EOF的值实际上是-1,所以如果我们用字符型来接收一个整型的话,就会有精度的缺失,而得不到我们想要的结果。

    举例

    使用fgets函数,从一个文件中读取一串字符。

    #include <stdio.h>
    
    int main()
    {
    	//打开文件
    	FILE* pf = fopen("test.txt", "r");
    	if (pf == NULL)
    	{
    		perror("fopen");
    		return 1;
    	}
    	//读文件
    	int ch = fgetc(pf);
    	printf("%c\n", ch);
    	ch = fgetc(pf);
    	printf("%c\n", ch);
    	ch = fgetc(pf);
    	printf("%c\n", ch);
    	ch = fgetc(pf);
    	printf("%c\n", ch);
    	ch = fgetc(pf);
    	printf("%c\n", ch);
    
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    这里我们使用fgetc函数来从文件text.txt中读取五个字符。首先我们先手动在文件中输入一串字符"hello",然后用fgetc函数读取字符,所读取的字符用一个变量ch来接收,每读取一个字符就将它打印到屏幕上。

    手动输入:
    在这里插入图片描述
    运行结果:
    在这里插入图片描述
    可以看到我们读取五次成功读取了这个文件中的5个字符。

    通过这个例子大家可以感受一下,fgetc函数在读取完一次字符之后维护该函数读取字符的指针会向后跳一位,但是这个指针可不是文件指针,应该函数内部定义的用来读取字符的指针。

    综合fgetc和fputc

    学会这两个函数之后,再举一个例子综合运用这两个函数,我们来将一个文件里的内容拷贝到另一个文件中去

    具体的做法是这样的,先用fgetc函数从text1文件中逐个读取字符串,将读取的字符串存放到一个变量中去。然后再将这个字符利用fputc函数拷贝到text2文件中去。

    前面我们说过,fgetc读取完一个字符之后,维护文件的指针就会自动向后跳1,而当全部读取结束之后,会返回EOF,所以这里我们可以设置一个循环来实现两个文件之间逐个字符的转换。

    代码:

    #include <stdio.h>
    
    int main()
    {
    	FILE* pfRead = fopen("test1.txt", "r");
    	if (pfRead == NULL)
    	{
    		perror("open file for reading");
    		return 1;
    	}
    	FILE* pfWrite = fopen("test2.txt", "w");
    	if (pfWrite == NULL)
    	{
    		perror("open file for writting");
    		fclose(pfRead);
    		pfRead = NULL;
    		return -1;
    	}
    	//拷贝
    	int ch = 0;
    	while ((ch = fgetc(pfRead)) != EOF)
    	{
    		fputc(ch, pfWrite);
    	}
    
    	//关闭文件
    	fclose(pfRead);
    	pfRead = NULL;
    	fclose(pfWrite);
    	pfWrite = NULL;
    	return 0;
    }
    

    这段代码的目的是把text1中的内容拷贝到text2中去,我们先手动的在test1文件中输入一串代码,然后建立text2文件,可以看到这个时候text2文件的大小还是0,说明里面没有内容。

    在这里插入图片描述
    下面我们再来看看程序运行后的结果:
    在这里插入图片描述
    可以看到成功将text1中的内容拷贝到了text2中去了。

    3.fputs(文本行输出函数)

    函数定义

    将字符串写入流

    函数声明

    int fputs( const char *string, FILE *stream );
    
    • string:要输入的字符串。
    • stream :指向文件结构的指针
    • 返回值:如果成功,这些函数中的每一个都返回一个非负值。出错时,fputs返回EOF

    举例

    将两个字符串输出到一个文件中去。

    #include <stdio.h>
    
    int main()
    {
    	FILE* pf = fopen("test.txt", "w");
    	if (pf == NULL)
    	{
    		perror("open file for writting");
    		return 1;
    	}
    	//写数据
    	fputs("hello bit\n", pf);
    	fputs("haha\n", pf);
    
    	fclose(pf);
    	pf = NULL;
    
    	return 0;
    }
    

    这段代码我们将两个字符串"hello bit\n"和"haha\n"输出到文件test.txt中,运行程序后查看文件的内容。
    在这里插入图片描述
    可以看到成功的将这两个字符串输出到了文件中。

    4.fgets(文本行输入函数)

    函数定义

    从流中获取字符串。

    函数声明

    char *fgets( char *string, int n, FILE *stream );
    
    • string:数据的存储位置
    • n:要读取的最大字符数
    • stream :指向文件结构的指针
    • 返回值:每个函数都返回字符串。返回NULL以指示错误或文件结束条件。使用feof或feror来确定是否发生了错误。

    举例

    从文件中读取字符串。

    #include <stdio.h>
    
    int main()
    {
    	char input[20] = { 0 };
    	FILE* pf = fopen("test.txt", "r");
    	if (pf == NULL)
    	{
    		perror("opne file for reading");
    		return 1;
    	}
    	//读数据
    	fgets(input, 20, pf);
    	printf("%s", input);
    
    	fgets(input, 20, pf);
    	printf("%s", input);
    	fclose(pf);
    	pf = NULL;
    
    	return 0;
    }
    

    上一段代码中我们将两个字符串输入到了test.txt文件中,接下来我们来把这两个字符串从该文件中读取出来,存放到一个数组中去,再打印到屏幕上。运行结果:
    在这里插入图片描述
    可以看到这个函数在读取字符串的时候一次读取一行的信息,然后维护的指针会跳到下一行。

    5.fprintf(格式化输出函数)

    函数定义

    将格式化数据打印到流。

    函数声明

    int fprintf( FILE *stream, const char *format [, argument ]...);
    
    • 返回值:fprintf返回写入的字节数。当发生输出错误时,这些函数中的每一个都返回一个负值。
    • stream:指向文件结构的指针
    • format:格式控制字符串
    • [, argument ]… :可选参数

    fprintf函数的使用可以参考一下printf函数:
    在这里插入图片描述
    可以看到,fprintf函数和printf函数的不同仅仅是多了一个参数文件流,而我们知道printf函数是将数据打印到屏幕上的,由此可以推断fprintf函数的作用就是将数据打印到对应的文件流上去。

    举例

    将一个结构体内容输出到文件中

    #include <stdio.h>
    
    struct Stu
    {
    	char name[20];
    	int age;
    	float score;
    };
    
    int main()
    {
    	struct Stu s = {"zhangsan", 20, 66.5f};
    	FILE*pf = fopen("test.txt", "w");
    	if (pf == NULL)
    	{
    		perror("fopen");
    		return 1;
    	}
    	fprintf(pf, "%s %d %f", s.name, s.age, s.score);
    
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    这段代码我们通过fprintf函数将一个结构体s的内容输出到text.txt文件中去,运行结果:
    在这里插入图片描述
    打开text.txt文件我们可以看到该结构体的内容被输出到该文件中去了。

    6.fscanf(格式化输入函数)

    函数定义

    从流中读取格式化数据。

    函数声明

    int fscanf( FILE *stream, const char *format [, argument ]... );
    
    • 返回值:每个函数都返回成功转换和分配的字段数;返回值不包括已读取但未分配的字段。返回值0表示未分配任何字段。如果发生错误,或者如果在第一次转换之前到达文件流的结尾,那么fscanf的返回值是EOF
    • FILE *stream:指向文件结构的指针
    • const char *format:格式控制字符串
    • [, argument ]…:可选参数

    我们还是拿fscanf函数来和scanf函数对比一下:
    在这里插入图片描述
    可以看到,fscanf函数和scanf函数的不同也仅仅是多了一个参数文件流,而我们知道scanf函数是从屏幕上获取数据的,由此可以推断fscanf函数的功能就是从文件流中获取数据。

    举例

    从文件中读取一个结构体内容。

    #include <stdio.h>
    
    struct Stu
    {
    	char name[20];
    	int age;
    	float score;
    };
    
    int main()
    {
    	struct Stu s = {0};
    	FILE*pf = fopen("test.txt", "r");
    	if (pf == NULL)
    	{
    		perror("fopen");
    		return 1;
    	}
    
    	fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
    	printf("%s %d %f\n", s.name, s.age, s.score);
    
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    上段代码中我们将一个结构体s的内容输出到了test.txt文件中,这段代码我们再使用fscanf函数将文件中的结构体拿出来打印到屏幕上。

    运行结果:
    在这里插入图片描述

    7.fwrite(二进制输出)

    函数定义

    将数据以二进制形式写入流。

    函数声明

    size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
    
    • 返回值:fwrite返回实际写入的完整项的数目,如果发生错误,该数目可能小于count。此外,如果发生错误,则无法确定文件位置指示器。
    • buffer:指向要写入的数据的指针
    • size:要写入项目的大小(字节)
    • count:要写入的项目数
    • stream:指向文件结构的指针

    举例

    将一个结构体的内容以二进制的形式输出一个到一个文件中去,代码如下:

    #include <stdio.h>
    
    struct Stu
    {
    	char name[20];
    	int age;
    	float score;
    };
    
    int main()
    {
    	struct Stu s = { "张三", 20, 99.5f };
    	FILE* pf = fopen("test.dat", "wb");
    	if (pf == NULL)
    	{
    		perror("open file for writting");
    		return 1;
    	}
    	//写文件
    	fwrite(&s, sizeof(struct Stu), 1, pf);
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    创建一个结构体变量s,以二进制写的方式打开一个文件test.dat,然后用fwrite函数将结构体s的内容写一个写到文件中去,最后我们来看文件里的内容。
    在这里插入图片描述
    其实如果我们真的来看这个文件中的内容你会发现你只能看懂一个"张三",而其他的东西都看不懂。为什么会这样呢,其实不难解释,因为fwrite函数是把数据以二进制的形式写到二进制文件中的,而我们的记事本只能观察文本文件,二进制文件是分辨不出来的,所以这里我们看不到这个文件的内容。但既然我们能看到结构体里的"张三",那也可以简单的说明我们已经成功的把结构体的数据写进去了。

    这里肯定有人会疑惑了,那为什么"张三"在二进制文件中可以用文本的方式查看呢?是这样的,"张三"实际上是一个字符串,字符串不论以文本还是二进制写进去内容都是一样的,都是字符串,所以可以看懂。

    8.fread(二进制输入)

    函数定义

    从流中读取二进制数据。

    函数声明

    size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
    
    • 返回值:fread返回实际读取的完整项目数,如果发生错误或在达到count之前遇到文件结尾,则该值可能小于count。使用feof或feror函数来区分读取错误和文件结束条件。如果size或count为0,则fread返回0且缓冲区内容不变。
    • buffer:数据的存储位置
    • size:项目大小(字节)
    • count:要读取的项目数
    • stream:指向文件结构的指针

    举例

    在上一段代码中我们将一个结构体的数据输入到了文件中,接下来我们再利用fread函数将这些数据从文件读到一个结构体中去

    #include <stdio.h>
    
    struct Stu
    {
    	char name[20];
    	int age;
    	float score;
    };
    
    int main()
    {
    	struct Stu s = { 0 };
    	FILE* pf = fopen("test.dat", "rb");
    	if (pf == NULL)
    	{
    		perror("open file for reading");
    		return 1;
    	}
    	//读文件
    	fread(&s, sizeof(struct Stu), 1, pf);
    	printf("%s %d %f\n", s.name, s.age, s.score);
    
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }
    

    这里我们又重新创建了一个结构体s,初始化里面为空。接下来我们以二进制读取的方式打开文件test.dat,然后利用fread函数从文件中读取一个结构体的数据到结构体s中去。为了方便展示,在读取结束之后我们将结构体s的内容打印出来,运行结果:
    在这里插入图片描述
    这里我总共介绍了八种重要的文件操作函数,大家一定要熟练掌握。

    其实这八个函数主要是用来顺序读取文件的,这些文件创建好之后,文件指针就自动指向该文件的起始位置,然后我们从起始位置开始往后操作,这种读写方式称为顺序读写。

    但是如果我们在拿到一个文件之后,想随机的来操作文件中的某一个位置,这几个函数显然就不能实现,最后我再向大家提几个有关随机读取的函数。

    1. fseek
    2. ftell
    3. rewind

    如果大家有兴趣可以自己查找学习一下。

    最后希望这篇文章可以帮助到大家。

    展开全文
  • 为什么结果会不同呢?就是因为printf函数对输出表中各量求值的顺序是自右至左进行 的。在式中,先对最后一项“-i--”求值,结果为-8,然后i自减1后为7。 再对“-i++”项求值得-7,然后i自增1后为8。再对“i--”项求...
  • 1.什么是文件 磁盘上的文件是文件。 但是在程序设计中,我们...在以前所处理数据的输入输出都是以终端对象的,即从终端的键盘输入数据,运行结果显示到显示器上。 其实有时候我们会把信息输出到磁盘上,当需要的时候

    1.什么是文件

    磁盘上的文件是文件。 但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件。

    1.程序文件

    包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀 为.exe)。

    2.数据文件

    文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内 容的文件。
    在以前所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。
    其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上。

    2.文件名

    文件名包含3部分:文件路径+文件名主干+文件后缀
    例如:/Users/cxf/CLionProjects/assignment/file.txt
    为了方便起见,文件标识常被称为文件名。

    3.文件类型

    根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
    数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件
    如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。
    一个数据在内存中是怎么存储的呢?
    字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
    如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输 出,则在磁盘上只占4个字节(VS2013测试)。

    测试代码

    #include <stdio.h>
    int main(){
        int a = 1000;
          //..表示上一级目录;.表示当前路径
    //    FILE *pf = fopen("/Users/cxf/CLionProjects/assignment/file.txt", "wb");//绝对路径
        FILE *pf = fopen("../file.txt", "wb");//相对路径
        fwrite(&a, 4, 1, pf);//数据地址, 数据字节大小, 写入个数, 待写入的文件指针
        fclose(pf);//关闭文件指针
        pf =NULL;//文件指针置为空
        return 0;
    }
    

    4.文件缓冲区

    ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘 上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐 个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。

    5.文件指针

    缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
    每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及 文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.
    例如,MacOS的GCC编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

    typedef	struct __sFILE {
    	unsigned char *_p;	/* current position in (some) buffer */
    	int	_r;		/* read space left for getc() */
    	int	_w;		/* write space left for putc() */
    	short	_flags;		/* flags, below; this FILE is free if 0 */
    	short	_file;		/* fileno, if Unix descriptor, else -1 */
    	struct	__sbuf _bf;	/* the buffer (at least 1 byte, if !NULL) */
    	int	_lbfsize;	/* 0 or -_bf._size, for inline putc */
    
    	/* operations */
    	void	*_cookie;	/* cookie passed to io functions */
    	int	(* _Nullable _close)(void *);
    	int	(* _Nullable _read) (void *, char *, int);
    	fpos_t	(* _Nullable _seek) (void *, fpos_t, int);
    	int	(* _Nullable _write)(void *, const char *, int);
    
    	/* separate buffer for long sequences of ungetc() */
    	struct	__sbuf _ub;	/* ungetc buffer */
    	struct __sFILEX *_extra; /* additions to FILE to not break ABI */
    	int	_ur;		/* saved _r when _r is counting ungetc data */
    
    	/* tricks to meet minimum requirements even when malloc() fails */
    	unsigned char _ubuf[3];	/* guarantee an ungetc() buffer */
    	unsigned char _nbuf[1];	/* guarantee a getc() buffer */
    
    	/* separate buffer for fgetln() when line crosses buffer boundary */
    	struct	__sbuf _lb;	/* buffer for fgetln() */
    
    	/* Unix stdio files get aligned to block boundaries on fseek() */
    	int	_blksize;	/* stat.st_blksize (may be != _bf._size) */
    	fpos_t	_offset;	/* current lseek offset (see WARNING) */
    } FILE;
    

    不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
    每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。
    一般都是通过一个FILE FILE 下面我们可以创建一个FILE的指针变量:
    下面我们可以创建一个FILE
    的指针变量:

    FILE* pf;//文件指针变量
    

    定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。

    6.文件的打开和关闭

    文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
    在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的 关系。
    ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。

    FILE * fopen ( const char * filename, const char * mode );
    int fclose ( FILE * stream );
    

    打开方式如下:

    文件使用方式 含义 如果指定文件不存在
    "r"只读 为了输入数据,打开一个已经存在的文本文件 出错
    "w"只写 为了输出数据,打开一个文本文件 建立一个新文件
    "a"追加 向文件末尾添加数据 出错
    "rb"只读 为了输入数据,打开一个二进制文件 出错
    "wb"只写 为了输出数据,打开一个二进制文件 建立一个新文件
    "ab"追加 向一个二进制文件末尾添加数据 出错
    "r+"读写 为了读写,打开一个文本文件 出错
    "w+"读写 为了读写,建立新文件 建立新的文件
    "a+"读写 打开一个文件,在文件尾进行读写 建立新文件
    "rb+"读写 为了读写,打开一个二进制文件 出错
    "wb+"读写 为了读写,建立一个新的二进制文件 建立新文件
    "ab+"读写 打开一个二进制文件,在文件末尾进行读写 建立新文件

    示例代码:

    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    
    int main(){
        int a = 1000;
        //..表示上一级目录;.表示当前路径
    //    FILE *pf = fopen("/Users/cxf/CLionProjects/assignment/file.txt", "wb");//绝对路径
        FILE *pf = fopen("../file.txt", "r");//相对路径
        if (pf == NULL){
            printf("%s\n", strerror(errno));//打开失败就会提示报错
        }
        //打开成功
        fwrite(&a, 4, 1, pf);
        //关闭文件
        fclose(pf);
        pf =NULL;
        return 0;
    }
    

    7.文件的顺序读写

    1.格式化输入出函数

    函数定义格式 函数功能 返回值
    int printf(char *format, 输出表) 按串format给定输出格式,把输出表各表达式的值,输出到标准输出文件 成功:输出字符数【失败:EOF】
    int scanf(char *format, 输入项地址表) 按串format给定输入格式,从标准输入文件读入数据,存入各输入项地址列表指定的存储单元中 成功:输入数据个数【失败:EOF】
    int sprintf(char *s, char *format, 输出表) 把输出表中格式化数据输出到(存储)字符串s 成功:输出数据个数【失败:EOF】
    int sscanf(char *s, char *format, 输入项地址表) 从字符串s中读取格式化的数据存储到输入地址表中 成功:输入数据个数【失败:EOF】
    int fprintf(FILE *pf, char *format, 输出表) 将输出表中数据输出到(存储)pf所指文件中 成功:输出数据个数【失败:负数】
    int fscanf(FILE *pf, char *format, 输入项地址表) 按输入地址项格式将所获得的数据存入pf所指的文件中 成功:输入数据个数【失败:EOF】

    2.字符(串)输入输出函数

    函数定义格式 函数功能 返回值
    int getchar() 从标准输入文件读入一个字符 字符ASCII值或EOF
    int putchar(char ch) 向标准输出文件输出字符ch 成功:ch【失败:EOF】
    char *gets(char *s) 从标准输入 成功:s【失败:EOF】
    int puts(char *s) 把字符串s输出到标准输出文件,‘\0’转换为‘\n’输出 成功:换行符【失败:NULL】
    int fgetc(FILE *fp) 从fp所指文件中读取一个字符 成功:所取字符【失败:EOF】
    int fputc(char ch, FILE *fp) 将字符ch输出到fp所指向的文件 成功:ch【失败:EOF】
    char *fgets(char *s, int n, FILE *fp) 从fp所指文件最多度n-1个字符(遇’\n’,^z终止)到字符串s中 成功:s【失败:EOF】
    int *fputs(char *s, FILE *fp) 将字符串s输出到fp所指向文件 成功:s的末字符【失败:0】

    3.文件操作函数

    函数定义格式 函数功能 返回值
    FILE *fopen(char *fname, char *mode) 以mode方式打开fname 成功:文件指针【失败:NULL】
    int fclose(FILE *fp) 关闭fp所指文件 成功:0【失败:非0】
    int feof(FILE *fp) 检查fp所指文件是否结束 是:非0【失败:0】
    int fread(T *a, long sizeof(T), unsigned int n, FILE *fp) 从fp所指文件复制n*sizeof(T)个字节的数据,到T类型指针变量a所指内存区域 成功:n【失败:0】
    int fwrite(T *a, long sizeof(T), unsigned int n, FILE *fp) 从T类型指针变量a所指初起复制n*sizeof(T)个字节的数据,到fp所指向文件 成功:n【失败:0】
    void rewind(FILE *fp) 移动fp所指文件读写位置到文件头
    int fseek(FILE *fp, long n, unsigned int posi) 移动fp所指文件读写位置,n为偏移量,posi决定起点位置 成功:0【失败:非0】
    long ftell(FILE *fp) 求当前读写位置到文件头的字节数 成功:所求字节数【失败:EOF】
    int remove(char *fname) 删除名为fname的文件 成功:0【失败:EOF】
    int rename(char *oldfname, char *newfname) 该文件名oldfname为newfname 成功:0【失败:EOF】

    说明:fread()和fwrite()中的类型T可以是任意合法定义的类型。

    8.文件的随机读写

    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    
    struct S{
        int n;
        float score;
        char arr[20];
    };
    
    //int fwrite(T *a, long sizeof(T), unsigned int n, FILE *fp)
    void r_write() {
        int a = 1000;
        //..表示上一级目录;.表示当前路径
    //    FILE *pf = fopen("/Users/cxf/CLionProjects/assignment/file.txt", "wb");//绝对路径
        FILE *pf = fopen("../r_write.txt", "wb");//相对路径
        if (pf == NULL) {
            printf("%s\n", strerror(errno));//打开失败就会提示报错
        }
        //打开成功
        fwrite(&a, 4, 1, pf);
        //关闭文件
        fclose(pf);
        pf = NULL;
    }
    
    //int fread(T *a, long sizeof(T), unsigned int n, FILE *fp)
    void r_fread(){
        struct S tmp= {0};
        FILE *pf = fopen("../w_fputs.txt", "rb");
        if (pf == NULL){
            printf("%s\n", strerror(errno));
        }
        //二进制的形式读文件
        fread(&tmp, sizeof(struct S), 1, pf);
        printf("%d %f %s\n", tmp.n, tmp.score, tmp.arr);
        fclose(pf);
        pf = NULL;
    }
    //int fputc(char ch, FILE *fp)
    void w_fputc() {
        FILE *pf = fopen("../w_fputc.txt", "w");
        if (pf == NULL) {
            printf("%s\n", strerror(errno));
        }
        /*
         * 写文件:一个一个字符写入
         */
        fputc('z', pf);
        fputc('x', pf);
        fputc('y', pf);
        fputc('\n', pf);
        fputc('c', pf);
        fputc('x', pf);
        fputc('f', pf);
        //关闭文件
        fclose(pf);
        pf = NULL;
    }
    
    //int *fputs(char *s, FILE *fp)
    void w_fputs(){
        FILE *pf = fopen("../w_fputs.txt", "w");
        if (pf == NULL){
            printf("%s\n", strerror(errno));
        }
        /*
         * 写文件:一行一行写到底,多个fputs不会自动换行;如要换行必须在内容中加入"\n"来换行
         */
        fputs("abcd陈雄峰", pf);
        fputs("我曾悲伤的爱过这个世界\n", pf);
        fputs("张晓韵\n", pf);
        fputs("50年后的世界会在地狱的火焰中湮灭\n", pf);
        fclose(pf);
        pf = NULL;
    }
    
    //int fgetc(FILE *fp)
    void r_fgetc() {
        FILE *pf = fopen("../w_fputc.txt", "r");
        if (pf == NULL) {
            printf("%s\n", strerror(errno));
        }
        /*
         * 读文件:一个一个字符读取
         */
        printf("%c", fgetc(pf));
        printf("%c", fgetc(pf));
        printf("%c", fgetc(pf));
        //关闭文件
        fclose(pf);
        pf = NULL;
    }
    
    //char *fgets(char *s, int n, FILE *fp)
    void r_fgets(){
        char buf[1024] = {0};//0有一个换行
        FILE *pf = fopen("../w_fputc.txt", "r");
        if (pf == NULL){
            printf("%s\n", strerror(errno));
        }
        /*
         * cxf
         * zxy
         * 读文件:一行一行读取
         * 遇到换行就结束,如果要多次读取需要多次fgets
         */
        printf("%s", fgets(buf, 1024, pf));
        printf("%s", fgets(buf, 1024, pf));
        fclose(pf);
        pf = NULL;
    }
    
    //int fprintf(char *s, char *format, 输出表)
    void w_fprintf(){
        struct S s = {100, 3.14f, "陈雄峰"};
        FILE *pf = fopen("../w_fprintf.txt", "w");
        if (pf == NULL){
            printf("%s\n", strerror(errno));
        }
        //格式化形式写文件
        fprintf(pf, "%d %f %s", s.n, s.score, s.arr);
        fclose(pf);
        pf = NULL;
    }
    
    //int fscanf(char *s, char *format, 输入项地址表)
    void r_fscanf(){
        struct S s = {0};
        FILE *pf = fopen("../w_fprintf.txt", "r");
        if (pf == NULL){
            printf("%s\n", strerror(errno));
        }
        //格式化的输入数据
        fscanf(pf, "%d %f %s", &(s.n), &(s.score), &(s.arr));
        printf("%d\n", s.n);
        printf("%f\n", s.score);
        printf("%s\n", s.arr);
        fclose(pf);
        pf = NULL;
    }
    
    void stdint_stdout() {
        /*int ch = fgetc(stdin);
        fputc(ch, stdout);
    
        printf("\n");
    
        char buf[1024] = {0};
        fgets(buf, 1024, stdin);//从标准输入流读取
        fputs(buf, stdout);//从标准输出流输出
    
        printf("\n");
    
        struct S s = {0};
        fscanf(stdin, "%d %f %s", &(s.n), &(s.score), &(s.arr));//格式化获取所有输入流
        fprintf(stdout, "%d %f %s\n", s.n, s.score, s.arr);*///格式化输出所有输出流
    
    
        printf("\n");
        char buf1[1024] = {0};
        struct S tmp = {0};
        struct S s1 = {200, 6.28, "陈雄峰陈雄峰"};
        sprintf(buf1, "%d %f %s", s1.n, s1.score, s1.arr);//把格式化的数据换成字符串存储到buf1
        printf("%s\n", s1.arr);
        sscanf(buf1, "%d %f %s", &(tmp.n), &(tmp.score), &(tmp.arr));//从buf1中读取格式化的数据到tmp中
        printf("%s\n", tmp.arr);
    
        /*
         * scanf/printf:针对标准输入流/输出流的 格式化输入/输出语句
         * fscanf/fprintf:针对所有输入流/输出流的 格式化输入/输出语句
         * sscanf/sprintf:sscanf是从字符串中读取格式化的数据【sprintf是把格式化数据输出成(存储)字符串】
         */
    }
    
    //int fseek(FILE *fp, long n, unsigned int posi)
    void r_fseek(){
        FILE *pf = fopen("../w_fputs.txt", "r");
        if (pf == NULL){
            printf("%s\n", strerror(errno));
        }
        //定位文件指针
        fseek(pf, 1, SEEK_CUR);//文件指针当前位置偏移1字节
    //    fseek(pf, -2, SEEK_END);//文件末尾位置向前偏移2字节【倒数第二个字符】
    //    fseek(pf, 1, SEEK_SET);//文件起始位置向后偏移1字节
    
        //读文件
        int ch = fgetc(pf);
        printf("%c\n", ch);
        fclose(pf);
        pf = NULL;
    }
    
    //long ftell(FILE *fp)
    void r_ftell(){
        FILE *pf = fopen("../w_fputs.txt", "r");
        if (pf == NULL){
            printf("%s\n", strerror(errno));
        }
        //定位文件指针
        fseek(pf, 1, SEEK_CUR);//文件指针当前位置偏移1字节
    //    fseek(pf, -2, SEEK_END);//文件末尾位置向前偏移2字节【倒数第二个字符】
    //    fseek(pf, 1, SEEK_SET);//文件起始位置向后偏移1字节
    
        //读文件
        int pos = ftell(pf);
        printf("%d\n", pos);
        fclose(pf);
        pf = NULL;
    }
    
    void r_rewind(){
        FILE *pf = fopen("../w_fputs.txt", "r");
        if (pf == NULL){
            printf("%s\n", strerror(errno));
        }
        //定位文件指针
    //    fseek(pf, 1, SEEK_CUR);//文件指针当前位置偏移1字节
        fseek(pf, -2, SEEK_END);//文件末尾位置向前偏移2字节【倒数第二个字符】
    //    fseek(pf, 1, SEEK_SET);//文件起始位置向后偏移1字节
    
        //恢复文件指针
        rewind(pf);
        //读文件
        printf("%c\n", fgetc(pf));
        fclose(pf);
        pf = NULL;
    }
    

    9.文件结束的判定

    被错误使用的feof
    牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
    而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。

    1. 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或者NULL(fgets)
      例如:
    • fgetc判断是否为EOF
    • fgets判断返回值是否为NULL
    1. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
      例如: fread判断返回值是否小于实际要读的个数。
      正确的使用:

    文本文件举例:

        FILE *pf = fopen("../w_fputs.txt", "r");
        if (pf == NULL) {
            perror("Open w_fputs.txt faild: ");
        }
        //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
        int ch;//int非char,要处理EOF
        while ((ch = fgetc(pf)) != EOF) {//标准I/O读取文件循环
            putchar(ch);
        }
        //判断什么原因结束的
        if (ferror(pf)) {
            puts("I/O error when reading!");
        } else if (feof(pf)) {
            puts("end of file reached successfuly!");
        }
        fclose(pf);
        pf = NULL;
    

    二进制文件举例:

        enum {
            size = 5
        };
        double a[size] = {1.1, 2.2, 3.3, 4.4, 5.5}, b;
        size_t ret_code = 0;
        FILE *pf = fopen("../bin_end.bin", "wb");
        if (pf == NULL) {
            perror("Open bin_end.bin faild: ");
        }
        fwrite(a, sizeof(a), 1, pf);
        fclose(pf);
    
        pf = fopen("../bin_end.bin", "rb");
        if (pf == NULL) {
            perror("Open bin_end.bin faild: ");
        }
        while ((ret_code = fread(&b, sizeof(a), 1, pf)) == 1) {
            printf("%lf\n", b);
        }
        //判断什么原因结束的
        if (ferror(pf)) {
            puts("I/O error when reading!");
        } else if (feof(pf)) {
            puts("end of file reached successfuly!");
        }
        fclose(pf);
        pf = NULL;
    
    展开全文
  • o 7.18 当数组是函数的参数时, 为什么 sizeof 能正确报告数组的大小 ? * 8. 内存分配 o 8.1 为什么这段代码不行?char *answer; printf("Type something:\n"); gets(answer); printf("You typed \"%s\"\n", ...
  • c语言编写单片机技巧

    2009-04-19 12:15:17
    此外,C语言程序具有完善的模块程序结构,从而软件开发中采用模块化程序设计方法提供了有力的保障。因此,使用C语言进行程序设计已成为软件开发的一个主流。用C语言来编写目标系统软件,会大大缩短开发周期,且...
  • 《你必须知道的495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    1.24 我在一个文件中定义了一个extern数组,然后在另一个文件中使用,为什么sizeof取到数组的大小? 13 声明问题 14 1.25 函数只定义了一次,调用了一次,但编译器提示非法重声明了。 14 *1.26 main的正确...
  • 1.24 我在一个文件中定义了一个extern数组,然后在另一个文件中使用,为什么sizeof取到数组的大小? 声明问题 1.25 函数只定义了一次,调用了一次,但编译器提示非法重声明了。 1.26 main的正确定义是什么?void ...
  • 1.2 为什么不精确定义标准类型的大小? 2 1.3 因为C语言没有精确定义类型的大小,所以我一般都用typedef定义int16和int32。然后根据实际的机器环境把它们定义为int、short、long等类型。这样看来,所有的问题都...
  • 1.2 为什么不精确定义标准类型的大小? 1.3 因为C语言没有精确定义类型的大小,所以我一般都用typedef定义int16和int32。然后根据实际的机器环境把它们定义为int、short、long等类型。这样看来,所有的问题都解决...
  • 电话薄管理系统C语言

    2010-12-16 18:31:55
    win-tc下的,修改下可以在vc下运行,是c语言编写的 #include "stdio.h" /*标准输入输出函数库*/ #include "stdlib.h" /*标准函数库*/ #include "string.h" /*字符串函数库*/ #include "conio.h" /*屏幕操作函数库*/ ...
  • 1.2 为什么不精确定义标准类型的大小? 1.3 因为C语言没有精确定义类型的大小,所以我一般都用typedef定义int16和int32。然后根据实际的机器环境把它们定义为int、short、long等类型。这样看来,所有的问题都解决...
  • 本书集综合性、实用性一体,是学习C语言的优秀入门教材,在世界范围内广受欢迎,口碑极佳。书中除了讲解C程序设计语言,还广泛介绍了作为一名C程序设计人员应该掌握的必要知识,并提供了大量的实用性很强的编程...
  • 你必须知道的495个C语言问题(PDF)

    热门讨论 2009-09-15 10:25:47
    2.2 为什么struct x f . . . g; x thestruct; 不对? . . . . . . . . . . . . . 7 2.3 一个结构可以包含指向自己的指针吗? . . . . . . . . . . . . . . . 7 2.4 在C 语言中实现抽象数据类型什么方法最好? . . . ....
  • 本书集综合性、实用性一体,是学习C语言的优秀入门教材,在世界范围内广受欢迎,口碑极佳。书中除了讲解C程序设计语言,还广泛介绍了作为一名C程序设计人员应该掌握的必要知识,并提供了大量的实用性很强的编程...
  •  1.24 我在一个文件中定义了一个extern数组,然后在另一个文件中使用,为什么sizeof取到数组的大小?  声明问题  1.25 函数只定义了一次,调用了一次,但编译器提示非法重声明了。  1.26 main的正确定义是什么...

空空如也

空空如也

1 2 3 4 5
收藏数 81
精华内容 32
关键字:

为什么c语言输出不显示结果

c语言 订阅