C语言之预处理器、文件操作

预处理

预处理器

  1. 预处理器:C语言在编译之前会使用预处理器处理代码;宏替换、文件包含、条件编译。
  2. 预处理指令:以#开头;预处理指令应该放在代码开头部分;都以#开头,指令前面可以有空格,#和指令之间也可以有,为了兼容老的编译器,一般不留空格。
  3. 预处理指令不需要分号作为结束符,指令结束是通过换行符来识别的。
  4. 预处理指令通常不能写在函数内部,有些编译器的扩展允许将预处理指令写在函数里。

宏定义

  1. 宏定义:用一个标识符(宏名称)来表示一个替换文本。
  2. 语法: #define  宏名称   替换文本
  3. 宏名称,一般大写字母表示,以便和变量区分。
  4. 替换文本:可以含任何字符,可以是字面量、表达式、if语句、函数等,预处理程序不会作检查,直接替换,如有错误,在编译已被宏展开后的源程序时发现。
  5. 宏定义嵌套:在宏定义的替换文本中可以使用已经定义的宏名,在宏展开时由预处理程序层层替换。
  6. 取消宏定义:#undef 命令。
  7. 带参数的宏定义:在宏定义中的称为形参,在宏调用中的称为实参,宏展开时用实参替换形参。
  8. 带参宏调用形式: 宏名 (实参列表)。
  9. 带参宏定义中,形参之间可以出现空格,宏名和形参列表之间不能出现空格。
  10. 带参宏定义中,形参不会分配内存,不必指明数据类型,在宏调用中,实参必须指明数据类型。
  11. 带参宏定义和函数的区别:
    1. 宏展开只是文本的替换,不会对表达式进行计算,宏在编译之前就被处理了,不参与编译,也不占用内存。
    2. 函数是一段可以重复使用的代码,会被编译,会分配内存,每次调用函数,就是执行这块内存中的代码。
#include <stdio.h>
// 带参数宏定义
// 预处理指令#代码,末尾不能有 分号
// 注意: 1. 宏定义的时候形参之间可以有空格
//        2. 宏名字与形参列表之间不能有空格
#define MAX(a, b) a > b ? a : b
#define SQUARE(x) x * x
int main() {
  
  printf("%d\n",MAX(10, 12));
  printf("%d\n",SQUARE(12));

  return 0;
}

文件包含

  1. #include 指令用于引入标准库头文件、自定义头文件和其他外部源代码文件。
  2. 一个源文件可以导入多个头文件,一个头文件可以被多个源文件导入。
  3. 头文件的扩展名都是 .h。
  4. 标准库头文件: #include <stdio.h> 
  5. 自定义头文件: #include "文件名.h"
  6. 相对路径:如果自定义的头文件在源文件的同级目录或在目录的下级目录,使用 ./ 开头的路径, ./ 可以省略;如果自定义的头文件在源文件所在目录的上级或更上级,使用 ../ 开头的路径。
  7. 绝对路径:从文件系统的盘符(Windows系统)或根目录(Linux系统、MacOS系统)开始,沿着文件系统的目录结构一直到达目标文件。

条件编译

#if

  1. #if ... #endif : 预处理器的条件判断,满足条件时,内部的行会被编译,否则被编译器忽略。
  2. #if后面的判断条件通常是一个表达式,如果表达式的值不等于0,表示判断为真,编译内部的语句,如果表达式的值等于0,表示为假,忽略内部的语句。
#include <stdio.h>
#if 1 
int a = 100;
double kill = 3.23;
char ch = 'a';
#endif
#if 1 - 1
可以作为注释
#endif
int main() {
  // if条件编译
  printf("%d %lf\n", a, kill);
  return 0;
}
  1. #if ... #else ... #endif:#if ...  #endif之间可以加入#else指令,用于指定判断条件不成立时,需要编译的语句。
