20160220.CCPP体系详解(0030天)
程序片段(01):对称.c
内容概要:对称
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//01.对称原理:
// 1.双索引or双指针-->双边对称夹逼-->进行字符比对
// 2.判断存在情况,默认所有情况
int isSemmetry(char * pStr)
{
char * p1 = pStr;
char * p2 = pStr + strlen(pStr) - 1;
while (p1 < p2)
{
if (*p1 != *p2)
{
return 0;
}
--p2;
++p1;
}
return 1;
}
//01.所有位于栈内存的静态数组:
// 1.只要存在静态前置初始化,就一定存在静态后续默认初始化
// 2.字符串数组可以通过字符串拷贝实质初始化
int main01(void)
{
//char str[1024] = "";//""是一种初始化方式
char str[1024] = { 0 };
scanf("%s", str);
printf("isSemmetry = %d \n", isSemmetry(str));
system("pause");
}
程序片段(02):指针.c
内容概要:指针
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
//01.指针内容大总结:
// 1.按照所指向内存实质的不同:
// 数据区:数据指针
// 代码区:函数指针
// 2.按照常变量的不同特点:
// 常量指针
// 变量指针
// 3.两种不同类型的常变量指针特点:
// 数据指针:
// 常量指针:
// 添加星号("*")右侧的const关键字
// 所有数组名称
// 变量指针:
// 常规形式
// 函数指针:
// 常量指针:
// 函数名称
// 变量指针:
// 常规形式
//02.间接修改数据和调用函数的不同:
// 间接修改数据:
// 数据指针
// 需要指向变量的指针!
// 间接调用函数:
// 函数指针
// 必须得是函数指针变量
//注:严格区分跨函数间接调用还是本函数间接调用:
// 本函数间接调用:只需函数指针变量
// 跨函数间接调用:必须指向函数指针的指针(二级函数指针)
//03.跨函数修改函数指针变量不成功的原因:
// 1.严格区分跨函数(跨进程)和非跨函数
// 2.跨进程要注意外部对内部访问权限的满足情况
// 3.安全软件劫持跨进程调用
// 4.Debug和Release模式的不同特点
// 5.跨进程访问并开启新的进程
// 进程1告诉进程2开启进程3
//04.严格区分是打开线程还是打开进程的特点
// 所导致的差异
void run()
{
//system("pause");
MessageBoxA(0, "haihua", "fangfang", 0);
}
void test()
{
MessageBoxA(0, "fangfang", "haihua", 0);
}
int main(void)
{
int num = 10;//数据区
//run,&run,*run所获取的数值都是一样的,都是同一块儿还是实体的入口点
printf("&num = %p, run = %p, &run = %p, *run = %p \n", &num, run, &run, *run);
//同一个函数实现间接调用-->只需函数指针变量
void(*pFun)() = run;
printf("&pFun = %p, test = %p \n", &pFun, test);
while (1)
{
//printf("%d \n", num);
pFun();
Sleep(3000);
}
system("pause");
}
程序片段(03):dll.c
内容概要:外部间接修改调用
#include <stdio.h>
//01.注入函数的执行特点:
// 在执行注入操作的那一刻
// 注入的指定函数被直接加载进注入进程所占用的进程当中
// 并且此时所注入的指定函数位于运行时堆栈(栈顶)当中
// 也就注入之后,立即得到执行
// 执行的结果显示于所注入的进程当中
//02.严格区分地址与指针之间的区别:
// 空指针(空指针变量):存储的是地址
// 指针(常量指针和变量指针:存储的是指针
// 注:地址不具备解析意义,指针具备解析意义!
//03.跨进程调用和跨进程修改调用:
// 跨进程调用:
// 一级函数指针变量(需要函数常量指针)
// 跨进程修改调用:
// 二级函数指针变量(需要函数变量指针)
//04.经过测试,要想实现函数的间接调用:
// 必须使用函数变量指针,不能使用函数常量指针
_declspec(dllexport) void go()
{
printf("注入成功! \n");
//数据区-->数据指针-->跨函数间接修改数据
//int * pNum = (int *)0x004FFC0C;
//*pNum = 1000;
//代码区-->函数指针-->跨函数间接调用函数-->获取调用行为
//void(*const pFun)() = (void(*)())0x0032136B;//函数常量指针不能够实现间接调用
//void(*pFun)() = (void(*)())0x009E136B;//函数指针变量
pFun();
//代码区-->二级函数指针-->跨函数修改调用-->修改调用行为
//void(**ppFun)() = (void(**)())0x0018F914;
//*ppFun = (void(*)())0x0134136B;
}
程序片段(04):01.结构体.c+02.结构体定义变量.c+03.结构体变量初始化.c
内容概要:结构体定义
///01.结构体.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//01.结构体:
// 用法:
// 可以用于组合不同类型的多个变量
// 举例:
// 待拆分的字符串整体:
// tyhyxs_fw@163.com,袁可,长治路303号大生科技楼411室,3517027946,15110340952,14.90
struct DangDang01
{//定义方式一:标准形式
char email[20];
char name[20];
char addr[100];
long long QQ;
long long mobile;
double price;
};
//02.结构体嵌套定义特点:
// 1.结构体之间可以进行嵌套定义(不同)
// 并且支持结构体多层嵌套定义
// 2.结构体本体不能进行嵌套定义(相同)
//注:严格区分是否能够准确分配内存大小!
// 这是结构体是否能够成功定义的判断条件
struct DangDang02
{
int num;
struct DangDang01 dd01;//不同
//struct DangDang02 dd02;//本体
};
struct DangDang03
{
int num;
struct DangDang02 dd02;
};
//03.结构体类型定义的两种方式:
// 方式一:标准形式:
// 方式二:匿名形式
// 用作锁定结构体变量的定义数量,可以用作权限控制
// 方式三:简写形式
struct
{//定义方式二:匿名方式
char email[20];
char name[20];
char addr[100];
long long QQ;
long long mobile;
double price;
} boss;//匿名结构体:用于锁定结构体变量的定义数量[经常用作权限控制]
//04.结构体成员的作用范围:
// 仅仅作用于当前结构体变量范围之内,外部不可直接进行访问
//05.结构体成员变量的初始化方式:
// 1.在定义结构体变量的同时完成初始化:
// (1).可以采用指定成员指定初始化,其余成员默认初始化的方式
// 如果是字符串同样可以采用指定初始化方式,而无需使用strcpy();完成初始化操作
// (2).如果是整体初始化:
// 就可以按照非指定初始化方式进行初始化,结构体成员按照顺序进行初始化,此状态
// 下的结构体成员(字符串)也同样可以直接完成初始化操作(无需借助strcpy();函数)
// 2.其余赋值情况:
// 既不能使用指定初始化方式,而且还不能使用非strcpy();函数完成字符串初始化操作!
//注:凡是基于非初始化状态下的结构体变量赋值都必须采用strcpy();函数完成结构体成员
// 字符串的赋值操作
int main01(void)
{
//price;//结构体成员的作用范围:仅仅作用于当前结构体变量定义范围之内
strcpy(boss.email, "tyhyxs_fw@163.com");
strcpy(boss.name, "袁可");
strcpy(boss.addr, "长治路303号大生科技楼411室");
boss.QQ = 3417027946;
boss.mobile = 15110240952;
boss.price = 14.90;
printf("%s, %s, %s, %lld, %lld, %lf \n", boss.email, boss.name, boss.addr, boss.QQ, boss.mobile, boss.price);
system("pause");
}
///02.结构体定义变量.c
#include <stdio.h>
#include <stdlib.h>
//01.结构体类型特点:
// 1.定义的结构体类型只是会作用于本文件当中,跨文件无效!
// 定义的结构体类型作用域:定义位置开始+本文件结束
// 因此,结构体类型常常被定义与头文件当中(以备其他文件所使用)
struct DangDang01
{
char email[20];
char name[20];
char addr[100];
long long QQ;
long long mobile;
double price;
} dd03, *pDD04, dd05[10];
//02.结构体类型的简化形式:
// 宏定义简化:
// #define DangDang struct DangDang01
// 关键字简化:
// typedef struct DangDang01 DnagDang;
//注:严格区分这两种方式所定义变量的区别
// 尤其是在同时定义多个变量的时候;
// 尤其是在定义指针变量的时候!
//03.结构体定义特点:
// 1.既可以定义于函数外部,也可以定义于函数内部
// 2.如果出现同名的结构体类型定义,按照从前往后
// 的就近原则进行准确区分!
#define DANGDANG struct DangDang01
int main02(void)
{
struct DangDang01 dd06;
struct DangDang01 * dd07, dd08;//结构体指针变量+结构体普通变量
DANGDANG * dd09, dd10;//同上!
struct DangDang01 dd11[3];
struct DangDang01 dd12[3][4];
struct DangDang01
{
int num;
double price;
} dd13;
dd13.num = 10;
dd13.price = 99.0;
system("pause");
}
///03.结构体变量初始化.c
#include <stdio.h>
#include <stdlib.h>
//01.C99新语法之结构体变量初始化:
// C99新语法当中的结构体整体可以看做为
// 一个数组进行静态初始化,不过没有索引
struct MyStruct01
{//初始化方式一:全体成员初始化
int num;
char str[10];
} ms01 = { 10, "123" }, ms04 = {.num = 10, "123"};
struct MyStruct01 ms02 = { 10, "123" };
//初始化方式二:指定成员初始化
struct MyStruct01 ms03 = { .num = 10,.str = "123" };
//02.结构体初始化方式:
// 1.全体成员初始化:
// 按照成员的顺序进行完整初始化
// 2.指定成员初始化:
// 通过点儿号('.')代表结构体变量本体,执行指定初始化操作
// 一旦存在指定初始化的操作,就存在默认初始化操作
//注:只有在初始化的赋值情况之下才存在指定初始化的操作
// 其他情况之下的赋值操作不具备指定初始化的特点
// 指定初始化的赋值操作同样适用于匿名结构体
struct
{
int num;
char str[10];
} ms05 = { .num = 10,.str = "123" };
int main03(void)
{
printf("%d, %s \n", ms01.num, ms01.str);
printf("%d, %s \n", ms02.num, ms02.str);
printf("%d, %s \n", ms03.num, ms03.str);
printf("%d, %s \n", ms04.num, ms04.str);
printf("%d, %s \n", ms05.num, ms05.str);
struct MyStruct01 ms06;
//ms05.str = "123";//结构体变量当中的字符串成员只有在初始化的条件下进行字符串赋值无需strcpy();函数
//其它情况之下的赋值操作都必须依赖于strcpy();函数完成对字符串成员的赋值操作
system("pause");
}
程序片段(05):01.引用结构体.c+02.结构体深浅拷贝.c
内容概要:结构体引用
///01.引用结构体.c
#include <stdio.h>
#include <stdlib.h>
//01.结构体类型定义特点:
// 定义结构体类型的时候,不允许对结构体成员实施初始化操作!
// (结构体类型成员默认初始化操作!)
//注:此条法则只是针对于C语言有效,针对于C++语言是无效的!
struct MyStruct01
{
int num;
char str[10];
//double db = 99.0;
};
struct MyStruct02
{
struct MyStruct01 ms01;
int num;
char str[10];
};
//02.关于结构体当中的struct关键字:
// 在C语言当中,如果没有定义结构体类型别名的情况之下:
// 凡是使用结构体类型的时候都必须添加上struct关键字
//03.结构体成员在进行初始化的时候:
// 全体成员初始化:无需结构体成员名
// 指定成员初始化:必须结构体成员名
//04.同一类型的结构体变量之间支持赋值操作
//05.结构体嵌套形式的多层访问需要使用点儿号('.')
//06.结构体访问成员的两种方式:
// 结构体变量:点儿号('.')
// 结构体指针:箭头号('->')
//注:指针执行某个结构体,那么就能采用指针方式直接
// 访问结构体当中的该级成员
//07.结构体不支持整体打印操作:
// 需要逐级访问内部成员实现打印结构体内容
//08.针对于结构体变量整体的无意义运算符:
// 1.算数运算符(+,-,*,/,%)
// 1.自变运算符(++,--)
// 2.关系运算符(>,<,>=,<=,==,!=)
int main01(void)
{
struct MyStruct02 ms01 = { { 10, "calc"}, 101, "notepad" };
struct MyStruct02 ms02 = ms01;
ms01.ms01.num = 90;
ms01.num = 30;
printf("%d, %s, %d, %s \n", ms01.ms01.num, ms01.ms01.str, ms01.num, ms01.str);
printf("%d, %s, %d, %s \n", ms02.ms01.num, ms02.ms01.str, ms02.num, ms02.str);
system("pause");
}
///02.结构体深浅拷贝.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//01.浅拷贝和深拷贝:
// 1.其实浅拷贝和深拷贝的实质都是一样的:
// 都同样执行的是拷贝数据操作!
// 2.针对不同的拷贝对象,意义层次不同:
// 普通变量:拷贝的仅仅是数据本身而已
// 指针变量:拷贝的是指向实际数据的指针
//注:当结构体成员是属于数组类型的情况:
// 由于C语言当中的数组名称属于是常量指针,
// 因此,在进行结构体变量拷贝操作的时候,针对于
// 数组类型的成员执行的都是副本拷贝(深拷贝),而不是原本拷贝(浅拷贝)
//特:在结构体变量之间进行拷贝操作的时候,凡是涉及到数组类型的成员
// 拷贝操作,都是深拷贝,不会涉及到浅拷贝的情况!-->数组名:常量指针导致!
//02.结构体成员的深浅拷贝分类:
// 1.所有指针变量都涉及到深浅考别问题
// 2.由于数组名称是常量指针,因此只涉及到深拷贝问题,不会涉及到浅拷贝问题
// 3.其他类型的所有变量都只会涉及到浅拷贝问题!
//03.strcpy();函数的原理依赖于memset();函数进行实现!
struct MyStruct01
{
int num;
char * p;
int * px;
char arr[10];
};
//04.所有变量的赋值操作,默认情况之下都是浅拷贝操作:
// 因此,如果涉及到结构体变量的拷贝操作的时候,需要
// 根据成员需要,手动执行深拷贝操作!
//05.结构体成员深浅考别注意事项:
// 凡是涉及到指针变量的拷贝问题,都必须注意深浅拷贝问题!
//注:只需要注意指针变量的拷贝默认拷贝情况分析:
// 其实就是为了切断两个不同结构体变量之间的关联!
// 防止两个结构体变量共享一片儿内存!
int main02(void)
{
struct MyStruct01 ms01 = {.arr = "HaHaHa"};
ms01.num = 30;
ms01.p = malloc(20);
strcpy(ms01.p, "Hello World!");
struct MyStruct01 ms02 = ms01;//赋值操作:默认都是浅拷贝!
ms02.p = malloc(20);//以待深拷贝
ms02.p = strcpy(ms02.p, ms01.p);//替换浅拷贝
free(ms01.p);//浅拷贝情况之下会出现问题,深拷贝不会出现问题
printf("ms01.p = %s, ms02.p = %s \n", ms01.p, ms02.p);
printf("ms01.str = %s, ms02.str = %s \n", ms01.arr, ms02.arr);
system("pause");
}
程序片段(06):结构体赋值.c
内容概要:结构体赋值
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct MyStruct01
{
int arr[5];
char str[10];
char * p;
};
//01.结构体变量赋值:
// 1.首先拷贝深浅拷贝问题:
// 1.一旦涉及到指针(无论是常指针还是变指针),都会涉及到深浅拷贝问题
// 2.数组比较特殊,由于数组名不可直接通过赋值号进行修改,因此只有浅拷贝
// 区分:静态数组和动态数组(只有静态数组才会涉及到深浅拷贝问题!)
// 2.赋值号所做的只是浅拷贝动作而已
// 3.深浅拷贝的执行过程:
// 先执行浅拷贝操作,再执行深拷贝操作
//注:深浅拷贝的底层实现依赖于memcpy();函数
// 默认的浅拷贝操作只是简单的使用了memcpy();函数完成
//02.关于结构体初始化的注意事项:
// 1.大括号("{}")叫做静态初始化方式,只能用于具备初始化的赋值意义时期!
// 2.C99新语法之指定成员初始化方式只能用于静态初始化情况之下
//注:只有在初始化的情况之下对字符指针赋值无需strcpy();函数,其它情况之下
// 对于字符指针的赋值都必须依赖于strcpy();函数
//03.初始化情况也存在浅初始化和深初始化:
// 只要结构体的成员当中有指针就必定涉及到深浅问题!(拷贝+初始)
int main01(void)
{
struct MyStruct01 ms01 = { {1, 2, 3, 4, 5}, "calc", NULL };//浅初始化
ms01.p = (char *)malloc(30);//深初始化
strcpy(ms01.p, "HaiHuaLove");
struct MyStruct01 ms02 = ms01;//赋值号默认只是执行浅拷贝操作(针对于指针而言)
ms01.arr[3] = 'X';
ms01.str[2] = 'X';
*(ms01.p) = 'X';
free(ms01.p);//释放共享内存块儿
for (int i = 0; i < 5; ++i)
{
printf("%d, %d \n", *(ms01.arr + i), *(ms02.arr + i));
}
printf("%s, %s \n", ms01.str, ms01.str);
printf("%s, %s \n", ms01.p, ms02.p);
system("pause");
}
程序片段(07):进化论.c
内容概要:结构体嵌套
#include <stdio.h>
#include <stdlib.h>
struct Life
{//生物
int canMove;
};
struct Animal
{//动物
struct Life life;
int canRun;
};
struct Tiger
{//老虎
struct Animal animal;
int tooth;
int ismao;
};
//01.在C语言当中的结构体类型嵌套可以实现继承
// 1.在基于Windows的C语言编程过程当中,经常基于结构体实现单继承以及多继承
// 2.还可以实现多重继承(都是通过C语言当中的结构体完成实现!)
struct Human
{//人类
struct Animal animal;
char think[30];
};
//02.在C语言当中的所有数据结构体都依赖于结构体实现:
// 例如:二叉树这种数据结构体的实现!
struct BinTree
{
int num;//节点序号
struct BinTree * pLeftList;//指向左子树
struct BinTree * pRightList;//指向右子树
};
struct File
{//文件描述
int time;
int size;
int isBin;
int isExe;
};
//03.在C语言当中模拟磁盘文件系统:
// 磁盘系统可以通过结构体描述!
struct Dictory
{//目录描述
struct File * pFile;//动态数组管理多个文件
int fileNum;
struct Dictory * pDictory;//动态数组管理多个目录
int dictoryNum;
};
//04.在C语言当中模拟动态数组
struct Array
{//数组描述
int * pArr;
int length;
};
//05.总的来说,C语言的结构体作用:
// 1.可以描述C++语言的继承体系:
// 单继承+多继承+多重继承
// 2.用于组合多个不同类型的变量
// 数据封装体
// 3.所有标准数据结构的实现
// 4.所有扩充数据结构的实现
//注:所有复杂事物的描述
int main01(void)
{
system("pause");
}
程序片段(08):1.c+run1.c+run2.c
内容概要:头文件的作用以及结构体定义
///1.c
int num = 10;//定义并初始化一个变量
int add(int a, int b)
{
//函数的定义
}
///run1.c
#include "1.h"
///run2.c
#include <stdio.h>
#include "1.h"
//01.严格区分声明与定义之间的区别:
// 1.存在情况分析:
// 声明:只是说这个东西儿存在,但是并不一定存在(虚的)
// 定义:这个东西儿确实存在
// 2.存放位置不同:
// 声明:存放于头文件当中
// 定义:存放于源文件当中
// 3.包含性不同:
// 声明:由于声明可以进行重复声明,因此,可以重复包含
// 没有内存实体
// 定义:由于定义不能进行重复定义,因此,不能重复定义
// 存在内存实体
// 注:只有全局变量和函数存在声明和定义的区别,局部变量不存在区别
// 4.预编译和编译的不同:
// 预编译处理的是头文件
// 编译处理的是源文件(是在预编译之后的源文件)
//注:所有针对于类型的申明:
// 都只是作用于声明类型的文件本身:从声明位置起始,到本文件结束
// 所有全局内容的默认作用范围
// 当前定义文件起始,到跨文件范围之内
void main01()
{
struct MyStruct my01;
#include "2.h"//包含的只是内容而已
}
程序片段(09):LanMDa.cpp
内容概要:LanMda
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
//01.关于函数嵌套定义问题:
// C语言:既不允许函数的直接嵌套定义,也不允许函数的间接嵌套定义
// C++:只是不允许函数的直接嵌套定义,但是允许函数的间接嵌套定义
// 而这个间接嵌套定义的方式就是Lambda表达式
int add(int a, int b)
{
return a + b;
}
//02.C++语法之Lambda表达式
// [](函数形参){函数实体}(函数实参);
//03.C++语法之for循环:
// for (auto tmp : arr){printf("%d \n", tmp);};
//04.C++语法之增强for循环:
// for each(int tmp in arr){printf("%d \n", tmp)};
//05.C++语法之初始和赋值的区分:
// 初始格式:int num(10);
// 赋值格式:num = 20;
int main01(void)
{
[]() {system("notepad"); }();//最简单的Lambda表达式
[](int a, int b) {printf("a = %d, b = %d \n", a, b); MessageBoxA(0, "World", "Hello", 0); }(10, 20);
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (auto tmp : arr)
{
printf("%3d", tmp);
}
printf("\n");
for each(int tmp in arr)
{
printf("%3d", tmp);
}
printf("\n");
for each(auto tmp in arr)
{
printf("%3d", tmp);
}
printf("\n");
int num(10);
printf("num = %d \n", num);
num = 20;
printf("num = %d \n", num);
system("pause");
}
程序片段(10):01.时间优先压缩与解压缩.c+02.空间优先压缩与解压缩.c
内容概要:压缩与解压缩
///01.时间优先压缩与解压缩.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//01.数据压缩与解压缩涉及知识:
// 1.考虑时间和空间问题?
// 时间优先-->节省时间-->浪费空间
// 空间优先-->节省空间-->浪费时间
// 2.按照压缩单元问题区分?
// 单字符压缩
// 字符串压缩
//注:这里仅仅是对字符类型的数据实施压缩操作!
//02.如何选取具体的压缩算法?
// 1.电脑性能+占用空间:
// 时间优先or空间优先
// 2.数据操作方式:
// 双索引or双指针
// 3.压缩数据类型:
// 字符压缩or字符串压缩
//03.时间优先和空间优先的体现点:
// 看是否开辟了额外的内存空间:
// 如果已开辟:时间优先
// 如果未开辟:空间优先
char * timePriorityZip(char * pStr)
{
int pStrLen = strlen(pStr);
char * pZipStr = (char *)calloc(pStrLen + 1, sizeof(char));
char * pCopy = pZipStr;
while ('\0' != *pStr)
{
char * pTmpStr = pStr;
char tmpChr = *pStr;
int tmpStrLen = 0;
while (*(pTmpStr) == *(pTmpStr + 1))
{
++tmpStrLen;
++pTmpStr;
}
if (!tmpStrLen)
{
*pCopy = *pStr;
++pCopy;
++pStr;
}
else
{
*pCopy = tmpStrLen + 1 + '0';
*(pCopy + 1) = *pStr;
pCopy += 2;
pStr += tmpStrLen + 1;
}
}
return (char *)_recalloc(pZipStr, strlen(pZipStr) + 1, sizeof(char));
}
char * timePriorityUnZip(char * pStr)
{
char * pUnZipStr = (char *)calloc(1024 * 10, sizeof(char));
char * pCopy = pUnZipStr;
while (*pStr)
{
char tmpChr = *pStr;
if ('0' <= tmpChr && '9' >= tmpChr)
{
int tmpStrLen = tmpChr - '0';
for (int i = 0; i < tmpStrLen; ++i)
{
*pCopy++ = *(pStr + 1);
}
pStr += 2;
}
else
{
*pCopy++ = *pStr++;
}
}
return (char *)_recalloc(pUnZipStr, strlen(pUnZipStr) + 1, sizeof(char));
}
int main01(void)
{
//字符原串:aaaaabbbhaihualovefangfangooooooooo
//字符压缩:5a3bhaihualovefangfang9o
char str[1024] = "aaaaabbbhaihualovefangfangooooooooo";
printf("(%s) \n", str);
printf("(%s) \n", timePriorityZip(str));
printf("(%s) \n", timePriorityUnZip(timePriorityZip(str)));
system("pause");
}
///02.空间优先压缩与解压缩.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void spacePriorityZip(char * pSrcStr)
{
char * p1 = pSrcStr;
char * p2 = pSrcStr;
while (*p1 = *p2)
{
//if ('a' != *p1)
//{//删除所有字符
// ++p1;
//}
int sameChrLen = 1;
char * pTmp = p2 + 1;
while (*p2 == *pTmp)
{
++sameChrLen;
++pTmp;
}
if (1 == sameChrLen)
{
++p1;
++p2;
}
else
{
*(pTmp - 2) = sameChrLen + '0';
p2 += sameChrLen - 2;
}
}
}
void spacePriorityUnZip(char * pZipStr)
{
char * p1 = pZipStr;
char * p2 = pZipStr;
while (*p1 = *p2)
{
int tmpStrLen = 0;
if ('0' <= *p2 && '9' >= *p2)
{
tmpStrLen = *p2 - '0';
}
char tmpChr = *(p2 + 1);
if (!tmpStrLen)
{
++p1;
++p2;
}
else
{
for (char * p = p2 + strlen(p2); p >= p2; --p)
{
*(p + tmpStrLen - 2) = *p;
}
for (int i = 0; i < tmpStrLen; ++i)
{
*(p2 + i) = tmpChr;
}
}
}
}
int main02(void)
{
char str[1024] = "aaaaabbbhaihualovefangfangooooooooo";
printf("(%s) \n", str);
spacePriorityZip(str);
printf("(%s) \n", str);
spacePriorityUnZip(str);
printf("(%s) \n", str);
system("pause");
}
程序片段(11):strspn.c
内容概要:strspn
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//01.strspn(str1, str2);(返回字符串中第一个不在指定字符串中出现的字符下标)
// 原理:不断遍历字符串str2,如果那个字符不存在与str1当中的字符相匹配,就
// 返回该字符在str2当中的位置
int myStrSpn(char * pStr1, char * pStr2)
{
for (int i = 0; i < strlen(pStr1); ++i)
{
int flag = 0;
for (int j = 0; j < strlen(pStr2); ++j)
{
if (*(pStr1 + i) == *(pStr2 + j))
{
flag = 1;
}
}
if (!flag)
{
return i;
}
}
}
int main01(void)
{
char str1[100] = "o12345";
char str2[100] = "lh3jklo";
printf("%d \n", strspn(str1, str2));
printf("%d \n", myStrSpn(str1, str2));
system("pause");
}
程序片段(12):字符串.c
内容概要:360面试字符串出现一次的第一个字符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//01.字符串当中出现次数为一次的第一个字符:
// 要点:出现一次+首个字符
// 思路:从头到(尾-1)遍历每个字符,让其和后面的每一个
// 字符进行比较,然后统计字符个数,统计完成之后,如果
// 此时相同字符个数还是为0,那么就是该字符!
//02.严格区分空字符和空指针:
// 空字符:'\0'
// 空指针:空类型的指针变量
// 指针为空:NULL用于标识指针变量并为存储有意义的地址
//03.双for循环实现查找首个出现一次的字符:
// 时间复杂度为O(N*N)
char getFirstOnceByForFor(char * pStr)
{
if (NULL == pStr)
return '\0';
for (int i = 0; i < strlen(pStr); ++i)
{
int sameChrNum = 0;
for (int j = i + 1; j < strlen(pStr); ++j)
{
if (*(pStr + i) == *(pStr + j))
{
++sameChrNum;
}
}
if (!sameChrNum)
{
return *(pStr + i);
}
}
return '\0';
}
//04.哈希表的建立特点:
// 1.等同于ASCII码表的一一映射对应关系
// 2.通过查表法可以直接查询到所需查询的信息
// 3.通过建立有序的哈希表,可以提高查询效率
//05.哈希表的最大特点:
// 1.原生数据有序
// 2.查找数据可以采用二分查找法
// 3.可以通过(余数+模数)快速确定一个数据所在的位置
// 先判断个位,再判断十位,再判断百位..(按个进行匹配)
//06.哈希表(HashTable)的时间复杂度
// O(N+256)-->字符-->索引-->统计
//07.根据不同的字符映射哈希表当中的数值:
// char-->单字节-->8(bit位)-->2^8-->256种可能
// 因此哈希表的时间复杂度为(((N+256))
//08.哈希表的由来:
// a[00]-->'\0'
// a[49]-->'1'
// a[65]-->'A'
// 索引从0~256分别对应于一个字符,
// 而该索引所对应的数值,就表示该整数出现的次数
// 从而该整数的出现次数就等同于该字符出现的次数!
// 字符-->索引-->统计
//09.整型+字符+转义字符:
// 同一个整型数值可能同时对应于一个字符和一个转义字符
//注:转义字符'\0'所对应的ASCII码值就是0
//10.哈希表的建立特点和查询特点:
// 按照字符的顺序进行哈希表的建立;
// 按照字符的顺序进行哈希表的查询:
//注:顺序的一次,以便于快速定位查询
char getFirstOnceByHashTable(char * pStr)
{
if (NULL == pStr)
return '\0';
int hashTable[256] = { 0 };
char * pCopy = pStr;
while (*pCopy)
{//字符-->整型|索引-->统计(统计索引就等同于统计字符)
hashTable[*pCopy++]++;
}
pCopy = pStr;
while (*pCopy)
{
if (1 == hashTable[*pCopy])
{
return *pCopy;
}
++pCopy;
}
return '\0';
}
int main01(void)
{
char str[100] = "abcdfabcdvg";
//putchar(getFirstOnce(str));
putchar(getFirstOnceByHashTable(str));
system("pause");
}
程序片段(13):01.字符串加密.c+02.密码加密.c
内容概要:加密
///01.字符串加密.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void encode(char * pStr)
{
int pStrLen = strlen(pStr);
for (int i = 0; i < pStrLen; ++i)
{
*(pStr + i) += 3;
}
}
//01.加解密方式一:
// 加密:让每个数据进行统一算数运算
// 解密:让每个数据进行统一算数逆算
void decode(char * pStr)
{
int pStrLen = strlen(pStr);
for (int i = 0; i < pStrLen; ++i)
{
*(pStr + i) -= 3;
}
}
int main01(void)
{
char str[1024] = "HaiHua say: WangFang i love you 1314 forever";
printf("(%s) \n", str);
encode(str);
printf("(%s) \n", str);
decode(str);
printf("(%s) \n", str);
system("pause");
}
//02.加解密方式二:
// 采用异或运算符
int main02(void)
{
int a = 100, b = 10;
a = a ^ b;//加密
b = a ^ b;//解密-->加密
a = a ^ b; // -->解密
printf("a = %d, b = %d \n", a, b);
system("pause");
}
void encryptOrDecrypt(char * pStr)
{
int pStrLen = strlen(pStr);
for (int i = 0; i < pStrLen; ++i)
{
*(pStr + i) ^= 48;
}
}
int main03(void)
{
char str[1024] = "HaiHua say: WangFang i love you 1314 forever";
printf("(%s) \n", str);
encryptOrDecrypt(str);
printf("(%s) \n", str);
encryptOrDecrypt(str);
printf("(%s) \n", str);
system("pause");
}
///02.密码加密.c
#include <stdio.h>
#include <stdlib.h>
void encodeOrDecode(char * pStr, char * pPass, int pStrLen)
{
int pPassLen = strlen(pPass);
int modulus = pStrLen / pPassLen;
int remainder = pStrLen % pPassLen;
if (!remainder)
{
for (int i = 0; i < modulus; ++i)
{//分块儿
for (int j = 0; j < pPassLen; ++j)
{
*(pStr + i * pPassLen + j) ^= *(pPass + j);
}
}
}
else
{
for (int i = 0; i < modulus; ++i)
{
for (int j = 0; j < pPassLen; ++j)
{
*(pStr + i * pPassLen + j) ^= *(pPass + j);
}
}
for (int k = 0; k < remainder; ++k)
{
*(pStr + modulus * pPassLen + k) ^= *(pPass + k);
}
}
}
int main04(void)
{
char str[1024] = "HaiHua say: WangFang i love you 1314 forever";
char pass[20] = "lovefang1314";
int strLen = strlen(str);
printf("(%s) \n", str);
encodeOrDecode(str, pass, strLen);
printf("(%s) \n", str);
encodeOrDecode(str, pass, strLen);
printf("(%s) \n", str);
system("pause");
}