C语言——位、文件操作

一、位(适用于单片机)

位域、把一个字节拆开使用。分成不同的区域,每个区域还可以命名。使其对不同位域进行使用。

使用方法:

在结构体定义时,在结构体成员后面使用冒号(:)和数字来表示该成员所占的位数。

例:

#include <stdio.h>

int main(void)
{
	struct Test
	{
		unsigned int a:1;	//给其a分配占一个二进制位
		unsigned int b:1;	//默认无符号整型占4个内存空间
		unsigned int c:1;
	};

	struct Test test;
	test.a = 0;
	test.b = 1;
	test.c = 1;
	
	printf("a = %d b = %d c = %d\n", test.a, test.b, test.c);
	printf("size of test = %d\n", sizeof(test));
	
	getchar();
	return 0;
}

结果:

a = 0 b = 1 c = 1    //3位;一个字节等于8位
size of test = 4    //4字节    
//默认分配一个整型,在其int内分别为其分配。还有其29位内存未使用

无名位域

——位域成员可以没有名字,只要给出数据类型和位宽即可。

——无名位域一般用来填充或者调整内存。不能拿来使用。

例:

struct Test
{
	unsigned int x:100;
	unsigned int  :200;
	unsigned int z:300;
	unsigned int  :424;
}

注意:

    //注意变量所占的坑位一定要能够存储其值
    //位域的宽度不能超过它所依附的长度,如不能超过test的长度
    //不能对位域进行取址运算


 

逻辑运算符:(对两个或者两个以上进行判断)

只作用于整型数据,并且对数据当中每个二进制位进行运算

移位运算符:(将二进制位进行左移或者右移)

左移位:"<<"

右移位:">>"

例:

#include <stdio.h>

int main(void)
{
	int value = 1;

	while (value < 1024)
	{
		value <<= 1;	//value = value << 1;
		printf("左移的value = %d\n", value);
	}
printf("————————————————————\n");
	while (value > 0)
	{
		value >>= 1;	
		printf("右移的value = %d\n", value);
	}

	printf("\n");
	getchar();
	return 0;
}

结论:左移N位是乘以2的N次方,右移N位是除以2的N次方。(移位的效率是最高的)

注意:

—移位的操作数如果为负,或者右边的操作数大于左边操作数支持的最大宽度,表达式的结果属于“未定义行为”。

—有符号于无符号对移位运算符有着不同的影响。

二、文件操作

文件含义:是存储在某种长期存储设备或临时存储设备中的一段数据流。

类型:文本文件、二进制文件

文件操作流程:打开(必须)——读/写——关闭(必须)

(一)、打开文件

fopen()打开文件并返回文件指针

两个参数:path(路径,绝对路径与相对路径)、mode(模式,如只读模式等)。

返回值

1.如果文件打开成功,则返回一个指向FILE结构的文件指针;

2.如果文件打开失败,则返回NULL并设置errno为指定的错误。

注意:打开到关闭中间有一个缓冲区。

(二)、读写操作

分为:随机读写、顺序读写

  • 单个字符的读取:fgetc()和getc()

fgetc():用于从文件流中读取下一个字符并推进文件的位置指示器(用来指示接下来要读写的下一个字符的位置)。

    参数:只有一个参数"stream"该参数是一个FILE对象的指针,指示下一个待读取的文件流。

    返回值:将读取的unsigned char类型转换为int类型并返回。如果文件结束或者遇到错误则返回EOF。

注:fgetc()和getc()描述基本上一样。fgetc是一个函数,而getc则是一个宏的实现。 

  • 单个字符的写入:fputc()和putc()

fputc():用于写入一个字符到指定文件中并推进文件的位置指示器

参数:参数C和stream,C指定待写入的字符、stream是一个FILE对象的指针,指定一个待写入的文件流。

返回值:如果函数没有错误,返回值是写入的字符、如果函数发生错误,返回值是EOF。

注:fputc()putc()描述基本上一样。fputc()是一个函数,而putc()则是一个宏的实现。

例:

//把一个文件的内容以单字符形式传输到另一个文件中。
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	FILE *fp1,*fp2;
	int ch;

	if ((fp1 = fopen("test1a.txt", "r")) == NULL)
	{
		printf("文件打开失败!\n");
		exit(EXIT_FAILURE);
	}

	if ((fp2 = fopen("test1b.txt", "w")) == NULL)
	{
		printf("文件打开失败!\n");
		exit(EXIT_FAILURE);
	}

	while ((ch = fgetc(fp1)) != EOF)
	{
		fputc(ch, fp2);
	}
	fclose(fp1);
	fclose(fp2);

	return 0;
}
  • 整个字符串的读取:fgets()

