20160208.CCPP体系具体解释(0018天)

程序片段(01):main.c
内容概要:PointWithOutInit

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

//01.野指针具体解释:
//  1.野指针:没有进行初始化操作的指针-->由于该指针变量内部所存储的地址是个随机值,因此是野地址(类型含义:指针)
//    注:指针类型的变量必须在其被创建的时候就须要进行初始化操作,否则就成了野指针,所谓野指针就是乱指向的指针,形成的就是一个随机垃圾地址
//  2.胡乱使用野指针所造成的现象:
//    (1).指向驱动程序所属内存,将会出现蓝屏现象
//       (2).指向普通的应用程序,会将本身的这个应用程序结束掉
int main01(void)
{
  int * p;
  printf("%d \n", *p);//

    system("pause");
}

程序片段(02):01.地址.c+02.内容.c+03.指针实战.c+04.指针副本机制.c
内容概要:指针地址与取值运算符

///01.地址.c
#include <stdio.h>
#include <stdlib.h>

int get()
{
    return 10;
}

//01.严格进行变量区分:
//  1.普通变量和指针变量
//  2.严格的变量类型:
//      常规类型+特殊类型
//02.对变量取地址的操作发起于寄存器其中
//  因此地址也生成于寄存器变量其中,C语言无法直接訪问
//03.关于取地址符不能操作的两种情况:
//      &&intNum;-->C语言无法直接操作寄存器变量
//      &get();-->返回值存储与寄存器的(cache)区,或者程序的(备份内存),这两块儿内存都不可直接訪问
int main01(void)
{
    int intNum;
    &intNum;//这里获取一个声明但没有初始化的普通变量的所属地址能够,可是假设是指针类型的变量就不行了
    //&&intNum;//&intNum这个表达式所代表操作运行于寄存器其中,在寄存器其中使用寄存器变量进行存储,因此C语言无法进行寄存器变量的操作
    //  并且&intNum所获得的数据来自于CPU-->寄存器-->代码区-->符号表中,因此不能通过取地址运算符进行操作(C语言相对于汇编语言的缺点)
    //&get();//get();的返回值,也就是函数的返回值可能存储于两个常见位置:寄存器的缓冲区(cache),应用程序的备份内存,因此返回值不可取地址

    system("pause");
}
///02.内容.c
#include <stdio.h>
#include <stdlib.h>

//01.取值运算符("*")与取地址运算符("&"):
//  1.星号("*")表示取值运算符,也就是依据指针訪问内存块儿
//  2.与号("&")表示取地址运算符,也就是依据变量的内存实体获取变量的地址
//02.对指针变量使用取值运算符(星号:"*")的使用规律:
//  用原始指针类型的指针级别减去取地址运算符的个数;
//  就是当前所訪问的具体变量(普通变量和指针变量)
//      结果为0-->普通变量
//      结果为1-->一级指针变量
//      结果为2-->二级指针变量         
//      结果为n-->N级指针变量
int main02(void)
{
    //*(001) = 1;//由于常量读取于代码区符号表,产生于CPU寄存器,因此C语言不能够直接进行訪问
    int intVar = 10;
    *(&intVar) = 3;//星号(*)表示取值运算符,也就是依据指针訪问内存区块儿
    printf("%d \n", intVar);

    system("pause");
}

//03.取值运算符(星号:"*")的操作对象实质必须是指针
//  注:*&intVar-->严格区分运行流程
int main03(void)
{
    int intVar = 10;
    *&intVar = 3;//*&这两个符号能够同一时候进行出现,操作流程为:取地址运算符(与号:"&")先进行取地址操作,再依据取值运算符(星号:"*")依据指针获取该指针所指向的内存实体|数据实体
    //**&intVar;//编译报错-->由于*&intVar之后的结果为普通变量类型(int)-->取值运算符的操作对象必须是指针类型,也就是含有(星号:"*")的类型
    printf("%d \n", intVar);

    system("pause");
}

//04.凡是涉及到的操作和运算的步骤都是由CPU在寄存器其中进行运行的,这里的强制类型转换属于"读取"并"转换"的操作
//  因此属于寄存器操作,要进行间接改动数据,必须得先获取到相应的指针,并且指针类型必须是能够改动的,这样就有可能涉及到
//  指针变量的类型转换操作
//05.*(int *)&num这段儿代码的具体解释:
//  0.这些符号都是用于对变量名进行操作的
//      注:对变量进行的操作实质事实上是对内存实体(数据实体)直接进行操作
//  1.取地址运算符(与号:"&")最接近于变量名称,所以优先运行
//  2.强制类型转换操作(int *)次接近于变量名称,所以其次运行
//  3.取值运算符(星号:"*")再次接近于变量名称,所以再其次运行
int main04(void)
{
    const int num = 3;//在C语言中,Const关键字在处理普通变量的时候,仅仅能够避免对变量的直接改动,可是避免不了间接改动(普通变量适用,指针变量稍有区别)
    //num = 1;//直接改动,编译报错
    (int)num;//对不论什么变量的强制类型转换操作,强制转换之后的数值产生于CPU的寄存器
    *(int *)&num = 10;//int *类型转换,这里要特别注意,const int须要被看做为总体的一个类型进行处理
    printf("%d \n", num);

    system("pause");
}

