20160220.CCPP體系詳解(0030天)

尹成發表於2016-03-15

程式片段(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");
}

相關文章