C语言文件操作

一.提前说明

说明:我们对文件操作相信并不陌生,但是由于平时课程的关系,文件操作使用也比较少,知识点并不是很多,但容易忘记,忘记了某一天再使用又要重新学,因此我打算写一篇博客,记录C语言文件操作的知识点,巩固知识点,也以便以后回忆。

我们对文件的概念已经非常熟悉了,比如常见的 Word 文档、txt 文件、源文件等。文件是数据源的一种,最主要的作用是保存数据。

二.C语言文件操作

在操作系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。例如:

  • 通常把显示器称为标准输出文件,printf 就是向这个文件输出数据;
  • 通常把键盘称为标准输入文件,scanf 就是从这个文件读取数据。

1.常见硬件设备对应的文件

在C语言中,常见硬件设备对应的文件包括:

  1. 标准输入、输出和错误设备:
    • 标准输入:stdin(通常是键盘)
    • 标准输出:stdout(通常是屏幕)
    • 错误输出:stderr(通常是屏幕)
  2. 硬盘、磁盘等存储设备:
    • 文件:用文件名来表示
    • 硬盘:/dev/hd[a-d][1-16] 或 /dev/sd[a-p][1-16]
  3. 网络设备:
    • 网络接口卡:/dev/net/tun
  4. 串口设备:
    • 串口设备:/dev/ttyS[0-3] (COM1-COM4)
    • USB串口设备:/dev/ttyUSB[0-3]
  5. 并口设备:
    • 并口设备:/dev/lp[0-2]

2.文件操作流程

操作文件的正确流程为:打开文件 --> 读写(操作)文件 --> 关闭文件。文件在进行读写操作之前要先打开,使用完毕要关闭。

所谓打开文件,就是获取文件的有关信息,例如文件名、文件状态、当前读写位置等,这些信息会被保存到一个 FILE 类型的结构体变量中。关闭文件就是断开与文件之间的联系,释放结构体变量,同时禁止再对该文件进行操作。

在C语言中,文件有多种读写方式,可以一个字符一个字符地读取,也可以读取一整行,还可以读取若干个字节。文件的读写位置也非常灵活,可以从文件开头读取,也可以从中间位置读取。

3.文件流

所有的文件(保存在磁盘)都要载入内存才能处理,所有的数据必须写入文件(磁盘)才不会丢失。数据在文件和内存之间传递的过程叫做文件流,类似水从一个地方流动到另一个地方。数据从文件复制到内存的过程叫做输入流,从内存保存到文件的过程叫做输出流

文件是数据源的一种,除了文件,还有数据库、网络、键盘等;数据传递到内存也就是保存到C语言的变量(例如整数、字符串、数组、缓冲区等)。我们把数据在数据源和程序(内存)之间传递的过程叫做数据流(Data Stream)。相应的,数据从数据源到程序(内存)的过程叫做输入流(Input Stream),从程序(内存)到数据源的过程叫做输出流(Output Stream)。

输入输出(Input output,IO)是指程序(内存)与外部设备(键盘、显示器、磁盘、其他计算机等)进行交互的操作。几乎所有的程序都有输入与输出操作,如从键盘上读取数据,从本地或网络上的文件读取数据或写入数据等。通过输入和输出操作可以从外界接收信息,或者是把信息传递给外界。

我们可以说,打开文件就是打开了一个流。

三.文件操作三剑客

上面已经知道,文件的操作流程为:打开文件 --> 读写(操作)文件 --> 关闭文件。这部分我们就按照这个流程来解释对应的函数。

1.打开文件

在C语言中,操作文件之前必须先打开文件;所谓“打开文件”,就是让程序和文件建立连接的过程。

fopen() 是一个 C 语言标准库函数,用于打开文件,并返回一个文件指针。其语法如下:

FILE *fopen(const char *filename, const char *mode);