//06.关于空类型的指针与空指针的区分:
//  空类型的指针:
//      严格说是空类型的指针变量-->该指针变量没有具体类型,仅仅是用于存储地址(没有类型含义)而已
//      因此不能直接对空类型的指针变量进行数据实体的訪问操作,没有明白解析步长和解析方式
//  空指针:
//      就是用于标识指针变量没有存储不论什么有实际意义的地址-->空置的指针变量而已
//      实质形式:NULL-->(void *)0
//  区分:空类型的指针是左值,空指针属于右值
int main05(void)
{
    int intVar = 10;
    intVar = 3;
    void * pIntVar = &intVar;//空类型的指针多用于多线程的数据传送处理
    //printf("%d \n", *p);//不能够直接操作空类型的指针

    system("pause");
}

void change01(int * pNum)//副本机制,数组除外
{
    *pNum = 10;
}

int main06(void)
{
    int num = 20;
    change01(&num);
    printf("%d \n", num);

    system("pause");
}
///03.指针实战.c
#include <stdio.h>
#include <stdlib.h>

//01.怎样高速确定一个变量的所属类型?
//  变量名称对称法(直接看声明变量的代码块儿,进行直观对称得出)
int main07(void)
{
    double db = 10.8;
    double dbl = 10.9;
    double * p = &db;
    printf("%d \n", sizeof(p));//指针变量-->类型(double *)-->占用4个内存字节
    printf("%d \n", sizeof(*p));//数据实体-->类型(double)-->占用8个内存字节
    *p = 10.6;
    printf("db = %lf, dbl = %lf, *p = %lf \n", db, dbl, *p);//10.6 10.9 10.6
    p = &dbl;
    printf("db = %lf, dbl = %lf, *p = %lf \n", db, dbl, *p);//10.6 10.9 10.9
    *p = 9.2;
    printf("db = %lf, dbl = %lf, *p = %lf \n", db, dbl, *p);//10.6 9.2 9.2
    dbl = 2.1;
    printf("db = %lf, dbl = %lf, *p = %lf \n", db, dbl, *p);//10.6 2.1 2.1

    system("pause");
}
///04.指针副本机制.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//01.函数形式參数的副本机制:
//  1.在C语言其中,函数形式參数传參的副本机制仅仅有数组例外,由于提升效率,节约内存拷贝
//  2.跨函数改变变量(普通变量|指针变量)的传參要素
//      被掉函数改动主调函数其中的普通变量,须要普通变量的地址
//      被掉函数改动主调函数其中的指针变量,须要指针变量的地址
//  注:总之在被掉函数其中改动主调函数的变量,不管是普通变量还是指针变量,必须传递变量的地址
//      否则绝对不行!!!
//void change02(int a, int b);//副本机制,被掉函数须要改动主调函数其中的变量,须要由主调函数向被掉函数传递该待改动变量的所属地址
void change02(int * pa, int * pb)
{
    printf("change02:&pa = %p, &pb = %p \n", &pa, &pb);
    //int * pTemp;//某些编译器会编译不通过!
    int * pTemp = pa;
    pa = pb;
    pb = pTemp;
}

//02.区分指针变量和指针:
//  指针变量:含内存块儿
//      用于存储指针的变量
//  指针:不含有内存块儿
//      是一个具有类型含义的地址
//      是一个具有类型含义的数值
//  注:使用指针变量的实质就是使用指针!
int main08(void)
{
    int a;
    int b;
    int * pa = &a, *pb = &b;
    //scanf("%d%d", &a, &b);//scanf();函数后面所需的是"指针"
    scanf("%d%d", pa, pb);
    printf("main: &pa = %p, &pb = %p \n", &pa, &pb);
    if (*pa > *pb)
    {
        change02(pa, pb);//间接改动无法成功
        int temp = a;//直接改动
        a = b;
        b = temp;
    }
    printf("a = %d, b = %d \n", a, b);

    system("pause");
}

int main09(void)
{
    int a;
    int b;
    int * pa = &a, *pb = &b;
    scanf("%d%d", pa, pb);
    if (*pa > *pb)//相应指向的数据实体
    {
        int * pTemp = pa;//交换指针
        pa = pb; 
        pb = pTemp;
    }
    printf("a = %d, b = %d \n", a, b);
    printf("pa= %d, pb = %d \n", *pa, *pb);

    system("pause");
}

void change03(int * p1, int * p2)
{
    printf("change03: &p1 = %p, &p2 = %p \n", &p1, &p2);
    int pTemp = *p1;
    *p1 = *p2;
    *p2 = pTemp;
}

void change04(int * p1, int * p2)
{
    printf("change04: &p1 = %p, &p2 = %p \n", &p1, &p2);
    //int * pTemp;//野指针:没有经过初始化的指针-->某些编译器直接编译报错
    int * pTemp = NULL;//使用空指针来标识指针变量没有指向不论什么位置
    *pTemp = *p1;//错误:訪问了不该訪问的地址0
    *p1 = *p2;
    *p2 = *pTemp;
}

