【C语言】文件操作 -- 详解

news2025/3/1 21:22:09

一、什么是文件

磁盘上的文件是文件。

1、为什么要使用文件

        举个例子,当我们想实现一个 “通讯录” 程序时,在通讯录中新建联系人、删除联系人等一系列操作,此时的数据存储于内存中,程序退出后所有数据都会随之消失。为了让通讯录中的信息得以保存,也就是想让数据持久化,我们就需要采用让数据持久化的方法。我们一般数据持久化的方法有:把数据存放在磁盘文件中,或存放到数据库等方式


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

2、程序文件

包括源程序文件(后缀为 .c ),目标文件( windows 环境后缀为 .obj ),可执行程序( windows 环境后缀为 .exe)。
#include <stdio.h>
 
int main()
{
    printf("Hello,World!\n");
    
    return 0;
}

(1)

 (2)


3、数据文件

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

此时,如果我写的程序在读写这个文件(我可以读这个文件夹的内容进我的程序中,或是将一些内容写到这个文件夹中),那么这个文件就成为数据文件。 


二、文件名

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

文件名包含三个部分:文件路径 + 文件名主干 + 文件后缀( 例如:C:\code\test.txt )

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


三、文件类型

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

 

 

 

 


四、文件缓冲区(File Buffer)

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

#include <stdio.h>
#include <windows.h>

int main()
{
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf); // 先将代码放在输出缓冲区
	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
	Sleep(10000);
	printf("刷新缓冲区\n");
	fflush(pf); // 刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
	Sleep(10000);

	fclose(pf); // fclose在关闭文件的时候,也会刷新缓冲区
	pf = NULL;

	return 0;
}

 

结论: 因为有缓冲区的存在,C 语言在操作文件时,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。如果不做,可能导致读写文件的问题。


五、文件指针

在 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;

 注意

  1. FILE 的结构在不同的 C 编辑器中包含的内容并不是不完全相同的,但还是颇为相似的。
  2. 每当打开一个文件时,系统会根据文件的状况自动创建一个 FILE 结构的变量,并填充其中的信息。只要文件被读写发生变化,文件信息区也会跟着发生变化。至于文件变化时文件信息区是怎么变化和修改的,我们其实并不需要关心这些细节,因为 C 语言已经帮你弄好了。
  3. 我们一般会通过一个 FILE 的指针来维护这个 FILE 结构的变量。并不会直接使用,而是拿一个结构体指针指向这个结构,通过这个指针来访问和维护相关的数据,这样使用起来会更加方便。
// 以创建一个FILE*的指针变量
FILE* pf; // 文件指针变量
定义  pf  是一个指向  FILE   类型数据的指针变量。可以使  pf  指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件


六、文件的打开和关闭

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

 

 

// open the file
FILE * fopen (const char* filename, const char* mode);

// close the file
int fclose (FILE* stream);

// filename参数指的是文件名,mode参数为打开方式

#include <stdio.h>

int main()
{
    FILE* pf = fopen("test.dat", "w");
    if (pf == NULL) // 检查是否为空指针
    {
        perror("fopen");
        return 1;
    }

    fclose(pf);
    pf = NULL; // 将pf置为空指针

    return 0;
}

 一切正常。

我们把 test.dat 文件删除,然后打开方式改成 r 试试看。

#include <stdio.h>

int main()
{
    FILE* pf = fopen("test.dat", "r");
    if (pf == NULL) // 检查是否为空指针
    {
        perror("fopen");
        return 1;
    }

    fclose(pf);
    pf = NULL; // 将pf置为空指针

    return 0;
}

 perror 返回的错误信息。

如果不适用相对路径,使用绝对路径读文件:

可以使用绝对路径,但是要注意转义绝对路径中的斜杠

#include <stdio.h>
 
int main()
{
    // FILE* pf = fopen("D:\code\0824\0824\test.dat", "w"); // error

    FILE* pf = fopen("D:\\code\\0824\\0824\\test.dat", "w"); // 转移字符\

    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    fclose(pf);
    pf = NULL;
 
    return 0;
}

注意:不关闭文件的后果:一个程序能够打开的文件是有限的,文件属于一种资源。如果只打开不释放,文件就会被占用。可能会导致一些操作被缓冲在内存中,如果不能正常关闭,缓冲在内存中的数据就不能正常写入到文件中从而导致数据的丢失。


七、文件的顺序读写

  • 顺序读写,简而言之就是按照顺序在文件中读和写。

首先要了解什么是读写:我们写的程序是在内存中,而数据是要放到文件中的,文件又是在硬盘上的。当我们把文件里的数据读到内存中去时,这个动作我们称之为输入 / 读取。反过来,如果把程序中的东西放到硬盘上,这个动作我们称之为输出 / 写入


