浅学C++(3)学习C语言(结构、联合、枚举、文件)

一,结构
    结构是一种由程序员自己设计的数据类型,用于描述一个事物的的各项特征数据,由若干个可以不同的基础类型组成

    设计:
    struct 结构类型名
    {
        类型 成员名1;
        类型 成员们2;
        ...
    };
    定义结构变量:
    struct 结构类型名 结构变量名 = {v1,v2,...};顺序初始化
        一定要与成员类型顺序一致
    struct 结构类型名 结构变量名 = { ,.成员名1=v1,...,.成员名5=v5};指定初始化
        只初始化某些成员,顺序无需一致   
    struct Student stu;
    struct Student stu1 = stu; 整体初始化
    tap: struct 在C语言中,定义结构变量时不能省略,这种赋值方式只能在初始化时使用
    tap:同类型的结构变量可以直接给另一个结构变量初始化 

    重定义:
        在C语言中,struct、union、enum关键字在定义变量时不能省略,可以使用typdef进行类型重定义
        typedef struct 结构类型名
        {

        }结构类型名;

    访问成员:
        struct Student stu;
        static Student* sp;
        结构变量名.成员名;
    由于结构体变量的字节数一般都比较大,普通的值传递效率非常低,因此传递结构变量的地址,也即是传递结构指针
    变量,此时想要通过结构指针变量访问成员时借助 ->   结构指针变量名->成员名

    如何计算结构体的总字节数:
        结构成员的顺序可能会影响它的总字节数,如果能够在设计结构体时合理的安排成员顺序,可以大大节约内存
        内存对齐:
            假设第一个成员从0地址开始,存储每个成员的地址编号必须能被该成员的类型字节数整除,如果不能整除就自动补空白字节补齐
        内存补齐:
            结构体的总字节数必须是它最大成员字节数的整数倍,如果不能整除,则在末尾补齐一些空白字符,在32位Linux系统下计算结构体的对齐补齐时
            如果最大字节数大于4则按4来算。windows是按实际字节数对齐补齐
        #pragma pack(n)     可以设置对齐、补齐的最大字节数为n 但 n <=4(1,2,4)
    
    tap:结构体一般适合堆内存存储

二,联合 union 
    联合与结构的用法基本一致,与结构的区别是联合的所有成员公用一块内存,一个成员的值发生改变,其他成员也随之发生改变
    联合的效果就是使用少量的内存对应多个标识符,以此达到节约内存的目的,但是现在几乎不使用
    计算联合总字节数时不用考虑对齐,但是要考虑补齐问题

    如何判断系统的大小端?
        例 0x01020304 存在 0x0A~0x0D
        大端系统:高位数据存储在低位地址,低位数据存储在高位地址
            (0x0D,0x04 ; 0x0C,0x03 ; 0x0B,0x02 ; 0x0A,0x01)
        小端系统:低位数据存储在低位地址,高位数据存储在高位地址
            (0x0D,0x01 ; 0x0C,0x02 ; 0x0B,0x03 ; 0x0A,0x04)
        个人计算机一般都是小端系统,而UNIX网络设备大多是大端系统,网络字节序是大端模式数据,本地字节序就是小端模式的数据
            序列化与反序列化

    实现一个程序,判断当前系统是大端还是小端
    #include <stdio.h>

    union Dx
    {
        char ch;
        int num;
    };

    int main(int argc,const char* argv[])
    {
        union Dx date={date.num=0x01020304};
        if(0x04 == date.ch)
            printf("小端系统\n");
        else
            printf("大端系统\n");
    }


三,枚举 enum
    枚举就是一种数据类型,把可能出现的所有值都罗列出来,并起一个有意义的名字表示这些值,除此之外给该类型的变量赋其他值,是非法的(愿望)
    枚举可以看作一种值受限的int类型,但是在C编译器为了效率不检查,所以在C中枚举就相当于int类型变量
    如果不给成员值,那么枚举中的第一个成员默认从0开始,逐渐+1,如果设了某个值,后面的成员在它的基础上逐渐+1

    为什么要使用枚举:
        为无意义的值起一个有意义的名字,提高代码可读性,提高安全性(变量更安全)

四,文件
    文件的分类:
        文本文件:存储的是ASCII码的二进制
        二进制文件:存储的是数据的补码

    文件IO:
        FILE* fopen(const char *path,const char *mode);
        功能:打开或创建文件
        path:文件的路径
        mode:文件打开的模式
            r       以只读权限打开文件,如果文件不存在则失败
            r+      在r的基础上增加写权限 
            w       以只写权限打开文件,如果存在则清空打开,如果不存在则创建文件再打开
            w+      在w的基础上增加读权限
            a       以只写权限打开文件,如果存在在末尾追加,如果不存在则创建文件
            a+      在a的基础上增加读权限
        返回值:文件指针,不需要关心里面有什么数据,只需要知道它是一个指针对已打开文件的凭证,打开失败返回NULL

    二进制方式读写:
        size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
        功能:从文件读取数据到内存中
        ptr:接收文件数据的内存首地址
        size:一次读取多少字节
        nmemb:读取的次数
        stream:文件指针,表示从那个文件读取
        返回值:成功读取的次数


        size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
        功能:把内存中的数据写入到文件中
        ptr:待写入的内存首地址
        size:一次写入的字节数
        nmemb:写入的次数
        stream:文件指针(fopen的返回值)
        返回值:成功写入的次数

    文本方式读写:
        int fprintf(FILE *stream, const char *format, ...);
        功能:以文本形式写入数据到文件中
        stream:要写入的文件
        format:占位符和提示信息
        ...:变量名列表
        返回值:成功写入的字节数

        int fscanf(FILE *stream, const char *format, ...);
        功能:从文件中读取数据到变量中
        stream:要读取的文件
        format:占位符(数据格式)
        ...:变量地址列表
        返回值:成功读取的变量个数
关闭文件:
    int fclose(FILE *stream);
    功能:关闭一个打开的文件
    返回值:成功0,失败-1
    tap:如果需要立即修改文件的内容,最好先关闭文件

文件位置指针:
    每个通过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

        long ftell(FILE *stream);
        功能:获取当前文件位置指针的位置
        返回值:在第几个字节

        void rewind(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        每个参数字符串的首地址
    tap:./a.out 是 argv[0]

使用文件实现Linux cp 命令

#include <stdio.h>

int main(int argc,const char* argv[])
{
    if(3 != argc)
    {
        printf("输入参数有误!!!");
        return 0;
    }
    FILE* frp = fopen(argv[1],"r");
    if(NULL == frp)
    {
        printf("源文件不存在\n");
        perror("fopen");
        return -1;
    }
    FILE* fwp = fopen(argv[2],"r");
    if(fwp)
    {
        printf("目标文件已存在,是否覆盖(y//n)?");
        char cmd = getchar();
        if('y'!= cmd && 'Y' != cmd)
        {
            printf("停止拷贝\n");
            return 0;
        }
        fclose(fwp);
    }
    fwp = fopen(argv[2],"w");
    char str[255]={};
    int ret=0;   
    do
    {
        ret = fread(str,1,255,frp);
        fwrite(str,1,ret,fwp);
    }while(0 > ret);
}

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值