Bootstrap

NDK开发—C语言基础

数据类型

实例1

各数据类型对应的占位符

#include <stdio.h>

int main2() {
    printf("T2的世界!\n");
    int i=100;
    double d=200;
    long l=200;
    short a=100;
    float s=200;
    char c='d';
    char * str="World Hello";
    printf("i的值为%d\n",i);
    printf("d为%lf\n",d);
    printf("s为%f\n",s);
    printf("c为%c\n",c);
    printf("str为%s\n",str);

    return 0;
}

非0即true 除了0之外都是true

实例2

字节长度 使用sizeof获取

#include <stdio.h>

int main3() {
    printf("int数据的字节:%d\n", sizeof(int));
    printf("double数据的字节:%d\n", sizeof(double ));
    printf("char数据的字节:%d\n", sizeof(char));
    return 0;
}

实例3

取地址符&

#include <stdio.h>

int main4(){
    int num1=10001;
    printf("此number1变量的地址是%p\n",&num1);

    return NULL;
}

C语言中万物皆地址

#include <stdio.h>

int main5(){
    int int_num=100;
    double double_num=200;
    printf("intnum的值为:%d\n",int_num);
    printf("intnum的值为:%lf\n",double_num);
    printf("地址取intnum的值为:%d\n",*(&int_num));
    printf("地址取intnum的值为:%lf\n",*(&double_num));

    int * intP=&int_num;
    double * pDouble=&double_num;

    printf("intnum的值为:%d\n",*intP);
    printf("intnum的值为:%lf\n",*pDouble);
    return NULL;
}

如int_num的地址为001H 而 &int_num=001H ,*为获取地址的值,如 * (&int_num)获取&int_num的值,即获取地址为001H的值,100

操作变量值,需要对地址进行操作

#include <stdio.h>

int main6(){
    int i = 100;
    int *p = &i;
    *p +=100;
    printf("i的值为:%d\n",i);
}

函数

#include <stdio.h>
// void  change(int i); C不能函数重载

void changea(int * i);
int main7(){

    int i = 100;
    changea(&i);
    printf("%d\n",i);

    return 0;
}

//void  change(int i){
//    i=200;
//}

//使用指针

void changea(int * i){
    *i=666;
}

函数体在main()函数前可不用声明,在main函数后需要声明。

注:

  • 声明可以不带参数,因为c语言不支持函数重载,函数名唯一
  • 操作变量赋值,需要传入变量的地址,如void change(int i)传入的为数值不能修改i值,而void changea(int * i)能修改i的值

参数交换实例

#include "stdio.h"


//由于C不支持重载,不需要写参数,根据名字即可找到对应
void change(int *pInt, int *pInt1);

int main() {

    int a = 100;
    int b = 200;

    change(&a, &b);
    printf("交换后a=%d,b=%d\n",a,b);
}

void change(int *pInt, int *pInt1) {

    int numA= *pInt;
    *pInt=*pInt1;
    *pInt1=numA;
}

指针和数组

#include <stdio.h>

int main2() {

    int num = 999;

    //最多三级指针
    int * num_p = &num;

    int ** num_p_p = &num_p;

    int *** num_p_p_p = &num_p_p;

    printf("num_p的值:%p, num_p_p的值是:%p, num_p_p的值是:%p\n",num_p,num_p_p,num_p_p_p);

    printf("获取最终的值:%d\n",***num_p_p_p);

    return 0;
}

指针自身也有地址,于是存在嵌套,多级指针便是嵌套,使用*获取下一层的值如 *** num_p_p_p的获取流程:先获取到num_p_p所对应的值&num_p再获取&num所对应的值,再获取这个地址所对应的值

#include "stdio.h"

int main() {

    int arr[]={1,2,3,4};

//    for (int i = 0; i < 4; ++i) {
//
//    }
    int i=0;
    for (i = 0; i < 4; ++i) {
        printf("数组%d的值%d\n",i,arr[i]);
    }
    printf("arr = %p \n",arr);
    printf("&arr = %p \n",&arr);
    printf("&arr[0] = %p \n",&arr[0]);
}
//数组的内存地址 == 第一个元素的内存地址 == &arr
//数组的内存地址 == 第一个元素的内存地址,不是其他元素的
    int * arr_p=arr;
    printf("%d\n",*arr_p);