其中,filename 参数是要打开的文件名,可以包含路径信息;mode 参数是以哪种方式打开文件,常见的有以下模式:

  • "r":以只读方式打开文件,该文件必须存在。
  • "w":以写方式打开文件,如果文件不存在则创建新文件,如果文件已经存在则清空文件内容。
  • "a":以追加方式打开文件,在文件末尾添加数据,如果文件不存在则创建新文件。
  • "r+":以读写方式打开文件,该文件必须存在。
  • "w+":以读写方式打开文件,如果文件不存在则创建新文件,如果文件已经存在则清空文件内容。
  • "a+":以读写方式打开文件,在文件末尾添加数据,如果文件不存在则创建新文件。

如果打开文件成功,则返回一个指向 FILE 类型结构体的指针;否则返回 NULL

下面是一个打开文件的例子:

FILE *fp;
if( (fp=fopen("D:\\demo.txt","rb")) == NULL ){
    printf("Fail to open file!\n");
    exit(0);                       //退出程序(结束程序)
}

2.关闭文件

fclose() 函数用于关闭一个打开的文件。它的语法如下:

int fclose(FILE *stream);

其中,stream 是指向 FILE 对象的指针。如果成功退出,则返回 0 ,否则返回 EOF。

3.读写文件

在C语言中,读写文件比较灵活,既可以每次读写一个字符,也可以读写一个字符串,甚至是任意字节的数据(数据块)。本节介绍以字符形式读写文件。以字符形式读写文件时,每次可以从文件中读取一个字符,或者向文件中写入一个字符。主要使用两个函数,分别是 fgetc() 和 fputc()。

fgetc() 是 C 语言标准库中的一个函数,用于从指定的文件流读取一个字符。它的语法如下:

int fgetc(FILE *stream);

其中,stream 参数是一个 FILE 类型的指针,指向要读取的文件流。函数返回值为读取的字符(作为 int 类型返回)或者在遇到文件结束符(EOF)时返回 EOF。

由于它每次读取的都是一个字符,所以我们可以通过以下代码逐个字符读取一个文件:

    //每次读取一个字节,直到读取完毕
    while( (ch=fgetc(fp)) != EOF ){
        putchar(ch);
    }
    putchar('\n');  //输出换行符

fputc() 函数用于将一个字符写入指定的文件流中。其语法如下:

int fputc(int ch, FILE *stream);

其中,ch 表示要写入的字符,stream 表示文件指针。函数返回值为写入的字符,如果发生错误则返回 EOF(-1)。

例如,以下代码将字符 'a' 写入文件:

#include <stdio.h>

int main() {
    char ch = 'a';
    FILE *fp = fopen("file.txt", "w");
    if (fp != NULL) {
        fputc(ch, fp);
        fclose(fp);
    }
    return 0;
}

这个程序创建了一个名为 file.txt 的新文件,并向其中写入了字符 'a'。注意,打开文件时使用的模式为 "w",表示写操作。如果文件已存在,则会被截断为零长度,即清空文件内容。

那么我们可以通过以下代码实现逐个字符输入文件:

    char ch;
    printf("Input a string:\n");
    //每次从键盘读取一个字符并写入文件
    while ( (ch=getchar()) != '\n' ){
        fputc(ch,fp);
    }

4.完整流程实现

#include <stdio.h>

int main() {
    FILE *fp_in, *fp_out;
    int ch;

    // 打开输入文件
    fp_in = fopen("input.txt", "r");
    if (fp_in == NULL) {
        printf("Failed to open input.txt\n");
        return 1;
    }

    // 打开输出文件
    fp_out = fopen("output.txt", "w");
    if (fp_out == NULL) {
        printf("Failed to open output.txt\n");
        fclose(fp_in);
        return 1;
    }

    // 逐个字符地读取输入文件,并将其写入输出文件
    while ((ch = fgetc(fp_in)) != EOF) {
        fputc(ch, fp_out);
    }

    // 关闭文件指针
    fclose(fp_in);
    fclose(fp_out);

    return 0;
}

这个程序将打开名为 input.txt 的输入文件和名为 output.txt 的输出文件,然后逐个字符地从输入文件中读取字符,并将其写入输出文件中,最后关闭文件指针。

需要注意的是,在使用 fgetc() 函数和 fputc() 函数时,如果文件操作失败(例如文件无法打开、读写权限不足等),函数会返回相应的错误代码,此时应该及时处理错误并关闭文件指针。

四.其他读写方式

1.以字符串的形式读写

