初识c语言day16

复习:

    结构:是一个由程序员自己设计的数据结构,他十用于描述一个事物的各项数据,由若干个基础的数据类型组成

    设计:  

        struct 结构类型名

        {

            类型名 成员名;  

        };

    定义:

        struct 结构类型名 结构变量名;

            struct Student stu; // 结构变量

            struct Student* sp; // 结构指针

    访问成员:

        结构变量.成员名;

        结构指针->成员名;

    初始化:

        顺序:  struct 结构类型名 结构变量名={v1,v2...};

        指定:  struct 结构类型名 结构变量名={.成员名=v1,.成员名=v2,...};

        整体:  相同类型的结构变量可以直接初始化

            struct Student stu;

            struct Student stu1 = stu;

    类型重定义:

        在c语言中struct、union、enum关键字在定义变量不能省略,可以使用typedef进行类型重定义,简约这些类型名

        typedef struct 结构类型名 结构类型名;

        一边设计一边重定义:

            typedef struct 结构类型名

            {

            }结构类型名;

   

    结构体字节数的计算:

        内存对齐:

            假设第一个成员从0地址开始,每个成员使用的内存编号必须是它字节数的整数倍,如果不是则需要填充一些空白字节

        内存补齐:

            结构体总字节数必须是它最大成员字节数的整数倍,如果不是,则在末尾补充一些空白字节

       

        注意:在对齐和补齐时,Linux 32位下,超过4字节按照4字节算,windows是按实际字节数对齐补齐

        成员的顺序不同可能会影响结构体的总字节数,如果顺序安排合理可以节约内存

        #pragma pack(n)  可以设置对齐、补齐的最大字节数为n,但是 n <=4 (1,2,4)

        注意:结构体一般适合使用堆内存存储

一、联合union

    联合与结构使用方法基本一致,与结构的区别是联合的所有成员公用一块内存,一个成员的值发生改变,其他成员也随之改变

    联合的效果就是使用少量的内存对应多个标识符,以此达到节约内存的目的,但是现在几乎不使用

    常考的联合题:

    union Data

    {

        char ch[5];   0~4

        int num;      0~3

    };

    sizeof(union Data) == 8

    注意:计算联合总字节数时,不需要考虑内存对齐,但是需要考虑内存补齐

       

    如何判断系统的大小端问题?

        假设十六进制 0x01020304 存储在以0x0A起始的0x0A~0x0D字节内存中

            大端:(0x04->0x0D    0x03->0x0C   0x02->0x0B   0x01->0x0A)

            小端:(0x01->0x0D    0x02->0x0C   0x03->0x0B   0x04->0x0A)

        大端系统:高位数据存在低位地址,低位数据存在高位数组

        小端系统:高位数据存在高位地址,低位数据存在低位数组

        个人计算机一般都是小端系统,而UNIX服务器和网络设备都是大端,网络字节序也是大端模式的数据,本地字节序就是小端模式的数据

            序列化和反序列化

    常考编程题:实现一个程序,判断系统是大端还是小端

二、枚举

    枚举就是一种数据类型,把可能出现的所有值罗列出来,并起一个有意义的名字表示这些值,除此之外给该类型的变量赋其他值,是非法的(愿望)

    枚举可以看作一种值受限的int类型,但是c编译器为了效率不检查,所以在c中枚举就相当于int类型变量

    如果不给成员值,那么枚举中的值第一个默认从0开始,逐渐+1,如果设置了某个值,后面的成员在它的基础上逐渐+1

    为什么要使用枚举:

        为无意义的值取一个有意义的名字,提高代码的可读性,提高安全性(比变量更安全)(锦上添花)

    作业:通讯录更改为使用结构存储、使用堆内存存储