#include <stdio.h>
#define OK 0
#if OK
int a = 10; 
double b = 2.43;
#else 
double PI = 3.14;
int arr[] = {10, 20, 30};
typedef struct {
  char *name;
} Students;
#endif
int main() {

  printf("%lf\n", PI);

  return 0;
}
  1. #if ... #elif ... #else ... #endif:如果有多个判断条件,可以加入#elif命令。
#include <stdio.h>

int main() {
#define OK 1
#if OK == 1
  printf("我叫 tom"); // 预处理指令再全局中不能打印输出,这能打印是编译器做的
#elif OK == 2
  printf("welcome");
#else
  printf("thank you");
#endif
  printf("Hello World!\n");

  return 0;
}

#ifdef / #if defined

  1. #ifdef ... #endif:判断某个宏是否定义过。
  2. #ifdef  与#if  defined 相同。
#include <stdio.h>
#include "./src/stdc89.h"
#include "./src/stdc89.h"
// 判断是否存在宏
#define INT
#ifdef INT 
int a = 1000;
#else 
int a = 10;
#endif


int main() {

  printf("%d\n", a);
  printf("%d\n", d);

  return 0;
}

#ifndef 

  1. 3ifndef‘...#endif指令跟#ifdef ... #endif 正好相反。用来判断如果某个宏没有被定义过。
#include <stdio.h>
#ifndef BOOL
#define BOOL 1
#endif
int main() {
  printf("%d\n", BOOL);
  return 0;
}

预处理命令总结:

指令

说明

#include

包含一个源代码文件

#define

定义宏

#undef

取消已定义的宏

#if

如果给定条件为真,则编译下面代码

#ifdef

如果宏已经定义,则编译下面代码

#ifndef

如果宏没有定义,则编译下面代码

#elif

如果前面的#if给定条件不为真,当前条件为真,则编译下面代码

#endif

结束一个#if……#else条件编译块

文件操作

  1. 文件基本介绍:文件最主要的作用就是保存文件。文件中数据的输入输出操作以 流的方式进行。
  2. 输入流:数据从数据源(文件、屏幕)到程序(内存)的传输路径。
  3. 输出流:数据从程序(内存)到数据源(文件、屏幕)的传输路径。

输入 & 输出

  1. 标准文件:以下的文件会在程序执行时自动打开,以便访问屏幕和键盘。

标准文件

文件指针

设备

标准输入

stdin

键盘

标准输出

stdout

屏幕

标准错误

stderr

屏幕

文件指针:访问文件的方式。

  1. getchar() 和 putchar() 函数:
    1. getchar()  :用于从标准输入流(键盘)读取一个字符,这个函数在同一时间内只会读取一个单一的字符。
      1. 函数原型:int getchar(void);
      2. 返回值:返回一个整数,表示读取的字符。
    2. putchar()  : 将一个字符写入到标准输出流(屏幕),在同一时间内只会输出一个单一的字符。
      1. 函数原型:int putchar(int character);
      2. 返回值:返回一个整数,是写入的字符的ASCII码值。
      3. 参数:character 是要写入的字符的ASCII码值。  
#include <stdio.h>

int main() {
  // 从键盘输入一个字符,用char类型变量存储
  char ch = getchar();
  // 输出打印字符
  putchar(ch);
  return 0;
}

2.gets()  和 puts()  函数

  1. gets()函数:  从标准输入流(键盘)读取一行文本,并将其存储到一个字符数组中,直到遇到换行符。
    1. 函数原型:char  *gets( char *str) 
    2. 返回值:返回一个指向存储在str中的字符串的指针。
    3. 参数:字符数组的指针,用于存储读取的输入数据。
  2. puts() 函数:将字符串输出到标准输出流(屏幕),并自动添加换行符,它接受一个字符串作为参数,然后将其显示到屏幕上。
    1. 函数原型:int puts(const char *str)
    2. 返回子:返回成功写入的字符数,如果写入失败或出现错误,返回特殊值 EOF(EOF是一个定义在stdio.h头文件中的常量,值通常为 -1);
    3. 参数: str 是要输出的字符串。