取到的也是数组第一个的值
int i=0;
for (int i = 0; i < 4; ++i) {
    printf("数组%d的值%d\n",i,arr[i]);
}

为兼容写法,c语言不同java一处编译处处可行,c语言编译器不同环境不同语法有差异

指针位移

int * arr_p=arr;

printf("%d\n",*arr_p);//1

arr_p++;

printf("%d\n",*arr_p);//2

arr_p += 2;

printf("%d\n",*arr_p);//4

arr_p -= 3;//挪到到元素1

printf("%d\n",*arr_p);//1

arr_p += 3000;

printf("%d\n",*arr_p);//输出系统值 不会越界 野值

指针遍历数组

#include "stdio.h"

int main() {

    int arr[] = {1,2,3,4};

    int * arr_p = arr;

    int i=0;

    for (i = 0; i < 4; ++i) {
        printf("位置%d的值为:%d\n",i,*(arr_p+i));

        printf("位置%d的内存地址值为:%d\n",i,(arr_p+i));
    }
}

输出为

位置0的值为:1
位置0的内存地址值为:15989356
位置1的值为:2
位置1的内存地址值为:15989360
位置2的值为:3
位置2的内存地址值为:15989364
位置3的值为:4
位置3的内存地址值为:15989368

地址每次加4,因为int 的字节为4

**结论:**数组为连续的内存空间(没有断层,有规律),每次挪动的是数组类型的大小,如int 每次挪动4个字节

循环给数组赋值

#include <stdio.h>

int main() {

    int arr[4];
    int *arrp = arr;

    int i = 0;

    //sizeof(arr) == sizeof arr
    for (i = 0; i < sizeof arr / sizeof(int); ++i) {
        //拿到数组元素地址
        *(arrp + i) = (i + 10000);
    }

    //遍历输出

    for (int j = 0; j < sizeof arr / sizeof(int); ++j) {
        printf("位置%d的值为:%d\n",j,*(arrp+j));
    }
    return 0;
}

sizeof arr=16 ,sizeof(int)=4

数组指针操作的几种方式

#include <stdio.h>

int main() {

    int arr[] = {123,22,33,44214};
    int *arrp = arr;

    int i = 0;


    for (int i = 0; i < sizeof arr / sizeof(int); ++i) {
      //  printf("%d\n",arrp[i]);

       printf("%d\n",*(arrp+i));//挪动到元素 i 再取元素i内存地址所对应的值

      //  printf("%d\n",*arrp+i);//
    }
    return 0;
}

指针类型的用处

  • 任何类型的指针占用的空间大小都是相同的(32位CPU是4字节;64位CPU是8字节)
  • 既然任何类型的指针占用的空间大小都是相同的,为什么指针还需要类型呢?指针只是指向了一个内存地址,但是当存内存中取值的时候,系统不知道你要从当前指针指向的地址,取几个字节,指定了指针的类型后,系统就知道取几个字节了。char类型取1个字节,short类型取2个字节,int类型去4个字节。

指针函数

#include <stdio.h>

void add(int num1,int num2) {
    printf("num1 + num2 = %d\n", (num1 + num2));
}

void del(int num1,int num2) {
    printf("num1 - num2 = %d\n", (num1 - num2));
}
//操作回调

//void (*method)(int,int)声明好 函数指针

//void 返回值

// (*method) 函数名

//(int,int)两个参数
void opreate(void (*method)(int,int),int num1,int num2){
    method(num1, num2);
}

int main() {

    opreate(add,10,20);
    opreate(del,100,20);

    return 0;
}

原理:

add()和del()函数进栈,有各自的内存地址,如add()内存地址为100H,del为200H,void (*method)(int,int)可以接受地址传递, opreate(add,10,20)时传入地址100H, method(num1, num2)找到对应的函数,并且传入值进行操作,指向回调。

注:add和&add是同一地址

#include "stdio.h"

void callBackMethod(char * fileName, int current,int total){

    printf("图片%s压缩的进度是:%d/%d",fileName,current,total);

}

//定义函数指针  返回值(* 名称)(参数类型,参数类型...)
void  compress(char * fileName, void (*callBackP)(char *,int,int)){
    callBackP(fileName,5,100);
}
int main() {

    //先定义 再赋值
    void (* call)(char *,int,int) ;
    call = callBackMethod;//相同call = &callBackMethod;

    compress("海贼王",call);
    
    compress("derry.png",callBackMethod);

}