三、文件

    文件的分类:

        文本文件:  存储的ASCII码的二进制  '2''5''5'  50 53 53

        二进制文件:存储的是数据的补码  255  11111111

   

    文件IO:

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

        功能: 打开或创建文件

        path: 文件的路径

        mode: 文件打开模式

            r      以只读方式打开文件,如果不存在则失败

            r+     在r的基础上,增加写权限

            w      以只写权限打开文件,如果存在则清空打开,不存在则新建

            w+     在w的基础上,增加读权限

            a      以只写权限打开文件,如果存在则末尾追加,不存在则新建

            a+     在a的基础上,增加读权限

        返回值:文件指针,不需要关心里面有什么数据,只需要知道它是一个针对已开文件的凭证,打开失败会返回NULL

    二进制方式读写:

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

        功能:把内存中的数据写入到文件中

        ptr: 待写入的内存的首地址

        size: 一次写入的字节数

        nmemb: 写入的次数

        stream: 文件指针,fopen的返回值

        返回值:成功写入的次数

       

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

        功能:从文件读取数据到内存中

        ptr: 接收文件数据的内存首地址

        size: 一次读取多少字节

        nmemb: 读取多少次

        stream: 文件指针,表示从哪个文件读取

        返回值:成功读取到次数

        练习2: 设计并定义一个教师结构变量并初始化,以二进制方式写入到文件中

        练习3: 从文件中读取教师结构体数据到变量中并显示

    文本方式读写文件:

        int fprintf("FILE *stream,const char *format,...");

        功能:以文本形式写入数据到文件中

        stream: 要写入的文件

        format: 占位符和提示信息

        ...: 变量名列表

        返回值:成功写入的字节数

        int fsanf(FILE *stream,const char *format,...);

        功能:从文件中读取数据到变量中

        stream: 要读取的文件

        format: 占位符(提示信息)

        ...: 变量地址列表

        返回值:成功读取的变量个数

    练习4: 设计并定义一个教师结构变量并初始化,以文本的方式写入到文件中

    练习5: 从文件中以文本的方式读取教师结构体数据到变量中并显示

    关闭文件:

        int fclose(FILE *stream);

        功能:关闭一个打开的文件

        返回值: 成功0,失败-1

        注意:如果需要立即修改文件的内容,最好先关闭文件

    文件位置指针:

        每个通过fopen打开的文件都有一个文件位置指针来记录着接下来要读写的位置,

        以r、r+、w、w+打开文件,位置指针在文件的开头,以a a+打开文件,位置指针自动在末尾

        如果想要随意读写文件的任意位置,那么可以通过手动设置文件位置指针的位置

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

        功能: 手动设置位置指针的位置

        stream: 文件指针

        offset: 偏移值

        whence: 基础位置

            SEEK_SET   文件开头

            SEEK_CUR   当前位置

            SEEK_END   文件末尾

        返回值: 成功(调整后位置指针还在文件种)返回0,失败返回-1

       

        void rewind(FILE *stream);

        功能:把文件位置指针设置到文件开头

        long ftell("FILE *stream");

        功能:获取当前文件位置指针的位置

        返回:在第几个字节

        int fgetc(FILE *stream);

        功能:从文件中读取一个字符

        返回值: 失败、读取完毕返回EOF(-1)

        char *fgets(char *s, int size, FILE *stream);

        功能: 读取一行字符串到s中,最多读size-1个

        int fputc(int c, FILE *stream);

        功能:写入一个字符到文件中

        返回值:成功返回非负整数,失败返回-1

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

        功能:写入一个字符到文件中

        返回值:成功返回非负整数,失败返回-1

        int remove(const char *pathname);

        功能:删除文件

        pathname: 文件路径

        返回值: 成功返回0,失败返回-1

        int rename(const char *oldpath, const char *newpath);

        功能:重命名文件

        返回值: 成功返回0,失败返回-1

四、命令行参数: main函数的参数

    是为了获取./a.out 命令行中的参数

    argc    代表了命令行参数的个数

    argv    每个参数字符串的首地址

    注意:  ./a.out是argv[0]

    作业2: 实现cp命令

        cp dest src

        fread fwrite

        先读,存起来char buf[256],然后写进去

        循环直到读完为止

#include 

int main(int argc,const char* argv[])
{
	if(3 != argc)
	{
		printf("User: ./CP dest src\n");
		return 0;
	}
	FILE* dest = fopen(argv[1],"r");
	if(NULL == dest)
	{
		printf("源文件不存在,请检查\n");
		return 0;
	}
	FILE* src = fopen(argv[2],"r");
	if(src)
	{
		printf("目标文件已存在,是否覆盖(y\\n)?");
		char cmd = getchar();
		if('y' != cmd && 'Y' != cmd)
		{
			printf("停止拷贝\n");
			return 0;
		}
		fclose(src);

	}
	src = fopen(argv[2],"w");
	if(NULL == src)
	{
		printf("文件路径权限有误,请检查\n");
		return 0;
	}
	
	char buf[256]={};
	int ret =0;
	while(ret = fread(buf,1,256,dest))
	{
		fwrite(buf,1,ret,src);
	}
	fclose(dest);
	fclose(src);
	dest = NULL;
	src = NULL;
}


 

你可能感兴趣的:(c语言,开发语言)