int main10(void)
{   
    int a;
    int b;
    int * pa = &a, * pb = &b;
    scanf("%d %d", pa, pb);
    if (*pa > *pb)//对照指向的数据实体
    {
        //change03(pa, pb);
        change02(*pa, *pb);//函数传递数据,传递的都仅仅是副本而已
    }
    printf("a = %d, b = %d \n", a, b);
    printf("*pa = %d, *pb= %d \n", *pa, *pb);

    system("pause");
}

void change05(int * p1, int * p2)
{
    printf("change05: &p1 = %p, &p2 = %p \n", &p1, &p2);
    int * pTemp = p1;
    p1 = p2;
    p2 = pTemp;
}

//03.不管是指针变量的操作还是对指针的操作:
//  都必须明白其类型
int main11(void)
{
    int a;
    int b;
    int * pa = &a, *pb = &b;
    scanf("%d%d", pa, pb);
    printf("main: &pa =%p, &pb = %p \n", &pa, &pb);
    printf("main pa = %p, pb= %p", pa, pb);

    system("pause");
}

程序片段(03):01.线程.c
内容概要:多线程參数传递

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <process.h>

//01.空类型的指针-->空类型的指针变量:
//  仅仅是标识该类型的变量具备存储地址的能力,严格区分地址与指针的不同
void run(void * p)//採用空类型的一级指针变量能够存储不论什么类型的地址:仅仅是具备存储地址的能力
{
    int * pTemp = p;//为该地址赋予实际的意义(地址-->指针)-->具备(解析步长+解析方式)的能力
    char str[100] = { 0 };
    sprintf(str, "锄禾日当午%d \n", *pTemp);
    MessageBoxA(0, str, "天朝非常苦!", 0);
}

//02.关于单线程和多线程的实现问题:
//  1.要看CPU究竟有多少个逻辑内核?
//      逻辑内核仅仅有一个无法实现多线程的
//  2.要看使用的的线程技术?

// 使用单线程技术无法实现多线程訪问 // 使用多线程技术既能够实现单线程訪问也能够实现多线程訪问 //03.明白多线程情况下的一个应用程序的堆栈使用情况: // 1.单进程情况之下的堆栈使用情况 // 2.各条线程共享单进程的堆内存 // 3.各条线程独享各自的栈内存 // 注:当主线程开启辅助辅助线程的时候! // 主线程所占用的栈内存相对于其它辅助线程就是共享的堆内存! int main01(void) { int intArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; for (int i = 0; i < 10; ++i) { //多线程同一时刻訪问同一个变量的冲突问题(具体解释:多条线程全部开启,大家都读取到了变量i的地址,然后同一时刻訪问了变量i的数据,因此同样) // 此时的主线程数据相对于其它辅助线程的数据就如同堆内存其中的数据,各条线程共享该数据-->因此多线程訪问冲突 HANDLE hd = _beginthread(run , 0 , &i); WaitForSingleObject(hd, INFINITE);//无限等待,意思就是知道直到上一条工作线程运行完毕之后,再继续运行此行代码之后的代码 //_beginthread(run, 0, &intArr[i]);//多线程传递參数的方式-->此时每条线程当问的不是同一个数据,因此不会出现多线程訪问冲突问题 } system("pause"); }

程序片段(04):01.指针运算.c+02.数组.cpp+03.数组实战.c
内容概要:指针与数组

///01.指针运算.c
#include <stdio.h>
#include <stdlib.h>


//01.指针变量的运算符特点:
//  1.指针变量的运算仅仅有在所属数组的情况下才具备实际意义
//  2.指针变量的运算与其所指向的数据实体的类型密切相关
//  3.没有明白类型的指针变量全然无法进行訪问(读取|改动)
//      仅仅是具备这存储地址这么一个唯一的功能
//02.指针变量的运算规律总结:
//  1.p+1<==>p+sizeof(*p)*1;
//  2.空类型的指针变量必须明白数据类型之后才干进行具体操作
//      否则仅仅是具备容器的特点
int main01(void)
{
    int intNum = 10;
    int * pIntNum = &intNum;
    //pIntNum+1;<>pIntNum+sizeof(*pIntNum)*1;
    printf("%p, %p \n", pIntNum, pIntNum + 1);

    char ch = "X";
    char *pCh = &ch;
    printf("%p, %p, %p \n", pCh, pCh + 1, pCh - 1);//指针变量的运算与类型密切相关

    void * ppCh = &ch;
    //pv+1;//没有明白指针类型的指针变量,不能进行指针变量的算术运算

    system("pause");
}

int main02(void)
{
    int intNum = 10;
    int * pIntNum = &intNum;
    printf("%p, %p, %p \n", pIntNum - 1, pIntNum, pIntNum + 1);
    printf("%d, %d, %d \n", *(pIntNum - 1), *pIntNum, *(pIntNum + 1));
    //假设指针变量所存储的指针所描写叙述的地址不在数组其中,那么指针变量的加减运算法则没有不论什么意义
    //  由于运算结果能够和数组索引相互挂钩

    system("pause");
}