定义临时变量,不破坏原本的值,只破坏临时的值

静态开辟内存与动态开辟内存

随机数生成

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

int main() {


    //时间单位
    srand((unsigned ) time(NULL));

    //传入 &t &p可以直接传递 NULL尝试
    int i=10;
    for (i = 0; i <10 ; ++i) {
        printf("随机数%d\n",rand() % 100);
    }
    return (0);
}

c语言开发也需要看开发文档

字符拷贝

#include <stdio.h>
#include "string.h"
int main2() {
    char string[10];
    char *str1="asdfghjkz";
    strcpy_s(string,2,str1);
    printf("%s\n",string);
}

C中的布尔类型非0即1,0是false ,除外的都是true

静态开辟

请添加图片描述

main()函数执行在栈内,开始执行进栈,执行结束,弹栈

栈区平台大概2M 大于2M会栈溢出,如

#include "stdio.h"

//静态开辟
int main() {
    int arr[10*1024*1024]; //10M *4 =40M


    return (0);
}

就会发生栈溢出

堆区占用内存最大值大概是windows给编译器分配的空间的80%

#include "stdio.h"
#include <Windows.h>

//进栈
void staticAction() {
    int arr[5]; //栈区静态开辟

    for (int i = 0; i < 5; ++i) {
        arr[i] = i;
        printf("%d , %p\n",*(arr+i),arr+i);
    }
}
//执行完毕 弹栈

//静态开辟
int main() {

    while (1){
      Sleep(100);
        staticAction();
   }
    return (0);
}

main函数执行到 staticAction() , staticAction()会进栈,执行结束弹栈释放,因为死循环的原因 staticAction()会一直进栈弹栈

动态开辟

在堆区开辟内存都是动态的范畴

#include "stdlib.h"
#include <Windows.h>
//进栈
void sAction() {
    //void * 可以任意转换
    int * arr= malloc(1 * 1024 * 1024);
    
}
int main(){
    while (2){
        Sleep(100);
        sAction();
    }
}

使用malloc在堆区动态开辟,栈区回收,堆不会自动回收内存,内存会持续占用

请添加图片描述

内存会越来越大

释放free(arr);

如果不释放每次开辟的内存地址都不同,释放则会有相同的内存地址,如果释放只会不赋位null则会出现指针悬空

#include "stdlib.h"
#include <Windows.h>
//进栈
void sAction() {
    //void * 可以任意转换
    int * arr= malloc(1 * 1024 * 1024);

    free(arr);
    
    arr=NULL;//指向0x000000
}
int main(){
    while (2){
        Sleep(100);
        sAction();
    }
}

动态开辟的使用场景

#include "stdlib.h"
#include "stdio.h"

int main(){
    int num;
    printf("请输入一个数:");
    scanf("%d",&num);

    int * arr =(int *)malloc(sizeof(int) * num);
    int i=0;
    for (; i < num; ++i) {
        arr[i] = (i + 1001);
    }

    printf("开辟的内存指针:%p\n", arr);
    int j =0;
    for (; j < num; ++j) {
        printf("元素的值:%d, 内存地址:%p\n",*(arr+j),(arr+j));


        //在堆区开辟新的空间,加长空间大小
        //新增
    }
    int new_num;
    printf("请输入一个数:");
    scanf("%d",&new_num);

    //原来的那块内存大小+新增的大小
    int * new_arr =(int *)realloc(arr,sizeof(int) * (num + new_num));

    if(new_arr){
        i=0;
        for (; i < num + new_num; ++i) {
            arr[i]=(1001 + i);
        }

        printf("新开辟的内存指针:%p\n", new_arr);

        int k=0;
        for (; k < num + new_num; ++k) {
            printf("新元素的值:%d, 内存地址:%p\n", *(arr + k), (arr + k));
        }
    }
    if(new_arr){
        free(new_arr);
        new_arr = NULL;
        arr = NULL;
    } else{
        free(arr);
        arr = NULL;
    }

    return 0;
}

空间复用,第二个数组指针位置还是第一个数组,如果内存地址不同则可能是新的数组开辟空间时被系统占用,从而开辟新的内存地址,若内存不足则返回NULL。最后释放的时候,如果新开辟成功了,则释放新的内存,但是两个指针都指向同一地址,都为悬空,若开辟失败则只释放原始数组即可。

