一、知识点归纳

  1. 系统调用函数:
    open()
    read()
    write()
    lseek()
    close()
    I/O库函数:
    fopen()
    fread()
    fwrite()
    fseek()
    fclose()
    关系:fopen()依赖于open(),fread依赖于read()等等...

  2. fread算法
    调用fread————FILE结构体缓冲区为空————fread发出n = read(fd,fbuffer,BLKSIZE);
    ————初始化fbuf[]指针————将数据复制到程序的缓冲区————更新内部缓冲区

  3. fwrite算法
    与fread算法相似,但数据传输方向不同

  4. fclose算法
    写:fclose()关闭文件流的局部缓冲区————发出close(fd)系统调用来关闭FILE结构体的文件描述符————释放FILE结构体,将FILE指针重置为NULL

  5. I/O库模式
    “r”读
    "w"写
    "a"追加
    “r+”读/写,但不截断文件
    “w+”读/写,但截断文件;若文件不存在,则创建文件
    “a+”通过追加进行读/写;如果文件不存在,将创建文件

  6. 字符模式I/O


int fgetc(FILE *fp); // get achar from fp, cast to int
int ungetc(int c, FILE *fp); // push a prviously char got by fgetc() back to stream
int fputc(int c, FILE *fp); // put a char to fp
  1. 行模式I/O
char *fgets(char *buf, int size, FILE *fp);从fp中读取最多的为一行(以\n结尾)的字符。
int fputs(char *buf,FILE *fp);将buf的一行写入fp中
  1. 格式化I/O
格式化输入:(FMT=格式字符串)
scanf(char *FMT,&items);
fscanf(fp, char *FMT,&items);

格式化输出:
printf(char *FMT,items);
fprintf(fp,char *FMT,items);
  1. 内存中的转换函数
sscanf(buf, FMT,&items);       //input from buf[] in memory
sprintf(buf FMT,items);          //print to buf[] in memory
  1. 其他I/O库函数
fseek()、ftell()、rewind():更该文件流中的读/写字节位置
feof()、ferr()、fileno():测试文件流状态
fdopen():用文件描述符打开文件流
freopen():以新名称重新打开现有的流
setbuf()、setvbuf():设置缓冲方案
popen():创建管道,复刻子进程来调用sh
  1. 限制混合
    当文件流同时用于读/写时,会限制使用混合fread()和fwrite()调用,规范要求对fread()和fwrite()之间至少有一个fseek()和ftell()
  2. 文件流缓冲
    无缓冲:从非缓冲流中写入或读取的字符将尽快单独传输到文件或从文件中传输。
    行缓冲:遇到换行符时,写入行缓冲流的字符以块的形式传输。
    全缓冲:写入全缓冲流或从中读取的字符以块大小传输到文件或从文件传输。这是文件流的正常缓冲方案。
    通过fopen创建文件流之后,在对其执行任何操作之前,用户均可发出一个
    setvbuf(FILE *stream,char *buf , int node,int size)
  3. 变参函数
独特的printf,多种不同类型的可变数量参数可以调用它
int func(intm,int n) //n = last specified parameter
在函数内部,可以通过C语言库宏访问参数:
void va_start (va_list ap, last); //start param list from last parameter
type va_arg(va_list ap, type); //type=next parameter type
va_end(va_list ap);// clear parameter list

苏格拉底挑战:


二、问题与解决思路
由于之前做过类似的题目,所以一开始考虑用fscanf函数将文件读取到数组中去,然后再利用数组计算出单词数量:

while ( fscanf(fp,"%s",tmp)!=EOF )          //fscanf从文件中获取单个字符串
	{
		for(j=0;tmp[j]!='\0';j++)               //清除符号
		{
			if(tmp[j]==','||tmp[j]=='.'||tmp[j]==':'||tmp[j]=='"'||tmp[j]=='!'||tmp[j]=='//'||tmp[j]=='\\')//英文标点
				tmp[j]='\0';                    // 如果文本符号没有分隔开,会出错
		}

不过这种方式费时费力,还无法读取回车,因此我改变思路,只需要利用fread函数读文件就可以了,并且利用流指针就能准确定位单词的数量

三、实验过程截图、代码链接
问题三:编写一个c程序,从系统中导入文本,并计算文本的单词数,单词是由空格分开的一系列字符

代码:
使用fopen函数打开用户指定的文本文件,并使用fread函数读取文件内容到内存中。然后,它调用之前定义的countWords函数来计算文本中的单词数,并将结果打印出来。

#include <stdio.h>
#include <stdlib.h>

#define MAX_LENGTH 1000

int countWords(char *text) {
    int count = 0;
    int isWord = 0;

    while (*text) {
        if (*text == ' ' || *text == '\t' || *text == '\n') {
            isWord = 0;
        }
        else if (isWord == 0) {
            isWord = 1;
            count++;
        }

        text++;
    }

    return count;
}

int main() {
    FILE *file;
    char filename[255];
    char *text;
    long length;

    printf("请输入要导入的文本文件路径:");
    scanf("%s", filename);

    // 打开文件
    file = fopen(filename, "r");
    if (file == NULL) {
        printf("无法打开文件。\n");
        return 1;
    }

    // 获取文件长度
    fseek(file, 0, SEEK_END);
    length = ftell(file);
    fseek(file, 0, SEEK_SET);

    // 分配内存并读取文件内容
    text = malloc(length);
    if (text == NULL) {
        printf("内存分配失败。\n");
        fclose(file);
        return 1;
    }
    fread(text, 1, length, file);
    fclose(file);

    // 计算单词数
    int numWords = countWords(text);

    printf("单词数为:%d\n", numWords);

    // 释放内存
    free(text);

    return 0;
}

这道题我在计算机实习时做过类似题目,因此还算是较为熟悉