#include <stdio.h>

int main() {
  // 定义字符数组:用来保存用户从键盘输入的数据
  char buffer[100];
  // 输入
  gets(buffer);
  // 输出
  puts(buffer);

  return 0;
}

文件读写

打开文件

  1. fopen() 函数:创建一个新的文件或者打开一个已有的文件。函数位于stdio.h 头文件中。
    1. 函数原型: FILE *fopen(const char *filename, const char *mode)
    2. 返回值:返回一个指向FILE结构的指针,该结构表示文件流,使用这个指针来及逆行文件的读取和写入操作。如果打开失败,返回一个空指针(NULL)。
    3. 参数:
      1. filename是一个以字符串形式指定的文件,表示要打开的文件的名称。可以包括文件路径和文件名;
      2. mode是一个以字符串形式指定的打开模式。

模式

描述

r

只读模式

打开一个已有的文本文件,只允许读取文件。

w

只写模式

打开一个文本文件,从头写入文件。如果文件不存在,则会创建一个新文件并写入;如果文件存在,则清空文件并从头写入。

a

追加模式

打开一个文本文件,追加写入文件。如果文件不存在,则会创建一个新文件并写入;如果文件存在,在已有内容后面追加写入。

rb

只读二进制模式

打开一个已有的二进制文件,只允许读取文件。

wb

只写二进制模式

打开一个二进制文件,从头写入文件。如果文件不存在,则会创建一个新文件并写入;如果文件存在,则清空文件并从头写入。

ab

追加二进制模式

打开一个二进制文件,追加写入文件。如果文件不存在,则会创建一个新文件并写入;如果文件存在,在已有内容后面追加写入。

r+

读写模式

打开一个文本文件,允许读写文件。

w+

读写模式

打开一个文本文件,从头读写文件。如果文件不存在,则会创建一个新文件并读写;如果文件存在,则清空文件并从头读写。

a+

读写模式

打开一个文本文件,读取或追加写入文件。如果文件不存在,则会创建一个新文件并读写;如果文件存在,读取或在已有内容后面追加写入。

rb+

读写二进制模式

打开一个二进制文件,允许读写文件。

r+b

wb+

读写二进制模式

打开一个二进制文件,从头读写文件。如果文件不存在,则会创建一个新文件并读写;如果文件存在,则清空文件并从头读写。

w+b

ab+

读写二进制模式

打开一个二进制文件,读取或追加写入文件。如果文件不存在,则会创建一个新文件并读写;如果文件存在,读取或在已有内容后面追加写入。

a+b

关闭文件

  1. fclose() 函数:关闭文件,也位于stdio.h 头文件中。
  2. 函数原型: int fclose(FILE *stream)
  3. 返回值:返回一个整数值,通常为零(0),表示关闭操作成功,如果关闭失败,返回特殊值EOF;
  4. 参数:stream是一个指向FILE结构的指针,表示要关闭的文件流。

写入文件

fputc()
  1. fputc() 函数:逐字符写入文件,位于stdio.h 头文件中。
  2. 函数原型:int fputc(int character, FILE *stream)
  3. 返回值:返回一个整数值,通常是写入的字符的ASCII码值,如果写入成功,返回的值与输入的character值相同,如果失败,返回特殊值EOF;
  4. 参数:
    1. character:要写入的字符,以整数的形式表示,即字符的ASCII码值。
    2. stream:是一个指向FILE结构的指针,表示要写入字符的文件流。
#include <stdio.h>

int main() {
  // C语言中操作文件
  // 第一个参数:文件名字[字符串即可] 第二个参数:模式 demo
  FILE *file = fopen("a.txt", "a"); // a 追加模式
  // 判断文件是否创建成功
  if (file != NULL) {
    // 写入字符
    for (int i = 0; i < 10; i++) {
      fputc('a', file);
    }
  }
  // 关闭文件
  fclose(file);

  return 0;
}
fputs()
  1. fputs()函数:将字符串写入文件,位于stdio.h头文件中。
  2. 函数原型:int fputs(const char *str, FILE *stream)
  3. 返回值:返回一个整数值,如果写入成功,返回非负整数(通常是写入的字符数),否则返回特殊值EOF;
  4. 参数:
    1. str 是要写入的字符串,通常以const char *指针的形式传递。
    2. stream是指向输出流的指针,通常是文件指针。