操作字符串

两种方式

int main(){
    char str[] ={'H','E','L','L','O'};
    str[2] = 'M';
    printf("第一种方式%s\n",str); //printf 必须遇到 \0才结束 后边会出现系统值

    char * str2 = "HELLO";
    str2[2] = 'M';
    printf("第二种方式%s",str2);
    return 0;
}

结果

第一种方式HEMLO烫烫烫坛D蕳澉╔?I
第二种方式HEMLO
#include "stdio.h"

int main(){
    char str[] ={'H','E','L','L','O','\0'};
    str[2] = 'M';
    printf("第一种方式%s\n",str); //printf 必须遇到 \0才结束 后边会出现系统值

    char * str2 = "HELLO";
    str2[2] = 'M';
    printf("第二种方式%s",str2);
    return 0;
}

则正常,第二种是隐式自动加上\0

注意

char * str2 = "HELLO";
str2[2] = 'M';
printf("第二种方式%s",str2);

会造成崩溃,因为str2指向的是一个内存地址,没有权限修改值,而第一种是把全局区域的值copy到了栈区,可以修改,但是高版本的clion自动兼容了第二种写法,但是在语法上是不允许的

指针挪动获取字符串信息

#include "stdio.h"

int getLen(char *string){
    int count = 0;

    while (*string) {
        string++;
        count++;
    }

    return count;
}

int main(){
    char string[] = {'A','B','C','D','E','\0'};

    int r = getLen(string);
   //方式二 int rr = sizeof(string)/ sizeof(int);
    printf("长度是%d \n",r);
    return 0;
}

数组作为参数传递不能使用

int getLen(char *string1){
    int count = 0;

    while (*string1) {
        string1++;
        count++;
    }

    return sizeof(string1)/ sizeof(char *);
}

返回值会一直是1,把数组作为了一个整体

#include <stdio.h>

void getLen(int * result,int intarr[]){

    int count = 0;
    //手动计算
    while (*intarr){
        intarr++;
        count++;
    }

    *result = count;
}

int main(){
    int intarr[] = {1,2,3,4,5,6,7,'\0'};

    int len= sizeof(intarr) / sizeof(int);

    printf("长度是%d",len);

    int result; //&取出result遍历的地址给函数

    getLen(&result , intarr);

    printf("getLen长度是%d",result);
    return 0;
}

一般写法函数无返回值,传入一个地址接受最后的结果,然后再拿到这个结果,int数组建议使用sizeof(intarr) / sizeof(int)因为无法区分0和’\0’,有冲突

字符串的比较和转换

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

int main(){
    //字符串转换
    char *num = "1";


    int result = atoi(num);
    if(result){
        printf("转换成功,%d\n",result);
    }

    num="123.456";
    double result2 = atof(num);
    if(result2){
        printf("转换成功,%lf\n",result2);
    }

    //字符串比较

    char * str1 = "ABC";
    char * str2 = "abc";


  // int res = strcmp(str1 , str2); //相等则0 不等则非0 区分大小写
   int res = strcmpi(str1 , str2); //相等则0 不等则非0 不区分大小写
   if(!res){
       printf("相等");
   } else {
       printf("不相等");
   }
}

字符串查找,拼接,包含

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

int main(){

    char * test = "Hello World!";

    char * tag = "l";

    char * pop = strstr(test , tag); //从第二个参数的的第一次出现的位置截取到最后

    if(pop){ //非NULL就查找到了
        printf("找到了 ,pop的值是%s\n",pop); //找到即是包含
    } else {
        printf("未找到!");
    }

    //求取位置

    int index = pop - test; // 指针相减

    printf("第一次出现的位置是%d\n",index);


    //字符拼接

    char des[25]; //容器

    char * blank = "到", *bj="北京" , *sh = "上海";

    strcpy(des,bj); //先copy到数组中

    strcat(des, blank); //再拼接数组

    strcat(des, sh); //继续拼接

    printf("拼接后的结果: %s \n",des);

    return 0;

}

大小写转换

#include "stdio.h"
#include "ctype.h"

void change(char *tran,char * name) {

    //定义临时变量防止破环指针
    char * temp =name;
    while (* temp){
        *tran = tolower(*temp);
        temp++;
        tran++; //转换 挪动 赋值
    }
    *tran = '\0'; //避免打印系统值
}