1、什么是流

⚪stdin:标准输入流 - 键盘

⚪stdout:标准输出流 - 屏幕

⚪stderr:标准错误流 - 屏幕

(它们的类型都是 FILE* )

#include<stdio.h>

int main()
{
	// 从标准输出流里输入数据
	fputc('b', stdout);// 同printf("b");
	fputc('i', stdout);
	fputc('t', stdout);
	printf("\n");

	// 从标准输入流里读取数据
	int ret = fgetc(stdin); // 同scanf("%d", ret);
	printf("%c\n", ret);
	ret = fgetc(stdin);
	printf("%c\n", ret);
	ret = fgetc(stdin);
	printf("%c\n", ret);
	return 0;
}


2、字符输入函数 fgetc

从指定的流 stream 获取下一个字符,并把位置标识符向前移动(字符必须为一个无符号字符)。如果读取成功会返回相应的 ASCII码值,如果读取失败会返回一个 EOF 适用于所有输入流。

#include <stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    int ret = fgetc(pf);
    printf("%c\n", ret);
    ret = fgetc(pf);
    printf("%c\n", ret);
    ret = fgetc(pf);
    printf("%c\n", ret);

    fclose(pf);
    pf = NULL;
    
    return 0;
}

 

读取结束或者读取失败返回 EOF。


3、字符输出函数 fputc

  • 将参数 char 指定的字符写入到指定的流 stream 中,并把位置标识符向前移动 (字符必须为一个无符号字符)。适用于所有输出流。

#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);
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}

 abc 成功被写入。

倘若将代码修改为:

#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);*/
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}

此时再次运行,我们发现那个文件里的内容不见了(大小也变为0kb): 


4、文本行输入函数 fgets

  • 从指定的流 stream 读取一行,并把它存储在 string 所指向的字符串中,当读取(n-1)个字符时,或者读取到换行符、到达文件末尾时,它会停止,具体视情况而定。适用于所有输入流。

注意:假如 n 是 100,读取到的就是 99 个字符(n-1),因为要留一个字符给 '\0'。

 

#include <stdio.h>
 
int main()
{
    char arr[10] = "xxxxxx"; // 存放处
 
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    fgets(arr, 4, pf);
    printf("%s\n", arr);

    fgets(arr, 4, pf);
    printf("%s\n", arr);
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}


5、文本行输出函数 fputs

  • 将字符串写入到指定的流 stream 中(不包括空字符)。适用于所有输出流。

#include <stdio.h>
 
int main()
{
    FILE* pf = fopen("test.txt", "w");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    fputs("abcdef", pf);
    fputs("123456", pf);
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}

如果想要在 "abcdef" 后面换行,只需在 fputs("abcdef\n", pf); 加上换行符即可。 


6、 格式化输入函数 fscanf

  • fscanf 用于对格式化的数据进行读取,从流 stream 读取格式化输入。适用于所有输入流。

#include <stdio.h>
 
struct Student
{
    char name[10];
    int id;
    float score;
};
 
int main()
{
    struct Student s1 = { 0 };
 
    // 对格式化的数据进行写文件
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }
 
    fscanf(pf, "%s %d %f", s1.name, &(s1.id), &(s1.score));

    printf("%s %d %f\n", s1.name, s1.id, s1.score);
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}

注意: p1.name本身就是地址(不用&)。


7、格式化输出函数 fprintf

#include<stdio.h>
struct S
{
	char arr[10];
	int num;
	float sc;
};

int main()
{
	struct S s = { "abcdef", 10, 5.5f };
	FILE* pf1 = fopen("test.txt", "w");
	if(pf1 == NULL)
	{
		perror("fopen");
		return 1;
	}

	fprintf(pf1, "%s %d %f", s.arr, s.num, s.sc); // 将结构体格式化的数据写入文件
 
	fclose(pf1);
	pf1 = NULL;

	struct S temp = { 0 }; // 用于存储读出的数据 
	FILE* pf2 = fopen("test.txt", "r");
	if(pf2 == NULL)
	{
		perror("fopen");
		return 1;
	}

	fscanf(pf2, "%s %d %f", temp.arr, &(temp.num), &(temp.sc));	// 再把数据从文件中读到结构体中

	printf("%s %d %f\n", temp.arr, temp.num, temp.sc); // 打印
 
	fclose(pf2);
	pf2 = NULL;
	return 0;
}


8、二进制输入函数 fread

  • 从流中读取,从给定流 stream 读取数据到 buffer 所指向的数组中。

