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++。