C语法Day6-文件
# 内存管理
# 说明
内存的分配和管理函数
1、calloc 内存分配连续空间
void *calloc(int num, int size);
在内存中动态地分配 num 个长度为 size 的连续空间
并初始化内存数据0
2、malloc 堆区分配
void *malloc(int num);
在堆区分配一块指定大小的内存空间
这块内存空间在函数执行完成后不会被初始化,它们的值是未知的(错误访问地址会导致异常)
3、realloc 重新分配内存大小
void *realloc(void *address, int newsize);
重新分配内存空间大小为 newsize。
4、free 释放对象内存
void free(void *address);
该函数释放 address 所指向的内存块
释放的是动态分配的内存空间。
注意:
void * 类型表示未确定类型的指针。
void * 类型可以通过类型转换强制转换为任何其它类型的指针。
# 分配内存
// 1、分配固定内存大小,指定数组大小(不指定大小就会在实现时根据数据占用空间分配)
// 预先定义了大小的数组,一旦定义则无法改变大小,实际使用很少就会造成资源浪费
char name[200];
strcpy(name, "name1"); // 只能存储少于200的数据
// 2、动态分配内存
// 定义一个指针,预先不知道需要存储的文本长度
char *description;
description = (char *)malloc(50 * sizeof(char));
// 或者
description = (char *)calloc(50, sizeof(char));
# 重置内存
重新分配已经分配过大小,由50增加到100:
description = (char *)realloc(description, 100 * sizeof(char));
# 释放内存
当页面退出或者在不需要该内存数据时,应该调用函数 free() 来释放内存
free(description);
# 程序入口参数
程序启动前接受从程序之外传入参数:int main(int argc, char *argv[])
argv[] 这些值被称为命令行参数
#include <stdio.h>
int main(int argc, char *argv[])
{
for (int i = 0; i < argc; ++i)
{
printf("程序入口第%d个参数: %s\n", i, argv[i]);
}
return 0;
}
1、不传任何参数,直接执行:
$ ./mainarg4
程序入口第0个参数: ./mainarg
2、 传1个参数
$ ./mainarg4 name
程序入口第0个参数: ./mainarg4
程序入口第1个参数: name
3、 传2个参数
$ ./mainarg4 name age
程序入口第0个参数: ./mainarg4
程序入口第1个参数: name
程序入口第2个参数: age
总结:
argv[0] 默认存储程序的名称,不需要指定
从argv[1] 开始才是用户指定的参数。
很明显,传入一个参数,那么 argc = 2
参数包含空格时,这个参数需要放置在双引号 "" 或单引号 '' 内部
# 输入输出
前面讲到程序启动入口可以添加参数,但是程序执行过程中有时候也需要用户输入操作
这个时候就需要输入输出函数,用于用户操作和程序对接
# 1、getchar() & putchar() 单个字符输入输出函数
int getchar(void)
函数从屏幕读取下一个可用的字符,并把它返回为一个整数。
这个函数在同一个时间内只会读取一个单一的字符。
您可以在循环内使用这个方法,以便从屏幕上读取多个字符。
int putchar(int c)
函数把字符输出到屏幕上,并返回相同的字符。
这个函数在同一个时间内只会输出一个单一的字符。
您可以在循环内使用这个方法,以便在屏幕上输出多个字符。
#include <stdio.h>
int main( )
{
int c;
printf("请输入一个字符 :");
c = getchar(); // 获取输入的 字符串,回车
putchar( c ); // 只打印输入的单个字符
printf( "\n");
return 0;
}
# 2、fgets() & puts() 读取整行数据
fgets 函数从 stdin 读取一行到 s 所指向的缓冲区,直到一个终止符或 EOF。
int puts(const char *s) 函数把字符串 s 和一个尾随的换行符写入到 stdout。
# 实例
#include <stdio.h>
int main( )
{
char str[100];
printf("请输入:");
// 也可以使用 gets(str); 但是因为不知道缓冲区大小,所以使用gets函数不安全,使用fgets
fgets(str, (sizeof str / sizeof str[0]), stdin);
puts( str );
return 0;
}
# 3、scanf() 和 printf() 函数
int scanf(const char *format, ...)
获取输入数据,并可以指定数据格式
int printf(const char *format, ...)
输出数据,并可以指定数据格式
format 指定 %s、%d、%c、%f 等来输出或读取字符串、整数、字符或浮点数。
其他格式可以查看这些函数的参考手册。
#include <stdio.h>
int main()
{
int age;
printf("请输入年龄: ");
scanf("%d",&age); // 键盘输入浮点型数据
printf("您的年龄 = %d \n", age);
return 0;
}
显示如下:
$ ./main
请输入年龄: 17
您的年龄 = 17
⚠️ 您输入的数据应该和格式相同,假如我们输入不匹配格式呢?
比如int格式输入字符串:
$ ./main
请输入年龄: 你好
您的年龄 = 254025824
显然和预期不符,应该这样写:
#include <stdio.h>
int main()
{
char psw[7];
printf("请输入6位密码进行验证: ");
scanf("%s",psw);
printf("您的密码 = %s \n", psw);
return 0;
}
结果:
$ ./main
请输入6位密码进行验证: abc123
您的密码 = abc123
# 文件读写
文件,无论它是文本文件还是二进制文件,都是一系列的字节
前面介绍了输入输出,场景是用户临时输入的情况,比如验证时输入密码
现在介绍如何从文件中读取数据
示例:
当前目录新建文件 ming.txt :
我叫小明 今年5岁
来自上海
读取文件main.c
#include <stdio.h>
int main()
{
FILE *fp = NULL;
char buff[255];
fp = fopen("ming.txt", "r");
// 1、读取第一行内容到空格处
fscanf(fp, "%s", buff);
printf("1: %s\n", buff );
// 读取第一行空格以后内容
fgets(buff, 255, (FILE*)fp);
printf("2: %s\n", buff );
// 读取第二行
fgets(buff, 255, (FILE*)fp);
printf("3: %s\n", buff );
fclose(fp);
}
打印结果:
$ ./main
1: 我叫小明
2: 今年5岁
3: 来自上海
# 打开文件
文件类型FILE,可以使用 fopen( ) 函数来打开一个已有的文件
FILE *fopen(const char *filename, const char *mode );
第一个参数filename 是指文件名称,字符串
第二个参数是访问模式 mode 的值:
模式 | 描述 |
---|---|
r | 打开一个已有的文本文件,允许读取文件。 |
w | 打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。 |
a | 打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。 |
r+ | 打开一个文本文件,允许读写文件。 |
w+ | 打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。 |
a+ | 打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。 |
如果处理的是二进制文件,则需使用下面的访问模式来取代上面的访问模式:
"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"
# 关闭文件
为了关闭文件,请使用 fclose( ) 函数。函数的原型如下:
int fclose( FILE *fp );
如果成功关闭文件,fclose( ) 函数返回零
如果关闭文件时发生错误,函数返回 EOF。
这个函数实际上,会清空缓冲区中的数据,关闭文件,并释放用于该文件的所有内存。
EOF 是一个定义在头文件 stdio.h 中的常量。
C 标准库提供了各种函数来按字符或者以固定长度字符串的形式读写文件。
# 写入文件
下面是把字符写入到流中的最简单的函数:
int fputc( int c, FILE *fp );
或者
int fprintf(FILE \*fp,const char \*format, ...)
# 示例
#include <stdio.h>
int main()
{
FILE *fp = NULL;
fp = fopen("ming.txt", "a+"); // 文件尾部添加内容
// 添加一行内容
fprintf(fp, "来自上海浦东新区\n");
// 添加第二行内容
fputs("读幼儿园\n", fp);
fclose(fp);
}
执行后 ming.txt :
我叫小明 今年5岁
来自上海
来自上海浦东新区
读幼儿园
# 二进制 I/O 函数
下面两个函数用于二进制输入和输出:
size_t fread(void *ptr, size_t size_of_elements,
size_t number_of_elements, FILE *a_file);
size_t fwrite(const void *ptr, size_t size_of_elements,
size_t number_of_elements, FILE *a_file);
这两个函数都是用于存储块的读写 - 通常是数组或结构体。