#include <stdio.h>

int main() {
  // 文件操作
  FILE *file = fopen("b.txt", "a");
  if (file != NULL) {
    char *str = "我成功的写入字符串!";
    fputs(str, file);
  }
  fclose(file);

  return 0;
}
fprintf()
  1. fprintf()函数:格式化写入问价,位于stdio.h头文件中。
  2. 函数原型:int fprintf( FILE *stream, const char *format, ...)
  3. 返回值:返回一个整数值,如果写入成功,返回非负整数(通常是写入的字符数),否则返回特殊值EOF;
  4. 参数:
    1. stream是一个指向FILE结构的指针,表示要写入的文件流。
    2. format是一个格式化字符串,类似于printf()函数中的格式化字符串。
    3. .... 表示可变数量的参数,根据格式化字符串中的格式占位符对应。
#include <stdio.h>

int main() {
  FILE *file = fopen("c.txt", "a");
  if (file != NULL) {
    fprintf(file, "我的%s", "宝贝");
  }
  fclose(file);

  return 0;
}

读取文件

fgetc()
  1. fgetc() 函数:从文件中逐字符读取,位于stdio.h 头文件中。
  2. 函数原型:int fgetc(FILE *stream)
  3. 返回值:如果读取成功,返回读取字符的ASCII码值(0-255之间的整数),如果到达文件结束或发生错误,返回特殊值EOF。
  4. 参数:stream是一个指向FILE结构的指针,表示要写入字符的文件流。
fgets()
  1. fgets():从文件中逐行读取,遇到换行符读取结束,读取的内容包含换行符,位于stdio.h头文件中。
  2. 函数原型:char *fgets(char * str , int  num , FILE *stream)
  3. 返回值:如果读取成功,返回指向str的指针,如果到达文件结束或发生错误,返回一个空指针(NULL);
  4. 参数:
    1. str是一个指向字符数组的指针,用于存储读取的字符串;
    2. num是要读取的最大字符数(包括字符串终止符 \0),通常是str 的长度;
    3. stream是一个文件流,通常是标准输入流(stdin)或其他文件流,用于指定从哪里读取数据。
fscanf()
  1. fscanf()函数:从文件中解析数据并存储到变量中,使用空白字符(空格、制表符、换行符等)分隔内容赋值给不同的变量,该函数位于标准库的stdio.h头文件中。
  2. 函数原型:int fscanf(FILE *stream, const char *format, ....)
  3. 返回值:返回成功读取的分配的参数数目,如果没有成功读取任何参数,返回0,如果读取过程中发生错误,返回特殊值EOF;
  4. 参数:
    1. stream:一个指向FILE结构的指针,表示要从中读取数据的文件流。
    2. format:是一个格式化字符串,类似于prinft()函数中的格式化字符串。
    3. ....表示可变数量的参数,根据格式化字符串中的格式指定要存储数据的变量。
#include <stdio.h>

int main() {
  // 读取模式
  FILE *file = fopen("d.txt", "r");
  if (file != NULL) {
    // char ch = fgetc(file);
    // printf("%c\n",ch); // 读取一个字符
    // char ch1 = fgetc(file);
    // printf("%c\n", ch1); // 读取一个字符
    // char buffer[5];
    // fgets(buffer, 5, file); // 将字符数组的 结尾 \0 也计算进去
    // printf("%s\n", buffer);
    char buffer1[100];
    fscanf(file, "%s", buffer1); // buffer 字符数组不用 &
    printf("%s\n", buffer1);
  }
  fclose(file);
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值