C语言结构体和文件操作

293 阅读5分钟

C语言第三弹,结构体,在Java和Kotlin中我们有类的概念,在C语言有类似的结构,但是它不是类。它叫结构体。

第一弹:辨析C语言指针
第二弹:C语言字符串操作和指针小操练

1、结构体的声明和赋值

第一种方法

struct Dog {
    char name [10] ;
    int age;
    char sex;
};//这个分号一定要写
struct Dog dog;
//char name [10] 不能直接赋值
//dog.name = "aaa";
//没赋值之前,打印结构体的成员,都是系统值
printf("dogName:%s,dogAge:%d,dogSex:%c\n",dog.name,dog.age,dog.sex);
strcpy(dog.name,"煤球");
dog.age =10;
dog.sex ='g';
printf("dogName:%s,dogAge:%d,dogSex:%c\n",dog.name,dog.age,dog.sex);

第二种方法

//第二种赋值方法
struct Cat {
    char * name;
    int age;
    char sex;

}
cat = {"喵喵",5,'M'},
cat2
;
printf("catName:%s,catAge:%d,catSex:%c\n",cat.name,cat.age,cat.sex);

 printf("catName:%s,catAge:%d,catSex:%c\n",cat2.name,cat2.age,cat2.sex);

结构体嵌套

struct Book {
    char * name;
};
struct Student {
    char * name;
    int age;
    struct Book book;
    struct Teacher {
        char * name;
        int age;
    } teacher;
};


main () {
    struct Student student;
    student.name = "杜子腾";
    student.age = 16;
    student.book.name = "语文第一册";
    student.teacher.name ="Tony";
    student.teacher.age =24;

    printf("学生姓名:%s,学生年龄:%d,书本名称:%s,老师名字:%s,老师年龄:%d",student.name,student.age,student.book.name,student.teacher.name,student.teacher.age);
    return 0;
}

2、结构体和指针数组结合

结构体指针结合

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Book {
    char * name;
};



main () {
    struct Book *  bookp ={"西游记"};
    // 一级指针 -> name  操作一级指针,指向的结构体成员
    bookp ->name = "三国演义";//这样就不能 . 了
    printf("书名:%s\n",bookp->name);
    //vs 写法 Book * bookp2 = malloc(sizeof(Book)),在vs中是不用加struct 关键字的
    struct Book * bookp2 = malloc(sizeof(struct Book));
    bookp2->name ="红楼梦";
    if(bookp2) {
        free(bookp2);
        bookp2=NULL;
    }
    
    return 0;
}

在vs中和clion中的写法是不同的,在系统源码和框架源码中,为了统一写法,大量的使用了typedef取别名。

数组和结构体。。

struct Book bookArray[10];
struct Book book0 ={"C语言从入门到放弃"};
bookArray[0] =book0;
struct Book book8 = {"深入理解Java虚拟机"};
bookArray[8] = book8;
struct Book book9 = {"深入理解Java虚拟机"};
*(bookArray + 9) = book9;
printf("%s,%s,%s\n", bookArray[0], bookArray[8], bookArray[9]);
struct Book *bookArr2 = malloc(sizeof(struct Book) * 10);
bookArr2->name = "C语言从入门到放弃";

bookArr2[8].name ="aaaa";
struct Book book1010 = {"HelloWorld"};
*(bookArr2 + 9) = book1010;
printf("%s,%s,%s\n", bookArr2[0].name, bookArr2[8].name, bookArr2[9].name);
if (bookArr2) {
    free(bookArr2);
    bookArr2 = NULL;
}

3、枚举

枚举的用法和Java类似

enum ImageType {
    IMAGE_PNG ,
    IMAGE_JPG,
    IMAGE_JPEG
};


int main() {
    //枚举的值是int 型,而且枚举类里边的三个值是连续的
    printf("%d,%d,%d",IMAGE_PNG,IMAGE_JPG,IMAGE_JPEG);

    return 0;
}

4、文件读写和复制

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void readFile() {
    char *filePath = "D:\test\a.txt"; //文件路径
    // fopen(const char * __restrict__ _Filename,const char * __restrict__ _Mode)
    //第一个参数 文件路径,
    //第二个参数 r 读文件, w 写文件 , rb 二进制读文件   wb 二进制写文件
    FILE *file = fopen(filePath, "r");
    if (!file) {
        printf("请检查文件路径");
    }
    char buffer[10];
    //fgets 从文件里读取字符串, 第一个参数 缓冲区, 第二个参数 最大数量= buffer 大小, 第三个参数文件指针
    while (fgets(buffer,10,file)) {
        printf("%s",buffer);
    }
    printf("读取文件的内容%s",buffer);
    fclose(file);
}
void writFile() {
    char *filePath = "D:\test\b.txt"; //文件路径
    // fopen(const char * __restrict__ _Filename,const char * __restrict__ _Mode)
    //第一个参数 文件路径,
    //第二个参数 r 读文件, w 写文件 , rb 二进制读文件   wb 二进制写文件
    FILE *file = fopen(filePath, "w");
    if (!file) {
        printf("请检查文件路径");
        exit(0);
    }
    //往file 里put 字符串
    fputs("写入的文件的内容",file);

    fclose(file);
}