fgets() 是一个用于从标准输入流读取字符串的 C 语言函数。它的用法如下:

char *fgets(char *str, int n, FILE *stream);

其中,参数 str 是一个指向字符数组的指针,用来存储读取到的字符串;参数 n 是要读取的最大字符数(包括最后的空字符);参数 stream 是要读取的文件指针,通常使用 stdin 表示标准输入流。

fgets() 函数会从给定的文件指针读取字符,直到遇到换行符或者读取了 n-1 个字符(包括空字符)。如果成功读取了字符,则将它们存储在 str 所指向的字符数组中,并在末尾添加一个空字符 ‘\0’,以表示字符串的结束。

如果无法读取任何字符(例如已经到达文件末尾),则返回 NULL,否则返回 str 所指向的字符数组的指针。

注意,读取到的字符串会在末尾自动添加 ‘\0’,n 个字符也包括 ‘\0’。也就是说,实际只读取到了 n-1 个字符,如果希望读取 100 个字符,n 的值应该为 101。

例如:


#define N 101
char str[N];
FILE *fp = fopen("D:\\demo.txt", "r");
fgets(str, N, fp);

表示从 D:\demo.txt 中读取 100 个字符,并保存到字符数组 str 中。

需要重点说明的是,在读取到 n-1 个字符之前如果出现了换行,或者读到了文件末尾,则读取结束。这就意味着,不管 n 的值多大,fgets() 最多只能读取一行数据,不能跨行。在C语言中,没有按行读取文件的函数,我们可以借助 fgets(),将 n 的值设置地足够大,每次就可以读取到一行数据。

fputs() 是一个 C 语言标准库函数,用于将字符串写入到文件中。它的函数声明如下:

int fputs(const char *str, FILE *stream);

其中 str 参数是要写入的字符串,stream 参数是要写入的文件指针。如果成功写入,该函数会返回一个非负整数,否则返回 EOF

fputs() 函数会将给定的字符串作为一个整体写入到文件中,不包括字符串结尾处的空字符 ‘\0’。与 fprintf()printf() 不同,fputs() 不会自动在输出的字符串末尾添加换行符。

这里要想写入的字符串是从文本末尾开始,就得注意你的文件打开方式。

例如这里以追加写的方式,读取一个文件并编写:

#include<stdio.h>
int main(){
    FILE *fp;
    char str[102] = {0}, strTemp[100];
    if( (fp=fopen("D:\\demo.txt", "at+")) == NULL ){
        puts("Fail to open file!");
        exit(0);
    }
    printf("Input a string:");
    gets(strTemp);
    strcat(str, "\n");
    strcat(str, strTemp);
    fputs(str, fp);
    fclose(fp);
    return 0;
}

2.以数据块的形式读写

fgets() 有局限性,每次最多只能从文件中读取一行内容,因为 fgets() 遇到换行符就结束读取。如果希望读取多行内容,需要使用 fread() 函数;相应地写入函数为 fwrite()。

fread() 是 C 语言标准库中的一个函数,用于从文件中读取数据。它的函数声明如下:

size_t fread(void *ptr, size_t size, size_t count, FILE *stream);

其中各个参数的含义如下:

  • ptr:指向要读取数据的缓冲区。
  • size:每个数据块的字节数。
  • count:要读取的数据块数量。
  • stream:指向要读取的文件或流。

该函数会尝试从指定的文件中读取 count 个数据块,每个数据块的大小为 size。读取到的数据将存储到缓冲区 ptr 中。成功读取的数据块数量将作为函数返回值返回,如果出现错误或到达了文件末尾,则返回值可能小于 count

需要特别注意的是,在使用 fread() 函数时,应该确保缓冲区大小足够容纳要读取的数据,以避免发生缓冲区溢出等问题。

fwrite() 是 C 语言标准库中的一个函数,用于向文件中写入数据。它的函数声明如下:

size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);

其中各个参数的含义如下:

  • ptr:指向要写入数据的缓冲区。
  • size:每个数据块的字节数。
  • count:要写入的数据块数量。
  • stream:指向要写入的文件或流。