fgets():用于从指定文件中读取字符串。最多读取size-1个字符'\0'就自动结束。'\n'会被作为一个合法的字符读取。

    参数:三个参数,s、size、stream. s(字符型指针)用于指向存放读取字符串的位置、size指定读取的字符数(包括'\0')、stream是一个FILE对象的指针,指定一个待读取的数据流。

    返回值:如果函数调用成功,返回s参数指向的地址;如果在读取字符串的过程中遇到EOF,则EOF指示器被设置下一读取地址;如果还未读取任何字符串就遇到EOF,则s参数指向的位置保持原来的内容,函数返回NULL;如果在读取的过程中发生错误,则error指示器被设置,函数返回NULL(注:s参数指向的内容可能被改变)

  • 整个字符串的写入:fputs()

fputs():用于将字符串写入到指定文件中,'\0'不会被一并写入。

    参数:两个,s、stream. s(字符型指针)指向存放待写入字符串的位置;stream是一个FILE对象的指针,指定一个待写入的数据流。

    返回值:如果函数调用成功,返回一个非0值;如果函数调用失败,返回EOF。

例:

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

#define MAX 1024

int main(void)
{
	FILE * fp;
	char buffer[MAX];

	if ((fp = fopen("test2.txt", "w")) == NULL)
	{
		printf("打开文件失败!\n");
		exit(EXIT_FAILURE);
	}

	fputs("写入第一段字符串\n", fp);
	fputs("写入第二段字符串\n", fp);
	fputs("写入第三段字符串\n", fp);

	fclose(fp);	//关闭是为了让字符串写入进文件,同时重置字符串指示器的位置

	if ((fp = fopen("test2.txt", "r")) == NULL)
	{
		printf("打开文件失败!\n");
		exit(EXIT_FAILURE);
	}

	while (!feof(fp))	//循环打印,feof用来检测文件是否是末尾(详细请查找手册)
	{
		fgets(buffer, MAX, fp);
		printf("%s", buffer);
	}
/*
feof检测到末尾指示器被设置(未读取完毕),返回一个非零;如果未被设置(读取完毕),返回一个0.
*/
	fclose(fp);


	return 0;
}

结果:

root@debian:~/C# gcc test2.c && ./a.out
写入第一段字符串
写入第二段字符串
写入第三段字符串
写入第三段字符串

//多打印了一行的原因在于“最后的'\n'会被作为一个合法的字符读取,然后退出读取”,再次读取,直接遇到EOF.及返回值如同第二点:如果还未读取任何字符串就遇到EOF,则s参数指向的位置保持原来的内容,函数返回NULL;

注意小例子:


/*
 *printf与scanf本来是从终端输入输出
 *fprintf与fscanf指定文件的输入和输出
 *二进制文件进行读写,fputs可以指定对二进制操作,但该文件并不一定就是二进制文件
 * */

#include <stdio.h>
#include <stdlib.h>  //输入输出函数

int main(void)
{
        FILE *fp;

        if ((fp = fopen("date.txt", "wb")) == NULL)//“b”二进制方式打开
        {
                printf("打开文件失败!\n");
                exit(EXIT_FAILURE);
        }

        fputc('5', fp);
        fputc('2', fp);
        fputc('0', fp);
        fputc('\n', fp);

        fclose(fp);

        return 0;
}

 输出结果:

root@debian:~/C/test12/test12_2# cat date.txt
520
  • 格式化读写文件:fscanf()和fprintf()

fscanf():用于从指定文件中读取格式化字符串。

fprintf():用于打印格式化字符串到指定文件中。

     参数(它们的参数与printf和scanf的参数一样,只是输入的位置发生改变"添加了一个file结构体的指针"):(stream、format).stream是一个FILE对象的指针,指定一个待写入的数据流。format是一个格式化字符串,由格式化占位符和普通字符组成。

例子:

/*
 *printf与scanf本来是从终端输入输出
 *fprintf与fscanf指定文件的输入和输出
 *例子:获取当前写入的字符串并打印到文件内
 * */

#include <stdio.h>
#include <stdlib.h>  //输入输出函数
#include <time.h>       //为了localtime