//02.关于指针变量的运算特点:
//  1.參与运算的指针变量所存储的指针必须指向同一个数组内存情况下
//  2.指针变量的运算范围:
//      (1).指针变量既能够加上一个整数或者也能够减去一个整数(指针结果不要越过数组)
//      (2).指着变量值能够减去一个指针变量,但不能够加上一个指针变量
//      (3).指针变量既不能够运行乘法运算也不可运行除法运算,由于运算结果毫无实际意义!
int main03(void)
{
    int intArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int * p1 = &intArr[0];
    int * p2 = &intArr[6];
    printf("%d \n", p2 - p1);//在同一个数组其中的两个指针变量(指针变量p1-指针变量p2<=>(指针1-指针2)/sizeof(*p1)<=>相差的元素个数)
    //printf("%d \n", *(p1 -2));

    system("pause");
}
///02.数组.cpp
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

//01.关于数组名和&数组名的内容具体解释:
//  1.数组名的本质:将全部数组看作为一维数组,那么数组名就是该一维数组其中首个数组元素的地址
//      常量指针!-->含有内存实体,是个伪常量,能够避免直接改动,可是无法避免间接改动
//  2.&数组名的本质:获取指向整个数组总体的指针类型
//      指针常量!-->没有内存实体,是个真常量,既不能够直接改动,也不能够间接改动
//  因此:不管是常量指针还是指针常量所相应的值都是指针(是具备类型含义的地址)
//      数组名+1<=>常量指针+1<=>常量指针的值+sizeof(*常量指针)
//      &数组名+1<=>指针常量+1<=>指针常量的值+sizeof(*指针常量)
//  诀窍:对不论什么类型的变量(不管是真变量还是伪变量)进行取地址操作,都属于指针类型
//      也就统统占用4个字节的内存空间
int main04(void)
{
    int intArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    printf("intArr = %p, &intArr = %p \n", intArr, &intArr);
    printf("%d, %d \n", intArr, intArr + 1);//数组的第一个元素的地址,长度为int类型的字节数
    printf("%d ,%d \n", &intArr, &intArr + 1);//整个数组的类型,长度为整个数组的长度(4*10),这里说明取地址运算符在进行运算的时候同一时候获取了指针的地址和类型
    printf("sizeof(intArr) = %lu, sizeof(&intArr) = %lu \n", sizeof(intArr), sizeof(&intArr));
    printf("%s ,%s", typeid(intArr).name(), typeid(&intArr).name());

    system("pause");
    return 1;
}
///03.数组实战.c
#include <stdio.h>
#include <stdlib.h>

//01.函数的形式參数假设是数组名称,就取消了副本机制!
//  取消副本机制的原理-->将数组名称当做了指针变量的名称进行处理
//  该指针变量具备着实际參数数组的全部信息(包含类型信息)
//  注:这里的指针变量的类型是将全部数组类型看做为一维数组,那么
//      该一维数组其中的全部元素的类型就是该指针变量所指向的内存
//      实体的类型
void testFun(int * p)//借助指针变量訪问外界数组
{
    printf("testFun sizeof(p) = %d \n", sizeof(p));
    for (int * px = p; px < p + 10; px++)
    {
        *px = 12;
        printf("%d ,%p \n", *px, px);
    }
}

//02.sizeof(对象)运算诀窍:
//  sizeof(*&对象);<==>绝对正确的一个结果
int main05(void)
{
    int intArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    printf("main: sizof(intArr) = %d \n", sizeof(intArr));//sizeof(数组名)<=>sizeof(*&数组名);
    testFun(intArr);
    printf("原生数组: \n");
    for (int * p = intArr; p < intArr + 10; ++p)
    {
        printf("%d ,%p \n", *p, p);
    }

    system("pause");
}

//03.对于数组的变量须要借助指针变量进行:
//  指针变量作为循环变量进行运算
int main06(void)
{
    int intArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    //int * pIntArr = &intArr;//类型不匹配:&intArr-->指向数组的指针
    //intArr++;//数组名称intArr作为一个常量指针,是不能够直接进行自增自减运算的
    for (int * p = intArr + 2; p < intArr + 10; ++p)
    {
        printf("%d, %p \n", *p, p);
    }
    for (int * p = intArr + 10; p > intArr - 1; --p)
    {
        printf("%d, %p \n", *p, p);
    }

    system("pause");
}

//04.sizeof();诀窍:
//  sizeof(ob);<=>sizeof(*&obj);
int main07(void)
{
    double * pDb;//在C语言其中,指针变量必须进行初始化,否则就会成为野指针,使用的时候easy出现故障,某些编译器不会通过的
    printf("%d \n", sizeof(*pDb));//对称法则:double  | * pDb-->8个字节
    int intArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    printf("intArr = %p, &intArr = %p \n", intArr, &intArr);
    //printf("sizeof(intArr) = %lu, sizeof(&intArr) = %lu \n", sizeof(intArr), sizeof(&intArr));
    //printf("sizeof(*intArr) = %lu, sizeof(*&intArr) = %lu", sizeof(*intArr), sizeof(*&intArr));
    printf("%d \n", sizeof(intArr));//sizoef();使用诀窍

    system("pause");
}

程序片段(05):thread.c
内容概要:多线程分割

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <time.h>
#include <process.h>

typedef struct
{
    int * pStart;//待检索首地址
    int sLength;//待检索长度
    int dFindValue;//待检索值
    int tID;//当前检索线程ID
} thTask;
int isFind = 0;//线程检索成功标识,用于多线程之间的通信