#include <stdio.h>
// 二进制的形式读
 
struct S
{
    char arr[10];
    int num;
    float score;
};
 
int main()
{
    struct S s = { 0 };
 
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    fread(&s, sizeof(struct S), 1, pf);

    printf("%s %d %f", s.arr, s.num, s.score);

    fclose(pf);
    pf = NULL;
 
    return 0;
}

9、二进制输出函数 fwrite

  •  写一个数据到流中去,把 buffer 所指向的数组中的数据写入到给定流 stream 中。

#include <stdio.h>
// 二进制的形式写
 
struct S
{
    char arr[10];
    int num;
    float score;
};
 
int main()
{
    struct S s = { "abcde", 10, 5.5f };
 
    FILE* pf = fopen("test.txt", "w");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }
    fwrite(&s, sizeof(struct S), 1, pf);

    fclose(pf);
    pf = NULL;
 
    return 0;
}

 

为什么是乱码?为什么 abcde 不是乱码?
  1. 我们刚才用的都是文本编译器,文本编译器打开二进制形式的文件完全是两种状态。
  2. 因为字符串以文本形式写进去和以二进制形式写进去是一样的,但是对于整数、浮点数等来说就不一样了,文本形式写入和二进制形式写入完全是两个概念。

结论:fwritefread 是一对,fwrire 写进去用 fread 读。


八、文件的随机读写

1、文件指针定位函数 fseek

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

int fseek (FILE* stream, long int offset, int origin);

// offset是偏移量,origin是起始位置,有三种选项:

// 1、SEEK_CUR - 当前文件指针的位置开始偏移。
// 2、SEEK_END - 文件的末尾位置开始偏移。
// 3、SEEK_SET - 文件的起始位置开始偏移。

 

#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);
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}

如果我想得到 a a b,该怎么处理呢?
#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);
 
    // 调整文件指针
    fseek(pf, -1, SEEK_CUR); // SEEK_CUR为当前文件指针位置,偏移量为-1,向前移动1个单位
    ch = fgetc(pf);
    printf("%c\n", ch);
    ch = fgetc(pf);
    printf("%c\n", ch);
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}


⚪用 SEEK_SET ,打印 a d e

#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);
 
    // 调整文件指针
    fseek(pf, 2, SEEK_CUR); // SEEK_SET为文件的起始位置,偏移量为2,向后移动2个单位
    ch = fgetc(pf);
    printf("%c\n", ch);
    ch = fgetc(pf);
    printf("%c\n", ch);
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}


⚪用 SEEK_END ,打印 a e f 

#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);
 
    // 调整文件指针
    fseek(pf, -2, SEEK_END); // SEEK_END为当前文件末尾位置,偏移量为-2,向前移动2个单位
    ch = fgetc(pf);
    printf("%c\n", ch);
    ch = fgetc(pf);
    printf("%c\n", ch);
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}


2、返回偏移量函数 ftell

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

long int ftell ( FILE * stream );
#include <stdio.h>
 
int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }
 
    // 调整文件指针
    fseek(pf, 5, SEEK_CUR); // SEEK_CUR为当前文件指针位置,偏移量为5,向后移动5个单位
 
    int ch = fgetc(pf);
    printf("%c\n", ch); // f
 
    // 返回偏移量
    int ret = ftell(pf);
    printf("%d\n", ret); // 6
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}

 


3、文件指针回到起始位置函数 rewind

  • rewind(意为倒带,磁带倒带),设置文件位置为给定流 stream 的文件的开头,让文件指针回到起始位置

#include <stdio.h>
 
int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }
 
    // 调整文件指针
    fseek(pf, 5, SEEK_CUR); // SEEK_CUR为当前文件指针位置,偏移量为5,向后移动5个单位
 
    // 返回偏移量
    int loc = ftell(pf);
    printf("fseek调整文件指针后:%d\n", loc); // 6
 
    // 让文件指针回到起始位置
    rewind(pf);
 
    // 再次返回偏移量,看看是不是回到起始位置了
    loc = ftell(pf);
    printf("使用rewind后:%d\n", loc); // 6
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}


九、文件读取结束的判定 

1、被错误使用的 feof

  • 在文件结束时判断文件因为何种原因导致文件结束的函数判断是因为读取失败而结束,还是因为遇到文件尾而结束。如果文件结束,则返回非 0 值,否则返回 0。

注意feof 函数是个经常被错误使用的一个函数。在文件读取过程中,不能用 feof 函数的返回值直接判断文件是否结束!feof 函数绝对不是用来判断文件是否结束的函数!feof 不是用来判定文件是否结束了的,还是在文件已经结束时,判断是什么原因导致文件结束的