int main(){

    char * name = "ZhangSan";

    char tran[20];

    change(tran , name);
    printf("小写转换后的:%s",tran);

    return 0;
}

自定义截取指定位置

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
void AtoB(char * res,char * str,int  star,int  end){
    int t = end - star;
    while (star--){
        str++;
    }
    while (t--){
        *res = *str;
        str++;
        res++;
    }
    * res = '\0';
    printf("t=%d,star=%d,end=%d\n",t,star,end);
}
//利用堆和栈
void AtoB2(char ** res,char * str,int  star,int  end){
    char *tmp = str;
    char rest[end-star];
    int count = 0;
    for (int i=star; i<end; ++i){
        rest[count] = * (tmp +i);
        count++;
    }
	//*res = rest; 防止容器回收 为空
    strcpy(*res,rest);//第一种解决方案
    //第二种 rest= malloc(end - star); 栈区变成堆区 尽量不用 需要手动回收
    
}

void AtoB3(char * res,char * str,int  star,int  end){
    for (int i = star; i < end; ++i) {
        *(res++) = *(str + i);
    }
}

void AtoB4(char * res,char * str,int  star,int  end){
    strncpy(res,str+star,end-star);
}
int main(){
    char *str = "ABCDEF";

    char * result = (char *)malloc(sizeof(char) * *str);

    AtoB(result,str,2,5);
	//AtoB2(&result,str,2,5); 传入一级指针地址,二级指针接受,直接给一级指针赋值 但是函数弹栈会回收所有栈成员 包括 rest[end-star]
    printf("截取后:%s",result);
}

结构体与结构体指针

写法1

#include "stdio.h"
#include "string.h"
#include "malloc.h"
#include "stdlib.h"

struct Dog{

    char name[10];
    int age;
    char sex;


};//必须写;结束


int main(){

    struct Dog dog;//暂未初始化 是系统值 必须写 struct标识

    //赋值

    strcpy(dog.name,"旺财"); //不可直接赋值
    dog.age = 1;
    dog.sex = 'G';
    printf("name=%s,age=%d,sex=%c",dog.name,dog.age,dog.sex);


}

写法2 初始化的时候直接赋值

#include "stdio.h"
#include "string.h"
#include "malloc.h"
#include "stdlib.h"

struct Person{

    char *name;

    int age;

    char sex;

}
p1 = {"张三",18,'W'},
p2 = {"A",25,'M'},
p3
;

int main(){

    printf("name=%s,age=%d,sex=%c",p1.name,p1.age,p1.sex);

};

也可以先初始化实例,后续再赋值

常规嵌套

#include "stdio.h"
#include "string.h"
#include "malloc.h"
#include "stdlib.h"

struct Study{
    char * course;
};

struct Student{

    char *name;
    int age;
    char sex;
    struct Study study;
    struct play{
        char * playgame;
    }game;

};


int main(){

    struct Student st1 = { "张三",18,'m',{"安卓"},{"篮球"}};

    printf("name=%s,age=%d,sex=%c,学习=%s,玩=%s",st1.name,st1.age,st1.sex,st1.study.course,st1.game.playgame);

}

结构体指针

#include "stdio.h"
#include "string.h"
struct Cat{
    int name[10];
    int age;
};


int main(){
    struct Cat cat1={"叮当",1};

    struct Cat * cap = &cat1;

    cap->age = 3; //.是结构体 ->调用一级指针
    strcpy(cap->name,"兰兰");

    printf("name=%s,age=%d\n",cap->name,cap->age);
    printf("name=%s,age=%d\n",cat1.name,cat1.age);
}

使用堆区

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

struct Cat1{
    char name[10];

    int age;
};

int main() {

    struct Cat1 *cat = malloc(sizeof(struct Cat1));

    strcpy(cat->name,"金吉拉");
    cat->age = 1;
    printf("名字%s,年龄%d\n",cat->name,cat->age);

    free(cat);
    cat = NULL;

    return 0;
}

结构体数组

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

struct Cat3{
    char name[10];
    int age;
};