//01.多线程检索原理:
//  1.将多个线程任务放置到线程队列其中去
//  2.然后调度多条线程运行线程队列其中的任务代码
//  3.线程随机调度:
//      那条线程最闲置,那么该线程最easy优先运行到
#define M 100//待检索的数据量
#define N 4//总共所使用的检索线程数目(最好是CPU逻辑内核的倍数,负载均衡原理)

//02.多线程检索数据最easy遇到的问题:
//  数据量并非单条线程所处理数据量的整数倍?-->须要解决这个负载均衡问题
//      让N-1线程所处理的数据量一致,让最后一条线程处理量不一致
//  举例说明:
//      1.当线程处理数据量刚好平分的情况:
//          100%4=0
//      2.当线程处理数据量不好平分的情况:
//          100%7!=0
//          100/(7-1)=16...4-->前6条线程,每条的数据处理量是16条数据
//          100%(7-1)=4----->第7条线程的数据处理量为4条
void thSearchTask(void * pThTask)
{
    thTask * thTaskBlock = pThTask;//地址->指针
    printf("线程%d開始查找! \n", thTaskBlock->tID);
    for (int * pf = (*thTaskBlock).pStart; pf < (*thTaskBlock).pStart + (*thTaskBlock).sLength; ++pf)
    {
        if (1 == isFind)
        {
            printf("线程%d结束查找,其它线程已经找到! \n", (*thTaskBlock).tID);
            return;
        }
        if ((*thTaskBlock).dFindValue == *pf)
        {
            printf("结束查找状态!线程%d已经找到数据%d,地址为%p",(*thTaskBlock).tID, (*thTaskBlock).dFindValue, pf);
            isFind = 1;
            return;
        }
        Sleep(500);
    }
    printf("线程%d结束查找,没有找到! \n", (*thTaskBlock).tID);
}

int main01(void)
{
    int intArr[M] = { 0 };
    srand((unsigned int)time(NULL));
    for (int i = 0; i < 100; ++i)
    {
        intArr[i] = rand() % 100 + 1;
        printf("%4d", intArr[i]);
        if (0 == (i + 1) % 100)
        {
            printf("\n");
        }
    }

    int num = 0;
    scanf("%d", &num);//待查找的数据
    thTask thTaskArgS[N];//线程任务參数集
    if (0 == M%N)
    {
        for (int i = 0; i < N; ++i)
        {
            thTaskArgS[i].pStart = intArr + M / N *i;
            thTaskArgS[i].sLength = M / N;
            thTaskArgS[i].tID = i;
            thTaskArgS[i].dFindValue = num;
            HANDLE hd = _beginthread(thSearchTask, 0, &thTaskArgS[i]);//开启线程
            //WaitForSingleObject(hd, INFINITE);
        }
    }
    else
    {
        for (int i = 0; i < N - 1; ++i)
        {
            thTaskArgS[i].pStart = intArr + M / (N - 1)*i;
            thTaskArgS[i].sLength = M / (N - 1);
            thTaskArgS[i].tID = i;
            thTaskArgS[i].dFindValue = num;
            HANDLE hd = _beginthread(thSearchTask, 0, &thTaskArgS[i]);
            //WaitForSingleObject(hd, INFINITE);
        }
        int i = N - 1;
        thTaskArgS[i].pStart = intArr + M / (N - 1)*i;
        thTaskArgS[i].sLength = M % (N - 1);
        thTaskArgS[i].tID = i;
        thTaskArgS[i].dFindValue = num;
        HANDLE hd = _beginthread(thSearchTask, 0, &thTaskArgS[i]);
    }

    system("pause");
}

程序片段(06):多线程检索.c
内容概要:多线程检索

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <time.h>
#include <process.h>

typedef struct
{
    int tID;
    int * pStart;
    int sLength;
    int sValue;
} thTaskInfo;
int isFind = 0;

void searchTaskFun(void * pTemp)
{
    thTaskInfo * thTaskArg = pTemp;
    printf("ID为%d的线程開始进行检索任务! \n", (*thTaskArg).tID);
    for (int * pf = (*thTaskArg).pStart; pf < (*thTaskArg).pStart + (*thTaskArg).sLength; ++pf)
    {
        if (1 == isFind)
        {
            printf("ID为%d的线程结束检索状态,其它线程已经检索到%d! \n", (*thTaskArg).tID, (*thTaskArg).sValue);
            return;
        }
        if ((*thTaskArg).sValue == *pf)
        {
            isFind = 1;
            printf("ID为%d的线程已检索到数据%d,该值所在地址为%p \n", (*thTaskArg).tID, (*thTaskArg).sValue, pf);
            return;
        }
        Sleep(500);
    }
    printf("ID为%d的线程未能检索到数据%d,结束检索状态! \n", (*thTaskArg).tID, (*thTaskArg).sValue);
}