文本文件读取是否结束,判断返回值是否为EOF fgetc),或者NULLfgets

  • fgetc 判断是否为 EOF。
  • fgets 判断返回值是否为 NULL。
#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    int ch = 0; // 注意:int,非char,要求处理EOF
    FILE* pf = fopen("test.txt", "r");
    if (!pf)
    {
        perror("fopen");
        return EXIT_FAILURE; // 符号常量EXIT_FAILURE,表示没有成功地执行一个程序
    }

    // fgetc - 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ( (ch = fgetc(pf)) != EOF )
    {
        putchar(ch);
    }
    printf("\n");
 
    // 判断文件结束的原因
    if (ferror(pf)) // ferror - 检查是否出现错误
    {  
        puts("读取失败错误(I/O error when reading)");
    }
    else if (feof(pf))
    {
        puts("遇到文件尾而结束(End of file reached successfully)");
    }
 
    fclose(pf);
    pf = NULL;
}

 


二进制文件的读取结束判断,判断返回值是否小于实际要读的个数

  • fread 判断返回值是否小于实际要读的个数。
#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;
}


2、正确判定文件是否读取结束的方法

  • 文本文件读取是否结束,判断返回值是否为 EOFfgetc),或者 NULLfgets)。
  1. fgetc 函数在读取结束时会返回 EOF,正常读取时,返回读取到的字符的 ASCII 码值
  2. fgets 函数在读取结束时会返回 NULL,正常读取时,返回存放字符串的空间的起始地址
  3. fread 函数在读取结束时会返回实际读取到的完整元素的个数,如果发现读取到的完整的元素个数小于指定的元素个数,那么就是最后一次读取了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/925466.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue-admin-template实现按钮级控制

这里记录一下使用大佬的模板vue-admin-template&#xff0c;实现按钮级别控制 实现的思路&#xff1a;用户登录之后&#xff0c;返回用户详细信息(将用户的所有权限码发送给前端)&#xff0c;然后将权限码保存在全局状态管理对象中&#xff0c;然后在组件中进行判断是否显示 最…

JAVA学习-愚见

JAVA学习-愚见 分享一下Java的学习路线&#xff0c;仅供参考【本人亲测&#xff0c;真实有效】 1、尽可能推荐较新的课程 2、大部分视频在B站上直接搜关键词就行【自学&#xff0c;B大的学生】 文章目录 JAVA学习-愚见前期准备Java基础课程练手项目 数据库JavaWeb前端基础 Vue…

Rancher2.5.9版本证书更新

一、环境 主机名IP地址操作系统rancher版本K8s-Master192.168.10.236Centos 72.5.9 二、更新证书 1、查看当前证书到期时间 2、进行证书轮换 [rootK8s-Master ~]# docker ps |grep rancher/rancher d581da2b7c4e rancher/rancher:v2.5.9 &q…

ARM汇编【4】:CONDITIONAL EXECUTION

我们在讨论消费品安全标准登记册时已经简要地谈到了条件的主题。我们在程序运行时使用条件来控制程序流&#xff0c;通常是通过跳转&#xff08;分支&#xff09;或仅在满足条件时执行某些指令。该条件被描述为CPSR寄存器中特定位的状态。这些比特根据一些指令的结果不时地变化…

结构体指针和结构体数组指针

结构体指针和结构体数组指针是不同的类型。 结构体指针定义&#xff1a;Student *stu 结构体指针的步长是一个结构体的大小&#xff1b; 结构体数组指针定义&#xff1a;Student (*stu)[] 结构体数组指针的步长是整个结构体数组的大小。 例程&#xff1a; #include <stdio…

机器学习理论笔记(二):数据集划分以及模型选择

文章目录 1 前言2 经验误差与过拟合3 训练集与测试集的划分方法3.1 留出法&#xff08;Hold-out&#xff09;3.2 交叉验证法&#xff08;Cross Validation&#xff09;3.3 自助法&#xff08;Bootstrap&#xff09; 4 调参与最终模型5 结语 1 前言 欢迎来到蓝色是天的机器学习…

java八股文面试[java基础]——面向对象特点

三大特点&#xff1a; 封装 继承 多态 面试题&#xff1a;java如何实现多继承&#xff08;除了使用接口之外&#xff09; 实现多继承有三个方法&#xff1a; 多层继承内部类接口 参考 java实现多继承的三种方式 多层继承 ​如果要直接继承类&#xff0c;子类是不可以直接多…

微信小程序的汽车租赁系统的l9k0e

随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&#xf…

开源文库系统moredoc