该函数会尝试向指定的文件中写入 count 个数据块,每个数据块的大小为 size 字节。待写入的数据存储在缓冲区 ptr 中。成功写入的数据块数量将作为函数返回值返回,如果出现错误,则返回值可能小于 count

需要特别注意的是,在使用 fwrite() 函数时,应该确保缓冲区大小足够容纳要写入的数据,以避免发生缓冲区溢出等问题。

以下是 fread()fwrite() 函数读写文本文件的一个示例:

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

int main()
{
    FILE *fp = fopen("file.txt", "w");
    if (fp == NULL) {
        perror("Failed to open file");
        return -1;
    }

    const char *str = "Hello, world!";
    fwrite(str, sizeof(char), strlen(str), fp);

    fclose(fp);

    fp = fopen("file.txt", "r");
    if (fp == NULL) {
        perror("Failed to open file");
        return -1;
    }

    fseek(fp, 0L, SEEK_END);
    long int size = ftell(fp);
    rewind(fp);

    char *buffer = malloc(size + 1);
    fread(buffer, sizeof(char), size, fp);
    buffer[size] = '\0';

    printf("%s\n", buffer);

    free(buffer);
    fclose(fp);

    return 0;
}

在这个示例中,我们首先以只写模式打开名为 file.txt 的文本文件,并使用 fwrite() 函数将字符串 “Hello, world!” 写入到文件中。然后,我们再次打开同一个文件,并使用 fread() 函数读取文件内容。最后,我们输出读取到的文件内容并释放缓冲区,关闭文件句柄。

3.格式化读写文件

fscanf()和fprintf()函数是C语言中常用的文件格式化读写函数。

fprintf()函数可以将特定格式的数据写入文件中。它的原型为:

Copy Codeint fprintf(FILE *stream, const char *format, ...)

其中,第一个参数是指向要写入的文件的指针,第二个参数是格式化字符串,后面可以跟上要写入的数据。

例如,下面的代码将字符串和整数分别以特定格式写入文件中:

#include <stdio.h>

int main() {
    FILE *fp = fopen("example.txt", "w");
    char str[] = "Hello World";
    int num = 1234;
    fprintf(fp, "String: %s, Number: %d\n", str, num);
    fclose(fp);
    return 0;
}

而fscanf()函数则可以从文件中读取特定格式的数据。它的原型为:

int fscanf(FILE *stream, const char *format, ...)

其中,第一个参数是指向要读取的文件的指针,第二个参数是格式化字符串,后面可以跟上要读取的变量名。

例如,下面的代码从文件中读取字符串和整数,并按照特定格式进行解析:

#include <stdio.h>

int main() {
    FILE *fp = fopen("example.txt", "r");
    char str[20];
    int num;
    fscanf(fp, "String: %s, Number: %d", str, &num);
    printf("String: %s, Number: %d\n", str, num);
    fclose(fp);
    return 0;
}

需要注意的是,使用fscanf()和fprintf()函数进行文件格式化读写时,需要保证读写数据的格式和数量与指定的格式字符串一致,否则可能会导致读写错误。

4.随机读写

前面介绍的文件读写函数都是顺序读写,即读写文件只能从头开始,依次读写各个数据。但在实际开发中经常需要读写文件的中间部分,要解决这个问题,就得先移动文件内部的位置指针,再进行读写。这种读写方式称为随机读写,也就是说从文件的任意位置开始读写。

移动文件内部位置指针的函数主要有两个,即 rewind() 和 fseek()。

rewind() 用来将位置指针移动到文件开头,前面已经多次使用过,它的原型为:

void rewind ( FILE *fp );

fseek() 用来将位置指针移动到任意位置,它的原型为:

int fseek ( FILE *fp, long offset, int origin );c

参数说明:

  1. fp 为文件指针,也就是被移动的文件。

  2. offset 为偏移量,也就是要移动的字节数。之所以为 long 类型,是希望移动的范围更大,能处理的文件更大。offset 为正时,向后移动;offset 为负时,向前移动。

  3. origin 为起始位置,也就是从何处开始计算偏移量。C语言规定的起始位置有三种,分别为文件开头、当前位置和文件末尾,每个位置都用对应的常量来表示:

起始点常量名常量值
文件开头SEEK_SET0
当前位置SEEK_CUR1
文件末尾SEEK_END2

在移动位置指针之后,就可以用前面介绍的任何一种读写函数进行读写了。

五.补充知识点

1.文本文件与二进制文件

文本文件和二进制文件是两种不同类型的文件,它们之间的主要区别在于数据的存储方式和处理方式。

文本文件是一种只包含文本数据的文件,其中的每个字符都按照某种编码格式(如 ASCII 或 UTF-8)被存储为一个字节序列。文本文件通常用于存储简单的文本信息,例如程序源代码、配置文件、日志文件等。由于文本文件中只包含文本数据,因此可以通过普通的文本编辑器打开和编辑。

二进制文件则是一种包含非文本数据的文件,其中的数据可以是任何形式的二进制数据,包括图像、音频、视频、压缩文件等。二进制文件通常采用特定的格式来存储数据,这些格式往往是由厂商或标准委员会定义的。由于二进制文件中的数据通常不是以文本形式存储的,因此无法使用普通的文本编辑器直接打开和编辑。

由于文本文件和二进制文件的存储方式和处理方式不同,因此在进行文件读写操作时需要使用不同的函数和方法。例如,对于文本文件,可以使用 C 语言中的 fputc() 和 fgets() 等函数进行读写;而对于二进制文件,则需要使用 fread() 和 fwrite() 等函数进行读写。

2.EOF说明

EOF 本来表示文件末尾,意味着读取结束,但是很多函数在读取出错时也返回 EOF,那么当返回 EOF 时,到底是文件读取完毕了还是读取出错了?我们可以借助 stdio.h 中的两个函数来判断,分别是 feof() 和 ferror()。

feof() 函数用来判断文件内部指针是否指向了文件末尾,它的原型是:

int feof ( FILE * fp );

当指向文件末尾时返回非零值,否则返回零值。

ferror() 函数用来判断文件操作是否出错,它的原型是:

int ferror ( FILE *fp );

出错时返回非零值,否则返回零值。

3. strcat()函数

strcat() 是一个 C 语言字符串库函数,用于将两个字符串拼接在一起。它的函数声明如下:

char *strcat(char *dest, const char *src);

其中 dest 参数是目标字符串,也就是要将源字符串 src 添加到其后面的字符串。注意,目标字符串 dest 必须具有足够的空间来容纳源字符串 src

strcat() 函数会将源字符串 src 中的字符依次添加到目标字符串 dest 的末尾,并在最后一个字符之后添加一个空字符 ‘\0’。如果成功拼接了两个字符串,则返回指向目标字符串 dest 的指针。

4. fread() 和 fwrite() 补充

注意看这个两个函数的语法声明,所以我们不能用int类型变量接收它的返回值。size_t 是在 stdio.h 和 stdlib.h 头文件中使用 typedef 定义的数据类型,表示无符号整数,也即非负数,常用来表示数量。

返回值:返回成功读写的块数,也即 count。如果返回值小于 count:

  • 对于 fwrite() 来说,肯定发生了写入错误,可以用 ferror() 函数检测。
  • 对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror() 或 feof() 检测。

5.获取文件长度

ftell() 函数用来获取文件内部指针(位置指针)距离文件开头的字节数,它的原型为:

long int ftell ( FILE * fp );

注意:fp 要以二进制方式打开,如果以文本方式打开,函数的返回值可能没有意义。

先使用 fseek() 将文件内部指针定位到文件末尾,再使用 ftell() 返回内部指针距离文件开头的字节数,这个返回值就等于文件的大小。请看下面的代码:

long fsize(FILE *fp){    
    fseek(fp, 0, SEEK_END);    
    return ftell(fp);
}

6.实现逐行读取