int main() {
    //栈区
    struct Cat3 cat [10] = {
            {"叮当",1},
            {"喵喵",2},
            {"猫猫",2},
    };

    struct Cat3 cat9 = {"啊黄",2};
    //cat [9] = cat9;

    *(cat + 9) = cat9;
    printf("name%s,age%d\n",cat9.name,cat9.age);

    //堆区 动态开辟
    struct Cat3 *cat2 = malloc(sizeof(struct Cat3) * 10);

    strcpy(cat2->name,"大橘");
    cat2->age = 5;
    printf("name%s,age%d\n",cat2->name,cat2->age);

    //给第八个元素赋值

    cat2 += 7;
    strcpy(cat2->name,"小黑");
    cat2->age = 3;
    printf("name%s,age%d\n",cat2->name,cat2->age);
    free(cat2);
    cat2 = NULL;

    return 0;
}

结构体别名 解决兼容性问题

#include "stdio.h"
#include "stdlib.h"

struct DAO {
 char name[10];
 int age;
 char sex;

};

typedef struct DAO DAO;

typedef DAO * DAO_;

int main(){
    DAO_ *dao = malloc(sizeof(DAO));

}

使用typedef起别完别名后 不需要引用的时候加struct关键字,就实现了不同平台代码一致

进阶

#include "stdio.h"
#include "stdlib.h"

//匿名结构体的别名 源码
//给结构体AV取别名AV
typedef struct {
    char name[10];
    int age;
    char sex;

} AV;
int main(){
    AV av = {

    };

    AV *pav = malloc(sizeof(AV));

    
}

枚举

#include "stdio.h"

typedef enum{
    TEXT = 10,
    TEXT_IMAGE,
    IMAGE
} CommenType;
int main(){
    //Clion写法
    // enum CommenType commenType =  TEXT;

    //VS写法
    // CommenType commenType =  TEXT;

    CommenType commenType =  TEXT;
    CommenType commenType2 =  TEXT_IMAGE;
    CommenType commenType3 =  IMAGE;

    printf("%d,%d,%d \n" , commenType , commenType2 , commenType3);
}

游戏破解与文件加解密

对于C拿到内存地址即可修改一切,最难的是地址的寻找

文件读写操作

读取
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

int main(){
    //参数1 文件路径 ,参数2 模式 r读 w写 rb二进制文件读 wb二进制文件写
    // 返回值是结构体
    //fopen();

    char * fileNameStr = "D:\\aaa.txt";

    FILE * file= fopen(fileNameStr,"r");

    if(!file){
        printf("文件打开失败,请检测文件路径%s\n",fileNameStr);
        exit(0);
    }

    //定义缓冲区

    char buff[1024];

    //缓冲区buff  长度 文件指针变量
    while (fgets(buff, 1024, file)){
        printf("%s",buff);
    }

    //关闭文件
    fclose(file);
}
写入
#include <stdlib.h>
#include "stdio.h"
int main(){
    char * fileNameStr = "D:\\aaa.txt";

    //不存在会自动生成文件 无需判断
    FILE * file= fopen(fileNameStr,"w");


    if(!file){
        printf("文件打开失败,请检测文件路径%s\n",fileNameStr);
        exit(0);
    }
    fputs("This is C code",file);

    fclose(file);

    return 0;
}

文件复制

#include <stdlib.h>
#include "stdio.h"
// 二进制文件复制
int main(){
    char * fileNameStr = "D:\\aaa.txt";  //来源
    char * fileNameCopy = "D:\\acopy.txt";  //目标
    //读取二进制数据
    FILE * file= fopen(fileNameStr,"rb");
    FILE * file2= fopen(fileNameCopy,"wb");

    if(!file || !file2){
        printf("文件打开失败,请检测文件路径%s\n",fileNameStr);
        exit(0);
    }

    int buffer[512];

    int len; //每次接收长度

    //参数1 容器buff 参数2 每次偏移多少 参数3 容器大小 参数4文件指针
    while ((len = fread(buffer,sizeof(int), sizeof(buffer)/sizeof (int),file))!=0){
        fwrite(buffer,sizeof(int),len,file2);
    }

    fclose(file);
    fclose(file2);
}

文件大小获取

没有专门的API 用获取头指针,挪动位置,挪动到最后即可求得文件大小