int main(void)
{
        FILE *fp;
        struct tm *p;
        time_t t;

        time(&t);
        p = localtime(&t);

        if ((fp = fopen("date.txt", "w")) == NULL)
        {
                printf("打开文件失败!\n");
                exit(EXIT_FAILURE);
        }

        fprintf(fp, "%d-%d-%d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);

        fclose(fp);
//读取写入文件
        int year, month, day;

        if ((fp = fopen("date.txt", "r")) == NULL)
        {
                printf("打开文件失败!\n");
                exit(EXIT_FAILURE);
        }

        fscanf(fp, "%d-%d-%d", &year, &month, &day);
        printf("%d-%d-%d\n", year, month, day);

        fclose(fp);

        return 0;
}

二进制文件操作:

fread()函数与fwrite()函数

fread():用于从指定文件中读取指定尺寸的数据。

fread():用于从指定文件中写入指定尺寸的数据。

例子:

/*
 *printf与scanf本来是从终端输入输出
 *fprintf与fscanf指定文件的输入和输出
 *例子:对二进制进行操作fread与fwrite
 * */

#include <stdio.h>
#include <stdlib.h>  //输入输出函数
#include <string.h>     //对字符串的操作

struct Date
{
        int year;
        int month;
        int day;
};

struct Book
{
        char name[40];
        char author[40];
        char publisher[40];
        struct Date date;
};

int main(void)
{
        FILE *fp;
        struct Book *book_for_write, *book_for_read;

        book_for_write = (struct Book *)malloc(sizeof(struct Book));
        book_for_read = (struct Book *)malloc(sizeof(struct Book));

        //检查是否分配成功
        if (book_for_write == NULL || book_for_read == NULL)
        {
                printf("内存分配失败!\n");
                exit(EXIT_FAILURE);
        }

        strcpy(book_for_write->name, "《C Primer Plus》");
        strcpy(book_for_write->author, "Stephen P rata");
        strcpy(book_for_write->publisher, "人民邮电出版社");
        book_for_write->date.year = 11;
        book_for_write->date.month = 22;
        book_for_write->date.day = 33;

        if ((fp = fopen("date.txt", "w")) == NULL)//为了证明打开形式跟具体写入一致,没有加‘b’
        {
                printf("打开文件失败!\n");
                exit(EXIT_FAILURE);
        }

        fwrite(book_for_write, sizeof(struct Book),1,fp);
        fclose(fp);

        if ((fp = fopen("date.txt", "r")) == NULL)
        {
                printf("打开文件失败!\n");
                exit(EXIT_FAILURE);
        }

        fread(book_for_read, sizeof(struct Book),1,fp);
        printf("书名:%s\n",book_for_read->name);
        printf("作者:%s\n",book_for_read->author);
        printf("出版社:%s\n",book_for_read->publisher);
        printf("出版日期:%d-%d-%d\n", book_for_read->date.year, book_for_read->date.month, book_for_read->date.day);
        fclose(fp);

        return 0;
}

结果:

root@debian:~/C/test12/test12_3# ./a.out
书名:《C Primer Plus》
作者:Stephen P rata
出版社:人民邮电出版社
出版日期:11-22-33
root@debian:~/C/test12/test12_3# vim date.txt

随机读写:

ftell()得到当前文件指针位置。

rewind()初始化文件指针(使文件指针回到文件头)。

fseek()设置文件流的位置指示器。如果函数成功返回0,如果失败返回非零。+-

      函数原型:int fseek(FILE *stream, long offset, int fromwhere);

     参数解析:stream指向文件流。offset指定从fromwhere参数的位置起偏移多少字节。fromwhere(SEEK_SET文件头、SEEK_CUR当前的读写位置、SEEK_END文件末尾)

/*
 *录入相关信息并读取
 * */

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

#define N 4

struct Stu
{
        char name[24];
        int num;
        float score;
}stu[N], sb;

int main(void)
{
        FILE *fp;
        int i;

        if ((fp = fopen("sorce.txt", "wb")) == NULL)
        {
                printf("打开文件失败!\n");
                exit(EXIT_FAILURE);
        }

        printf("请开始录入成绩(格式:姓名 学号 成绩):\n");
        for (i = 0; i < N; i++)
        {
                scanf("%s %d %f", stu[i].name, &stu[i].num, &stu[i].score);
        }

        fwrite(stu, sizeof(struct Stu), N, fp);//结构体用二进制写入
        fclose(fp);

        if ((fp = fopen("sorce.txt", "rb")) == NULL)
        {
                printf("打开文件失败!\n");
                exit(EXIT_FAILURE);
        }

        fseek(fp, sizeof(struct Stu), SEEK_SET);
        fread(&sb, sizeof(struct Stu), 1, fp);
        printf("%s(%d)的成绩是:%.2f\n",sb.name, sb.num, sb.score);
        fclose(fp);

        return 0;
}

猜你喜欢

转载自blog.csdn.net/u013283956/article/details/80572090
今日推荐