#include <stdio.h>#include <stdlib.h>#include <time.h>
 #define MAX_SIZE 100 //学生最大个数
 typedef struct {
    char group[10];
    char name[20];
    char studentId[20];
    char class;} Person;
 int main() {
    FILE *file = fopen("example.txt", "r");
    if (file == NULL) {
        printf("Failed to open the file.\n");
        return 1;
    }
 
    Person student[MAX_SIZE];
    int numPeople = 0;
 
    char line[100];
    while (fgets(line, sizeof(line), file)) {
        sscanf(line, "%s %s %s %s", &student[numPeople].group, &student[numPeople].name, &student[numPeople].studentId,
               &student[numPeople].class);
        numPeople++;
    }
    fclose(file);
 
    int a;
    srand((unsigned)time(NULL));
    a = rand() % 44 + 1;
    while( a==9 || a==10){
        printf("该同学不存在");
    }
    printf("Num %d:\n", a );
    printf("Name: %s\n", student[a-1].name);
    printf("Group: %s\n", student[a-1].group);
    printf("Student ID: %s\n", student[a-1].studentId);
    printf("\n");
 }

六.总结

相信大家也知道C语言的底层性,相对于其他语言来说,C语言的许多功能需要自定义函数实现,这里我们学习文件操作后,可以自定义封装函数,实现文件复制、插入、删除、更改文件内容等操作。

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
#include "graphics.h" #include "stdio.h" #include "dos.h" #include "conio.h" #include "bios.h" #include "stdlib.h" #include "math.h" #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif #define VK_LEFT 0x4b00 #define VK_RIGHT 0x4d00 #define VK_DOWN 0x5000 #define VK_UP 0x4800 #define VK_HOME 0x4700 #define VK_END 0x4f00 #define VK_SPACE 0x3920 #define VK_ESC 0x011b #define VK_ENTER 0x1c0d #define VK_PGUP 0x4900 #define VK_PGDOWN 0x5100 #define TIMER 0x1c void drawblock(int,int,int); void nedr(void); void fk(int,int,int,int); void rewr(int,int,int,int); void rrwf(int,int); int is_bd(int,int,int); int is_line(void); void interrupt ( *oldhandler)(__CPPARGS); void KillTimer(void); void SetTimer(void interrupt (*IntProc)(__CPPARGS)); void rscore(int); int fkt[]={0,4,8,12,14,16,18}; int cj[]={0,100,300,900,1500}; long grc[]={0,3000,60000,90000,120000,150000,180000,210000,240000,270000}; int cjb[]={0,0,0,0,0,0,0,0,0,0}; char cjc[]="score: 0"; char grad[]="grade:0"; struct shape { short xy[8]; short color; short next; }; struct shape shapes[19]= { /* {x1,y1,x2,y3,x3,y3,x4,y4,color,next} */ {1,1,2,1,3,1,3,2,LIGHTBLUE,1}, /* □□□□ */ {2,2,3,0,3,1,3,2,LIGHTBLUE,1}, /* □■□□ */ {1,1,1,2,2,2,3,2,LIGHTBLUE,1}, /* □■□□ */ {2,0,2,1,2,2,3,0,LIGHTBLUE,-3}, /* □■■□ */ {1,1,1,2,2,1,3,1,LIGHTCYAN,1}, /* □□□□ */ {2,0,3,0,3,1,3,2,LIGHTCYAN,1}, /* □■■□ */ {1,2,2,2,3,1,3,2,LIGHTCYAN,1}, /* □■□□ */ {2,0,2,1,2,2,3,2,LIGHTCYAN,-3}, /* □■□□ */ {2,1,3,0,3,1,3,2,LIGHTRED,1}, /* □□□□ */ {1,2,2,1,2,2,3,2,LIGHTRED,1}, /* □□□□ */ {1,0,1,1,1,2,2,1,LIGHTRED,1}, /* □■□□ */ {1,0,2,0,2,1,3,0,LIGHTRED,-3}, /* ■■■□ */ {2,1,2,2,3,0,3,1,DARKGRAY,1}, /* □□□□ */ {1,0,2,0,2,1,3,1,DARKGRAY,-1}, /* □□□□ */ /* □■■□ */ /* ■■□□ */ {2,0,2,1,3,1,3,2,MAGENTA,1}, /* □□□□ */ {1,2,2,1,2,2,3,1,MAGENTA,-1}, /* □□□□ */ /* ■■□□ */ /* □■■□ */ {0,1,1,1,2,1,3,1,BROWN,1}, /* □■□□ */ {1,0,1,1,1,2,1,3,BROWN,-1}, /* □■□□ */ /* □■□□ */ /* □■□□ */ {2,1,2,2,3,1,3,2,YELLOW,0}, /* □□□□ */ /* □□□□ */ /* □■■□ */ /* □■■□ */ }; int stx=5,sty=8,sdx=24,sdy=18,shx=7,shy=22,adx=4,ady=1,nexti,TimerCounter=0,grade=0,end=0; unsigned long score=0; short board[25][12]= /* 方块空间表示,1表示有方块 */ { {1,1,1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, /* 0 */ {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, /* 5 */ {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, /* 10 */ {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, 赞 0 2005-5-12 15:50 回复 218.85.57.* 2楼 {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, /* 15 */ {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, /* 20 */ }; short colable[25][12]= /* 方块空间颜色,1表示背景色蓝色*/ { {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, /* 0 */ {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, /* 5 */ {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, /* 10 */ {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, /* 15 */ {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, /* 20 */ }; void interrupt newhandler(__CPPARGS) /* 新的时钟中断处理函数 */ { TimerCounter++; oldhandler(); } void SetTimer(void interrupt (*IntProc)(__CPPARGS)) /* 设置新的时钟中断 */ { oldhandler=getvect(TIMER); disable(); setvect(TIMER,IntProc); enable(); } void KillTimer() /* 恢复原有的时钟中断处理过程 */ { disable(); setvect(TIMER,oldhandler); enable(); } void rscore(int line) /* 成绩更新函数 */ { int i,j,k=1; unsigned long s,f; score+=cj[line]; setfillstyle(1,GREEN); bar(0,5,150,30); s=score; if(s>=grc[grade]) { grade++; grad[6]=grade+48; bar(180,5,300,30); moveto(200,20); outtext(grad); } for(i=9;i>0;i--) { f=pow(10,i); j=s/f;s=s%f; if((!j)&&k); else k=0,cjc[15-i]=j+48; } moveto(10,20); outtext(cjc); } int is_bd(int x1,int y1,int i) /* 判断是否有方块 */ { int j,x2,y2; for(j=0;j<4;j++) { x2=shapes[i].xy[2*j]; y2=shapes[i].xy[2*j+1]; if(board[x1+x2+adx][y1+y2+ady])return 0; } return 1; } void fk(int re,int x1,int y1,int i) /* 方块的擦除、重写,并判断是否结束 有问题 */ { int j,x2,y2,color; for(j=0;j<4;j++) { x2=shapes[i].xy[2*j]; y2=shapes[i].xy[2*j+1]; if(!re) color=getbkcolor(); else color=shapes[i].color; if(re==2) { if((x1+x2)<=-1) { printf("Game is OVER!"); getch(); end=1; } break; } else { if((x1+x2)<=-1) continue; } board[x1+x2+adx][y1+y2+ady]=re; colable[x1+x2+adx][y1+y2+ady]=color; drawblock(stx+x1+x2,sty+y1+y2,color); } /* getch(); */ } void drawblock(int x,int y,int color) /* 写1个相对单位点的函数 */ { int i,j; for(i=0;i<16;i++) for(j=0;j<16;j++) putpixel(y*16+j,x*16+i,color); } void nedr(void) /* 产生并写下一个方块的函数 */ { int j,x2,y2,i,color; setfillstyle(1,GREEN); nexti=i=random(19); bar(shy*16,shx*16,(shy+4)*16,(shx+4)*16); for(j=0;j4;i--) { for(j=1;j4;i--) for(j=1;j<12;j++) colable[i][j]=colable[i-k][j],board[i][j]=board[i-k][j]; setfillstyle(1,BLUE); bar(sty*16,stx*16,(sdy)*16-1,(sdx+1)*16-1); for(i=5;i<24;i++) for(j=1;j9)) { if(TimerCounter>9)TimerCounter=0; fk(0,x1,y1,i); if(is_bd((k=x1+1),y1,i)) fk(re,x1=k,y1,i); else { fk(re,x1,y1,i); is_line(); fk(2,x1,y1,i); if(end)break; i=nexti;x1=-4;y1=3; fk(re,x1,y1,i); nedr(); } } } KillTimer(); }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨城烟柳ベ旧人殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值