int main01(void)
{
    int intArr[100] = { 0 };
    srand((unsigned int)time(NULL));
    for (int i = 0; i < 100; ++i)
    {
        printf("%4d", intArr[i] = rand() % 100 + 1);
        if (0 == (i + 1) % 10)
            printf("\n");
    }

    int value = 0;
    scanf("%d", &value);
    thTaskInfo thTaskArgS[10];
    for (int i = 0; i < 10; ++i)
    {
        thTaskArgS[i].tID = i;
        thTaskArgS[i].pStart = intArr + 10 * i;
        thTaskArgS[i].sLength = 10;
        thTaskArgS[i].sValue = value;
        HANDLE hd = _beginthread(searchTaskFun, 0, &thTaskArgS[i]);
    }

    system("pause");
}

程序片段(07):二级指针.c
内容概要:二级指针

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

//01.指针变量规律:
//  1.指针变量必须注意指针的类型
//  2.指针变量必须注意指针所指向实体的类型
//  3.针对于指针变量的(加减一个整数)规律:
//      实质:必须依据指针变量所存储的指针所指向的实体类型来定断
//      形式:p+1<=>p+sizeof(*p);-->必需带上内存实体才干准确!
//  4.指着变量的级数规律:
//      (1).怎样表明当前指针变量存储的是什么类型的变量的地址?

// double **pp-->二级指针变量PP存储的是(double * p)这个一级指针变量的地址 // 规律:指针变量的声明级数减去一级就是该指针变量所存储的变量的地址 // (2).怎样确定取值运算符(星号:"*")当前所訪问的内存实体是什么? // double **pp-->**pp-->(指针变量声明级数-当前取值运算符操作的级数) // 就是该取值运算符所訪问的变量的数据 // 比如:**-**=0-->变量的数据 int main01(void) { double db = 10.8; double * p = &db; //double * pT = &p;//指针类型不匹配 double ** pp = &p; //printf("%p, %p \n", pT, pT + 1);//PT结果不对 printf("%p, %p \n", pp, pp + 1); printf("%lf \n", **pp);//普通变量 system("pause"); } int a = 10; int b = 20; //02.函数形參的副本机制要点: // 仅仅是针对于数组类型没有副本机制,其它全部类型的形參都有副本机制 // 原理:就是将数组类型进行退化为指针("指向数组元素的指针"),以避免副本机制产生 // 注:指向数组元素的指针,明白该数组其中所存储的究竟是什么类型的数据! void changeP(int * p)//指针变量也有副本机制 { printf("change: &p = %p \n", &p); p = &b; } void changePP(int ** pp) { *pp = &b; } //03.要想让被掉函数改动主调函数其中的变量数据: // 诀窍:至少必须传递主调函数其中的变量地址(至少得是直接地址) int main02(void) { int * p = &a; printf("main: &p = %p \n", &p); printf("%d \n", *p);//10 //p = &b; //changeP(p); changePP(&p); printf("%d \n", *p); system("pause"); } //04.集团体系架构关系: // 职称体系能够通过指针级数进行描写叙述 // 比如:司令採用的是10级指针描写叙述,里面存储的军长的地址 int main03(void) { int a = 10; int * p = &a; int ** pp = &p; int *** ppp = &pp; printf("%p \n", &ppp); //集团体系架构关系能够通过指针级数进行描写叙述 system("pause"); } //05.字符类型的指针假设指向的是代码区符号表实体: // 那是不同意通过字符指针间接改动代码区符号表内容的! // 注:代码区符号表的内容仅仅能够进行读取操作,不能进行写入操作 int main04(void) { char * p = "123";//"123"存储于代码区符号表 *p = 'A';//*p所訪问的内存实体位于代码区符号表,因此不能直接进行改动 printf("%p \n", p); system("pause"); } void run(char * arr[5]) { printf("run: sizeof(arr) = %d \n", sizeof(arr));//sizeof(char **) for (int i = 0; i < 5; ++i) { system(arr[i]); } } //06.数组作为形參究竟退化为什么类型的指针? // 实质:退化为指向该数组其中全部元素的指针! //int arr[5]-->arr作形參,退化为-->int * arr //char * arr[5]-->arr作形參,退化为-->char ** arr void runT(char **arr)//指针数组作为形參,将会退化成为二级指针 { printf("runT: sizeof(arr) = %d \n", sizeof(arr)); for (int i = 0; i < 5; ++i) { system(arr[i]);//arr[i]的实质事实上是一级指针 } } //07.数组作为形參的时候,会具体转化为指向该数组其中每一个元素的指针类型: // 在訪问的时候,採取该指针类型变量名加上中括号("[]")等同于数组訪问方式! // 实质:arr[i]<=>*(arr+i)-->效果等价 int main05(void) { //int arr[10]; char * arr[5] = { "calc", "notepad", "mspaint", "tasklist", "pause" }; printf("main: sizeof(arr) = %d \n", sizeof(arr));//诀窍:sizeof(varName)<=>sizeof(*&varName) run(arr); //runT(arr); system("pause"); }

程序片段(08):数组.c
内容概要:指针结合数组

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