什么是 moredoc &#xff1f; moredoc 中文名 魔豆文库&#xff0c;是基于 golang 开发的类似百度文库、新浪爱问文库的开源文库系统&#xff0c;支持 TXT、PDF、EPUB、MOBI、Office 等格式文档的在线预览与管理&#xff0c;为 dochub 文库(github, gitee &#xff09;的重构版…

民族传统文化分享系统uniapp 微信小程序

管理员、用户可通过Android系统手机打开系统&#xff0c;注册登录后可进行管理员后端&#xff1b;首页、个人中心、用户管理、知识分类管理、知识资源管理、用户分享管理、意见反馈、系统管理&#xff0c;用户前端&#xff1b;首页、知识资源、用户分享、我的等。 本系统的使用…

初探修模的三维模型OBJ格式轻量化压缩的遇到常见问题与处理方法

初探修模的三维模型OBJ格式轻量化压缩的遇到常见问题与处理方法 在对经过修模的三维模型进行OBJ格式轻量化压缩处理的过程中&#xff0c;可能会遇到一些常见问题。以下是一些常见问题以及相应的处理方法&#xff1a; 1、顶点丢失和形状变形&#xff1a;在减小顶点数量的过程中…

自己实现 SpringMVC 底层机制 系列之-实现任务阶段 8- 完成返回 JSON 格式数据-@ResponseBody

&#x1f600;前言 自己实现 SpringMVC 底层机制 系列之-实现任务阶段 8- 完成返回 JSON 格式数据-ResponseBody &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希望我的文章可以帮助到大家&#xff0…

大数据风控介绍

众所周知&#xff0c;金融是数据化程度最高的行业之一&#xff0c;也是人工智能和大数据技术重要的应用领域。随着大数据收集、存储、分析和模型技术日益成熟&#xff0c;大数据技术逐渐应用到金融风控的各个环节。个推作为专业的数据智能服务商&#xff0c;拥有海量数据资源&a…

Android项目如何上传Gitee仓库

前言 最近Android项目比较多&#xff0c;我都是把Android项目上传到Gitee中去&#xff0c;GitHub的话我用的少&#xff0c;可能我还是更喜欢Gitee吧&#xff0c;毕竟Gitee仓库用起来更加方便 一. 创建Gitee仓库 1. 先创建一个Gitee账号&#xff0c;然后登录上去 2. 创建Androi…

基于JSP+Servlet+mysql养老院管理系统

基于JSPServletmysql养老院管理系统 一、系统介绍二、功能展示四、其他系统实现五、获取源码 一、系统介绍 项目类型&#xff1a;Java web项目 项目名称&#xff1a;基于JSPServlet的养老院管理系统 [yanglaoyuan] 当前版本&#xff1a;V1.0.0版本 难度等级&#xff1a;✩✩点…

恒运资本分析:科技股有哪些股票?

跟着科技的不断进步&#xff0c;科技职业越来越遭到人们的重视。在股市中&#xff0c;出资科技股票已经成为人们赚取高额收益的一种方法。那么科技股有哪些值得出资的股票呢&#xff1f;本文将从多个角度剖析科技股。 一、美股科技股票 在美股商场中&#xff0c;科技股票一向以…

QIIME 2教程. 29补充资源SupplementaryResources(2023.5)

补充资源 Supplementary resources https://docs.qiime2.org/2023.5/supplementary-resources/ 教学内容 Educational content 以下资源对于了解有关微生物组分析和生物信息学的更多信息很有用&#xff1a; 应用生物信息学导论 An Introduction to Applied Bioinformatics http…

三维模型OBJ格式轻量化压缩处理的数据质量提升方法分析

三维模型OBJ格式轻量化压缩处理的数据质量提升方法分析 在三维模型的OBJ格式轻量化压缩处理过程中&#xff0c;除了减小文件大小和提高加载速度之外&#xff0c;我们也需要考虑如何提升数据质量。以下是几种常见的方法&#xff1a; 1、优化顶点数据&#xff1a;顶点数据是三维…

三层架构与MVC模式区别

三层架构 三层即 视图层、业务逻辑层、持久层&#xff08;数据访问层&#xff09; MVC模式 MVC 即 Model&#xff08;模型&#xff09;&#xff0c;View&#xff08;视图&#xff09;&#xff0c;Controller&#xff08;控制控制器&#xff09;。 --------------------------…

fastapi集成elastic-apm,实现性能监控

fastapi集成elastic-apm&#xff0c;实现性能监控 本文适用于 Starlette/FastAPIStarlette/FastAPI SupportInstallationSetupFastAPIUsagePerformance metricsIgnoring specific routes Supported Starlette and Python versions 具体使用示例官网的配置项介绍各语言框架集成e…