#include <stdlib.h>
#include "stdio.h"
// 二进制文件复制
int main() {
    char *fileNameStr = "D:\\aaa.txt";  //来源

    FILE * file= fopen(fileNameStr,"rb");

    if(!file ){
        printf("文件打开失败,请检测文件路径%s\n",fileNameStr);
        exit(0);
    }
 	//SEEK_SET(开头) SEEK_CUR(当前) SEEK_END(结尾)
    fseek(file, 0, SEEK_END);//文件指针,起始点 结尾

    //执行后file有了更丰富的值

    //读取刚刚给file赋值的信息
    long file_seze= ftell(file);
    fclose(file);
    printf("%s文件的字节大小是:%ld",fileNameStr,file_seze);

}

文件加解密

加密
#include <stdlib.h>
#include "stdio.h"
// 二进制文件复制
int main() {

    char *fileNameStr = "D:\\tx.jpg";  //来源

    char *fileNameStrEncode = "D:\\tx_encode.jpg";  //加密的目标

    FILE * file= fopen(fileNameStr,"rb");

    FILE * fileEncode= fopen(fileNameStrEncode,"wb");


    if(!file || !fileNameStrEncode){
        printf("文件打开失败,请检测文件路径%s\n",fileNameStr);
        exit(0);
    }
    //加密==破坏文件 解密==还原文件
    //加密 :把每个字节都拿出来 对一个字节都处理(全部加密)。(处理部分内容)
    //TODO 加密
    //while 每个字节取出来 10
    //10^异或5
    //TODO 解密
    //while 再 异或5还原
    int c; //接收读取的值
    //fgetc 返回值 EOF=-1 结束
    while ((c = fgetc(file)) != EOF) {
        //加密
        fputc(c^5,fileEncode);
    }
    fclose(file);
    fclose(fileEncode);
    return 0;
}
解密
#include <stdlib.h>
#include "stdio.h"
// 二进制文件复制
int main() {



    char *fileNameStrEncode = "D:\\tx_encode.jpg";  //解密的目标

    char *fileNameStr = "D:\\tx_encode_sol.jpg";  //解密后
    FILE * file= fopen(fileNameStrEncode,"rb");

    FILE * fileEncode= fopen(fileNameStr,"wb");


    if(!file || !fileEncode){
        printf("文件打开失败,请检测文件路径%s\n",fileNameStr);
        exit(0);
    }
    //加密==破坏文件 解密==还原文件
    //加密 :把每个字节都拿出来 对一个字节都处理(全部加密)。(处理部分内容)
    //TODO 加密
    //while 每个字节取出来 10
    //10^异或5
    //TODO 解密
    //while 再 异或5还原
    int c; //接收读取的值
    //fgetc 返回值 EOF=-1 结束
    while ((c = fgetc(file)) != EOF) {
        //加密
        fputc(c^5,fileEncode);
    }

    fclose(file);
    fclose(fileEncode);
    return 0;
}
使用密钥

加密

#include <stdlib.h>
#include "stdio.h"
#include "string.h"
// 使用
int main() {

    char *fileNameStr = "D:\\tx.jpg";  //来源
    char *fileNameStrEncode = "D:\\tx_encode.jpg";  //加密的目标

    FILE * file= fopen(fileNameStr,"rb");
    FILE * fileEncode= fopen(fileNameStrEncode,"wb");

    if(!file || !fileEncode){
        printf("文件打开失败,请检测文件路径%s\n",fileNameStr);
        exit(0);
    }
    // 密钥
    char * password = "123456";
    int c;
    int index = 0;
    int pass_len = strlen(password);

    while ((c = fgetc(file) != EOF)){
        char item = password[index % pass_len];

        printf("intm:%c\n",item);
        fputc(c ^ item,fileEncode);
        index ++;
    }
    fclose(file);
    fclose(fileEncode);
}

解密

#include <stdlib.h>
#include "stdio.h"
#include "string.h"
// 使用
int main() {

    char *fileNameStr = "D:\\tx_encode.jpg";  //加密的来源
    char *fileNameStrEncode = "D:\\tx_encode_cx.jpg";  //解密

    FILE * file= fopen(fileNameStr,"rb");
    FILE * fileEncode= fopen(fileNameStrEncode,"wb");

    if(!file || !fileEncode){
        printf("文件打开失败,请检测文件路径%s\n",fileNameStr);
        exit(0);
    }
    // 密钥
    char * password = "123456";
    int c;
    int index = 0;
    int pass_len = strlen(password);

    while ((c = fgetc(file) != EOF)){
        fputc(c ^ password[index%pass_len],fileEncode);
        index ++;
    }
    fclose(file);
    fclose(fileEncode);
}
;