//01.几组概念区分:
//  1.普通变量和指针变量:
//      是否具有地址意义
//  2.变量指针和常量指针
//      指针变量和数组名的区分
//  3.常量指针和指针常量
//      数组名和地址意义上的数值
//  注:通常意义上的指针实质上是指着变量
//02.函数形參使用数组声明形式以及指针声明形式
//  其訪问实參的方式都是同样的(数组形式<=>指针形式)
int main01(void)
{
    int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    int * p = arr;//变量指针接收常量指针的值
    for (int i = 0; i < 10; ++i)
    {
        printf("%d, %d, %d, %d \n", arr[i], *(arr + i), p[i], *(p + i));
    }
    //接收同样一个数组实參
    //  採用数组声明形式和採用指针声明形式的訪问方式全然一样
    //  比如:arr[i]<=>p[i];*(p+i)<=>*(arr+i)

    system("pause");
}

//03.数组作为形參的函数标准声明形式!
//  指向数组元素的指针+数组元素个数
void revArr(int * p, int n)
{
    for (int i = 0; i < n / 2; ++i)//节省效率的反转方式
    {
        p[i] = p[i] ^ p[n - 1 - i];
        p[n - 1 - i] = p[i] ^ p[n - 1 - i];
        p[i] = p[i] ^ p[n - 1 - i];
    }
}

//04.通过指针方式来对数组进行遍历!
void revArrT(int * p, int n)
{
    for (int * pHead = p, *pTail = p + n - 1; pHead < pTail; ++pHead, --pTail)
    {//奇数:重合退出+偶数:交叉退出
        *pHead = *pHead ^ *pTail;
        *pTail = *pHead ^ *pTail;
        *pHead = *pHead ^ *pTail;
    }
}

//05.传递实质是什么就能够以何种形式进行数据訪问!
//  这里传递的实质是数组,因此能够採用数组方式訪问
void showArr(int * p, int n)
{
    for (int i = 0; i < n; ++i)
    {
        printf("%2d", p[i]);
    }
}

int main02(void)
{
    int arrA[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };//10/2=5..0--><=5-->0~4(前0~4与后0~4)对称
    int arrB[9] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };//9/2=4..1--><=4-->0~3(前0~3与后0~4)对称
    revArr(arrA, sizeof(arrA) / sizeof(arrA[0]));
    showArr(arrA, sizeof(arrA) / sizeof(arrA[0]));
    putchar('\n');
    revArrT(arrB, sizeof(arrB) / sizeof(arrB[0]));
    showArr(arrB, sizeof(arrB) / sizeof(arrB[0]));

    system("pause");
}

//06.特殊常量指针訪问数组方式:
//  原理:arr[i]<=>*(arr+i)
//  因此:i[arr]<=>*(i+arr)
//  注:全部数组的解析方式都是依照arr[i]-->*(arr+i)-->
//      全部荒唐使用方法i[arr]也能够进行替换为-->*(i+arr)
int main03(void)
{
    int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    printf("% \n", 8[arr]);
    //arr[1]<==>*(arr+1)

    system("pause");
}

程序片段(09):queue.h&queue.c+01.多线程.c+02.多线程排队.c
内容概要:多线程并行计算

///queue.h
#define EN 100

typedef struct
{
    int data[EN];
    int head;
    int tail;
} Queue;

void initQueue(Queue * pQueue);
int isEmpty(Queue * pQueue);
int isFull(Queue * pQueue);
void enQueue(Queue * pQueue, int value);
void deQueue(Queue * pQueue);
int getLast(Queue * pQueue);
void showQueue(Queue * pQueue);
//#undef N//结束宏名为N的作用域
///queue.c
#include "queue.h"
#include <memory.h>
#include <stdio.h>

void initQueue(Queue * pQueue)
{
    memset((*pQueue).data, 0, sizeof(int)*EN);//数据清零,模拟回收
    (*pQueue).head = (*pQueue).tail = -1;
}

int isEmpty(Queue * pQueue)
{
    if ((*pQueue).head == (*pQueue).tail)
        return 1;
    return 0;
}

int isFull(Queue * pQueue)
{
    if (EN - 1 == (*pQueue).tail)
        return 1;
    return 0;
}

void enQueue(Queue * pQueue, int value)
{
    if (1 == isFull(pQueue))
        return;
    if (1 == isEmpty(pQueue))
    {
        (*pQueue).data[0] = value;
        (*pQueue).tail = 0;
    }
    else
    {
        for (int i = (*pQueue).tail; i > 0; --i)
        {
            (*pQueue).data[i] = (*pQueue).data[i - 1];
        }
        (*pQueue).data[0] = value;
        ++((*pQueue).tail);
    }
}

void deQueue(Queue * pQueue)
{
    if (isEmpty(pQueue))
        return;
    --((*pQueue).tail);
}

int getLast(Queue * pQueue)
{
    return (*pQueue).data[((*pQueue).tail)--];
}

void showQueue(Queue * pQueue)
{
    for (int i = 0; i <= (*pQueue).tail; ++i)
    {
        printf("%2d", (*pQueue).data[i]);
    }
    printf("\n");
}
///01.多线程.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <process.h>

#define N 1024
int main01(void)
{
    srand((unsigned int)time(NULL));
    int data[N] = { 0 };
    for (int i = 0; i < N; ++i)
    {
        data[i] = rand() % 1000 + 1;
    }

    int sum = 0;
    for (int i = 0; i < N; ++i)
    {
        sum += data[i];
    }
    printf("单线程串行结果为%d! \n", sum);

    system("pause");
}