void copyFile() {
    char * srcFilePath = "D:\test\a.txt";
    char * dstFilePath ="D:\test\aa.txt";
    //二进制读
    FILE * srcFile = fopen(srcFilePath,"rb");
    //二进制写
    FILE * dstFile = fopen(dstFilePath,"wb");

    if(!srcFile || !dstFile) {
        printf("请检查文件路径");
        exit(0);
    }
    char buffer [512];
    int len;
    //fread 第一个参数 缓冲区指针 ,第二个参数 缓冲区指针类型的大小,
    //第三个参数  容器的大小, 第四个参数要读取的文件指针
    while ( (len = fread(buffer,sizeof(char),512,srcFile))!= 0) {
        //fwrite 第一个参数 缓冲区指针 ,第二个参数 缓冲区指针类型的大小,
        //第三个参数  读出来的长度, 第四个参数要写入的文件指针
       fwrite(buffer,sizeof(char),len,dstFile);
    }
    fclose(srcFile);
    fclose(dstFile);
}

5、文件大小获取

在C语言中,是没有专门的API获取大小的。所以我们利用读取头指针移动来获取文件大小。用到的两个API 是fseek 和ftell

void getFileSize() {
    char * srcFilePath = "D:\test\a.txt";
    FILE * srcFile = fopen(srcFilePath,"rb");
    if(!srcFile) {
        printf("请检查文件路径");
        exit(0);
    }
    //从0开始移动,移到文件的结尾  SEEK_SET 开头,,SEEK_CUR 当前 SEEK_END结束
    fseek(srcFile,0,SEEK_END);
    //移动完后,他会给file指针,给file赋值,file有了更丰富的值
    long fileSize = ftell(srcFile);//计算偏移的位置,从0 开始 到当前(SEEK_END)
    printf("文件的大小%ld",fileSize);
    fclose(srcFile);
}

6、文件加解密

对于一个图片和文件和视频文件来说,他们的二进制数据都是有一定的格式的。例如,‌在JPEG文件中,‌FFD8和FFD9标记着文件的开始和结束,‌而FFE0-APP0分块包含了图像的识别信息,‌如JFIF格式标识码、‌版本号、‌单位、‌分辨率等。‌我们只需要把二进制数据破坏掉。就完成了文件的加密。加密的前提是能还原,不能还原的加密不叫加密。
我们用代码对文件进行小小的破坏。对文件的每一个字节进行异或操作。解密的时候用相同的办法再次异或就达到还原的目的。然而在工作中,我们这样做远远不够,工作开发中的加密是很复杂的。

void fileEncode() {
    char * srcFilePath ="D:\test\IMG.jpg";
    char * dstFilePath ="D:\test\IMG_encode.jpg";
    //二进制读
    FILE * srcFile = fopen(srcFilePath,"rb");
    //二进制写
    FILE * dstFile = fopen(dstFilePath,"wb");

    if(!srcFile || !dstFile) {
        printf("请检查文件路径");
        exit(0);
    }
    char * password = "123456";
    int pwdLength = strlen(password);
    int c ;
    int index = 0;
    //EOF end of File
    while((c= fgetc(srcFile))!=EOF) {
        int item = index%pwdLength;
        fputc(c^item,dstFile);
        index++;
    }
    fclose(srcFile);
    fclose(dstFile);
}
fileDecode() {
    char * srcFilePath ="D:\test\IMG_encode.jpg";
    char * dstFilePath ="D:\test\IMG_decode.jpg";
    //二进制读
    FILE * srcFile = fopen(srcFilePath,"rb");
    //二进制写
    FILE * dstFile = fopen(dstFilePath,"wb");

    if(!srcFile || !dstFile) {
        printf("请检查文件路径");
        exit(0);
    }
    char * password = "123456";
    int pwdLength = strlen(password);
    int c ;
    int index = 0;
    //EOF end of File
    while((c= fgetc(srcFile))!=EOF) {
        int item = index%pwdLength;
        fputc(c^item,dstFile);
        index++;
    }
    fclose(srcFile);
    fclose(dstFile);
}

7、总结

我们用了三篇文章的篇幅,学习了 指针,结构体,枚举字符串操作和文件的操作,对NDK开发来说,C语言的学习就告一段落。接下来继续进行NDK开发的前置学习C++。