typedef struct
{
    int tID;
    int * pStart;
    int sLength;
    int cSum;
} thTaskInfo;
int main02(void)
{
    thTaskInfo thTask;
    thTaskInfo * pThTask = &thTask;
    printf("%d \n", (*pThTask).sLength = 100);
    //结构体訪问的等价关系!
    //  (*thTask).sLength <=>thTask->sLength
    printf("%d \n", (*pThTask).sLength);

    system("pause");
}


void thTaskFun(void * p)
{
    thTaskInfo * thTask = p;
    for (int i = 0; i < (*thTask).sLength; ++i)
    {
        (*thTask).cSum += (*thTask).pStart[i];
    }
    printf("ID为%d的线程计算结果为%d! \n", (*thTask).tID, (*thTask).cSum);
}

int main03(void)
{
    srand((unsigned int)time(NULL));
    int data[N] = { 0 };
    for (int i = 0; i < N; ++i)
    {
        data[i] = rand() % 1000 + 1;
    }

    int sum = 0;
    for (int i = 0; i < N; ++i)
    {
        sum += data[i];
    }
    printf("单线程串行计算结果为%d \n", sum);

    thTaskInfo thTaskArgs[4] = { 0 };
    for (int i = 0; i < 4; ++i)
    {
        thTaskArgs[i].tID = i;
        thTaskArgs[i].pStart = data + (N / 4) * i;
        thTaskArgs[i].sLength = N / 4;
        thTaskArgs[i].cSum = 0;
        _beginthread(thTaskFun, 0, &thTaskArgs[i]);
    }

    system("pause");//等待全部并行计算线程完毕计算操作
    int lastNum = 0;
    for (int i = 0; i < 4; ++i)
    {
        lastNum += thTaskArgs[i].cSum;
    }
    printf("多线程并行计算结果为%d! \n", lastNum);

    system("pause");
}
///02.多线程排队.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "queue.h"
#include <process.h>

#define N 1024
typedef struct
{
    int tID;
    int * pStart;
    int sLength;
    int cSum;
} thTaskInfo;
Queue thQueue;//管理线程的队列,全局变量,全部线程共享

//01.C语言其中的static关键字使用:
//  static关键字用于限定函数或者变量仅仅能作用域当前文件!
static void thTaskFun(void * p)
{
    thTaskInfo * thTask = p;
    for (int i = 0; i < (*thTask).sLength; ++i)
    {
        (*thTask).cSum += (*thTask).pStart[i];
    }
    enQueue(&thQueue, (*thTask).tID);//线程ID进队,便于顺序打印结果
    printf("ID为%d的线程计算结果为%d! \n", (*thTask).tID, (*thTask).cSum);
}

int main(void)
{
    srand((unsigned int)time(NULL));
    int data[N] = { 0 };
    for (int i = 0; i < N; ++i)
    {
        data[i] = rand() % 1000 + 1;
    }
    int sum = 0;
    for (int i = 0; i < N; ++i)
    {
        sum += data[i];
    }
    printf("单线程串行计算的结果为%d! \n", sum);

    initQueue(&thQueue);
    thTaskInfo thTaskArgs[4] = { 0 };
    for (int i = 0; i < 4; ++i)
    {
        thTaskArgs[i].tID = i;
        thTaskArgs[i].pStart = data + (N / 4) *i;
        thTaskArgs[i].sLength = N / 4;
        thTaskArgs[i].cSum = 0;
        _beginthread(thTaskFun, 0, &thTaskArgs[i]);
    }
    system("pause");//让主线程等待全部辅助线程完毕并行计算
    showQueue(&thQueue);

    int lastNum = 0;
    for (int i = 0; i < 4; ++i)
    {
        lastNum += thTaskArgs[i].cSum;
    }
    printf("多线程并行运算的结果为%d! \n", lastNum);

    system("pause");
}

程序片段(10):main.c
内容概要:TestC

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

//01.格式字符串规律:
//  格式字符串其中的两个%等同于一个非输入格式控制符
//  注:严格区分格式控制符与非格式控制符以及转义字符
int main01(void)
{
    int a = 2, b = 5;
    printf("a = %%d, b = %%d \n", a, b);

    system("pause");
}

程序片段(11):test.c
内容概要:Test

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

//01.自变运算符的特殊性:
//  同样的自变运算符假设在表达式其中同一时候出现;
//  那就须要进行同一时候总体取值运算操作!
//  比如:
//      出现几个(i++),就同一时间提出几个(i++)的值
//          可是提取的是第一个(i++)的值
//      出现几个(++I),就同一时间提出几个(++i)的值
//          可是提取的是最后一个(++i)的值
//02.溢出规律特点:
//  原来99块钱,两位数
//       99
//  加上1块钱,三位数
//      100
//  可是,仅仅能有两位数
//      所以剩下两位是00
int main01(void)
{
    float x = 1, y;
    y = ++x*++x;
    printf("%f \n", y);

    float i = 1, j;
    j = i+++i++;
    printf("%f \n" ,j);

    unsigned short num = 65535 + 1;
    printf("%d \n", num);

    int a, b;
    float c;
    //c = a = b;

    system("pause");
}

转载于:https://www.cnblogs.com/mfmdaoyou/p/7255935.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值