首页 > 编程语言 >C++版DNN最简主体框架

C++版DNN最简主体框架

时间:2022-08-16 10:46:33浏览次数:49  
标签:最简 Mat int dst DNN C++ r180 num delt

附属代码:

Mat convolution(Mat&delt,Mat&w,float bias=0,int flp=0)
{
    Mat dst;
    Mat w_r180,delt_r180;
    switch (flp)
    {
    case 0://如果flp==0,只对w翻转180度
        rotate(w,w_r180,ROTATE_180);
        filter2D(delt,dst,delt.type(),w_r180,Point(-1,-1),bias,BORDER_CONSTANT);
        break;
    case 1://如果flp==1,只对delt翻转180度
        rotate(delt,delt_r180,ROTATE_180);
        filter2D(delt_r180,dst,delt.type(),w,Point(-1,-1),bias,BORDER_CONSTANT);
        break;
    case 2://如果flp==2,对w、delt翻转180度
        rotate(w,w_r180,ROTATE_180);
        rotate(delt,delt_r180,ROTATE_180);
        filter2D(delt_r180,dst,delt.type(),w_r180,Point(-1,-1),bias,BORDER_CONSTANT);
        break;
    default:
        cout<<"you input flp is wrong!"<<endl;
    }
    return dst;
}
//w和delt的尺度要求一致,锚点默认为w的中心
Mat myConv(Mat&w,Mat& delt)
{
    int dr=abs(delt.rows-w.rows),dc=abs(delt.cols-w.cols);
    int top=dr/2,bottom=dr-top;
    int left=dc/2,right=dc-left;
    Mat wp,deltp;
    if(w.rows<delt.rows)
    {
        deltp=delt;
        copyMakeBorder(w,wp,top,bottom,left,right,BORDER_CONSTANT,Scalar::all(0));
    }
    if(wp.size()!=deltp.size())
    {
        cout<<"the size of two input is different!"<<endl;
        exit(1);
    }
    Mat dst=Mat(deltp.size(),deltp.type(),Scalar::all(0));
    int srows=dst.rows,scols=dst.cols;
    Mat delt_180,delt_ss;
    rotate(deltp,delt_180,ROTATE_180);
    Mat M=(Mat_<float>(2,3)<<1,0,0,
                              0,1,0);
    for(int i=-srows/2;i<srows/2+1;i++)
    {
        for(int j=-scols/2;j<scols/2+1;j++)
        {
            M.ptr<float>(0)[2]=j;
            M.ptr<float>(1)[2]=i;
            warpAffine(delt_180,delt_ss,M,deltp.size());
            dst.ptr<float>(i+srows/2)[j+scols/2]=sum(wp.mul(delt_ss))[0];
        }
    }
//    cout<<dst<<endl<<endl;
    return dst;
}
///src1和src2的尺寸要一致,卷积结果尺寸与lwk一致
///lwk的尺寸要比src1、src2的尺寸小
/// 卷积运算时,src2倒转180度,src2_180在src1上滑动卷积
Mat myConv(Mat&src1,Mat& src2,Mat&lwk)
{

    if(src1.size()!=src2.size())
    {
        cout<<"the size of two input is different!"<<endl;
        exit(1);
    }
    Mat dst=Mat(lwk.size(),lwk.type(),Scalar::all(0));
    int srows=dst.rows,scols=dst.cols;
    Mat src2_180,src2_ss;
    rotate(src2,src2_180,ROTATE_180);
    Mat ss=(Mat_<float>(2,3)<<1,0,0,
                              0,1,0);
    for(int i=-srows/2;i<srows/2+1;i++)
    {
        for(int j=-scols/2;j<scols/2+1;j++)
        {
            ss.ptr<float>(0)[2]=j;
            ss.ptr<float>(1)[2]=i;
            warpAffine(src2_180,src2_ss,ss,src2.size());
            dst.ptr<float>(i+srows/2)[j+scols/2]=sum(src1.mul(src2_ss))[0];
        }
    }
    return dst;
}
Mat sigmoid(Mat& zmat)
{
    Mat temp=Mat(zmat.size(),CV_32F,Scalar::all(0));
    for(int i=0;i<zmat.rows;i++)
    {
        float* ps=zmat.ptr<float>(i);
        for(int j=0;j<zmat.cols;j++)
        {
            temp.ptr<float>(i)[j]=1.0/(1.0+exp(-ps[j]));
        }
    }
    return  temp;
}
Mat sigmoid_d(Mat&z)
{
    Mat temp=Mat(z.size(),z.type(),Scalar::all(0));
    for(int i=0;i<z.rows;i++)
    {
        for(int j=0;j<z.cols;j++)
        {
            float x=z.ptr<float>(i)[j];
            float sig=1/(1+exp(-x));
            temp.ptr<float>(i)[j]=sig*(1-sig);
        }
    }
    return temp;
}
Mat ReLU(Mat&z)
{
    Mat temp=Mat(z.size(),z.type(),Scalar::all(0));
    for(int i=0;i<z.rows;i++)
    {
        for(int j=0;j<z.cols;j++)
        {
            float x=z.ptr<float>(i)[j];
            if(x<0)
                temp.ptr<float>(i)[j]=0;
        }
    }
    return temp;
}
Mat pooling(const Mat&zs)
{
    Mat result=Mat(zs.size()/2,zs.type(),Scalar::all(0));
    for(int i=0;i<zs.rows;i+=2)
    {
        for(int j=0;j<zs.cols;j+=2)
        {
            float* pz0=CV_MAT_ELEM2(zs,float,i,j);
            float* pz1=CV_MAT_ELEM2(zs,float,(i+1),j);
            float p4_average=(pz0[0]+pz0[1]+pz1[0]+pz1[1])/4.;//2*2个像素的均值
            float* pr=CV_MAT_ELEM2(result,float,i/2,j/2);
            pr[0]=p4_average;
        }

    }
    return result;
}
Mat poolingUp(const Mat&zs)
{
     Mat Dt(zs.rows*2,zs.cols*2,CV_32F,Scalar(0));
    int s=2;//池化尺寸
    for(int i=0;i<zs.rows;i++)
        for(int j=0;j<zs.cols;j++)
        {
            float x=zs.ptr<float>(i)[j];
            Dt(Rect(j*s,i*s,s,s))=x;
        }
    return Dt;
}
void Conv_bias_actvivate(const Mat&src,Mat& dst,const Mat &kernel,float bias)
{

    filter2D(src,dst,CV_32F,kernel);//卷积
    dst +=bias;//偏置
    dst=sigmoid(dst);//激活
    int y=kernel.rows/2,x=kernel.cols/2;
    int width=dst.cols-x*2, height=dst.rows-y*2;
//    cout<<"x="<<x<<" , y="<<y<<" , width="<<width<<" , height="<<height<<endl;
    Mat temp=dst(Rect(x,y,width,height)).clone();
    dst=temp.clone();

}
/*********************卷积神经网络,图像集合*************************/
class ImgUnit
{
public:
    ImgUnit(unsigned char *p)
    {
        for(int i=0;i<3;i++)
        {
            unsigned char *pp=p+1+i*1024;
            m[i]=Mat(32,32,CV_8U,pp);
        }
        merge(m,3,m_bgr);

        label=(int)p[0];
//        imshow("img unit",m_bgr);
    }
    ImgUnit(){}
    void makeImg(unsigned char *p)
    {
        for(int i=0;i<3;i++)
        {
            unsigned char *pp=p+1+i*1024;
            m[(2-i)]=Mat(32,32,CV_8U,pp);//图库中的三原色顺序式RGB,Opencv中式BGR,所以逆序读入
        }
        merge(m,3,m_bgr);

        label=(int)p[0];
    }
    Mat m[3];
    Mat m_bgr;
    int label;
};
//1.加载训练图片
void loadImgSet(ImgUnit *imgset,string datapath)
{
    unsigned char* p=new unsigned char[30730000];
    ifstream infile(datapath,ios::binary);
    if(!infile)
    {
        cerr<<"open err!"<<endl;
        exit(1);
    }
    infile.read((char*)p,30730000);

    for(int i=0;i<10000;i++)

    {
        uchar* pi=p+i*3073;
        imgset[i].makeImg(pi);
    }
    infile.close();
}
/*********************Parsing MNIST data******************************/
// 日常用的PC CPU是Intel处理器,用小端格式
// 把大端数据转换为我们常用的小端数据
void swap_endian(uint32_t& val)
{
    val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
   val=(val << 16) | (val >> 16);
}

class MNIST
{
public:

    Mat* m;
    int* label;
    static int magic_num_l;//Label的魔数
    static int numOfImages_l;//Label与图片一一对应,该参数是图片数
    static int magic_num_i; //图库的魔数
    static int numOfImages_i;//图库的图片数,要与Label一一对应
};
int MNIST::magic_num_l=0;
int MNIST::numOfImages_l=0;
int MNIST:: magic_num_i=0; //图库的魔数
int MNIST::numOfImages_i=0;//图库的图片数,要与Label一一对应

void reverseInt(int& i)
{
    unsigned char ch1, ch2, ch3, ch4;
    ch1 = i & 255;
    ch2 = (i >> 8) & 255;
    ch3 = (i >> 16) & 255;
    ch4 = (i >> 24) & 255;
    i=((int)ch1 << 24) + ((int)ch2 << 16) + ((int)ch3 << 8) + ch4;
}
/******************读取图库MNIST******************/
void readMnist(MNIST&mnist,string labelpath,string imgpath)
{
//    string filename="D:/Qt/MyImage/MNIST/train-labels.idx1-ubyte";

    ifstream file(labelpath, ios::binary);//打开Label文件的对象
    ifstream imgfile(imgpath, ios::binary);//打开图库的对象
    if(!file.is_open())
    {
        cerr<<"label open err!"<<endl;
        exit(1);
    }
    if(!file.is_open())
    {
        cerr<<"images set open err!"<<endl;
        exit(1);
    }
    int magic_num_l=0,numOfImages_l=0;//通过file读取Label的魔数和图片数,之后再赋值给MNIST成员变量
    int magic_num_i=0,numOfImages_i=0;//通过imgfile读取图库的魔数和图片数,之后再赋值给MNIST成员变量
    //读取图片label集的magic number和图片数量number of image.
    file.read((char*)&magic_num_l,sizeof(magic_num_l));
    file.read((char*)&numOfImages_l,sizeof(numOfImages_l));
    //读取image集合的magic number和图片数量number of image.
    imgfile.read((char*)&magic_num_i,sizeof(magic_num_i));
    imgfile.read((char*)&numOfImages_i,sizeof(numOfImages_i));
    //大小端转换
    reverseInt(magic_num_l);//label大小端转换
    reverseInt(numOfImages_l);//label大小端转换
    reverseInt(magic_num_i);//img magic number大小端转换
    reverseInt(numOfImages_i);//img number大小端转换
    cout<<"magic_num_l="<<magic_num_l<<" , numOfImages_l="<<numOfImages_l<<endl;
    cout<<"magic_num_i="<<magic_num_i<<" , numOfImages_i="<<numOfImages_i<<endl;
//     mnist=new MNIST[numOfImages_l];
     mnist.magic_num_l=magic_num_l;
     mnist.numOfImages_l=numOfImages_l;
     unsigned char * label=new unsigned char[numOfImages_l];
     mnist.label=new int[numOfImages_l];//为标号label分配内存
     mnist.m=new Mat[numOfImages_l];//为图像集分配内存
      file.read((char*)label,sizeof(char)*numOfImages_l);;//读取标号
//读取一副图片的行、列数
      uint img_rows,img_cols;
      imgfile.read((char*)&img_rows,sizeof(img_rows));
      imgfile.read((char*)&img_cols,sizeof(img_cols));
      swap_endian(img_rows);
      swap_endian(img_cols);
      cout<<"img_rows="<<img_rows<<" , img_cols="<<img_cols<<endl;
      //读取图像
      uchar *pixs=new uchar[img_rows*img_cols*numOfImages_i];
      imgfile.read((char*)pixs,img_rows*img_cols*numOfImages_i);


    for(int i=0;i<numOfImages_l;i++)
    {
       mnist.label[i]=label[i];
       uchar *p=pixs +i*img_cols*img_rows;
       mnist.m[i]=Mat(img_rows,img_cols,CV_8U,p);
    }

    file.close();
    imgfile.close();

}

/*********************Parsing MNIST data结束******************************/

 

基本代码:

 

class DnnLayer
{
public:
    DnnLayer()    {  }
    void initWeightAndBias(int l1_a_num,//前层输出a的个数
                           int l2_a_num)//当前层输出a的个数
    {
        cv::RNG rgn;//随机数
        this->numOfW=l1_a_num*l2_a_num;
        if(l1_a_num!=l2_a_num)
        {
            w=new Mat*[l1_a_num];
            for(int i=0;i<l1_a_num;i++)
            {
                w[i]=new Mat[l2_a_num];
                for(int j=0;j<l2_a_num;j++)
                {
                    w[i][j]=Mat(5,5,CV_32F,Scalar(0));
                    rgn.fill(w[i][j],RNG::UNIFORM,1,-1);
                }
            }
            b=new float*[l1_a_num];
            for(int i=0;i<l1_a_num;i++)
            {
                b[i]=new float[l2_a_num];
                for(int j=0;j<l2_a_num;j++)
                    b[i][j]=0.5;
            }
        }
        inaNum=l1_a_num;
        outaNum=l2_a_num;
    }
    Mat **w;
    float **b;
    int numOfW;
    int inaNum,outaNum;//输入、输出数量
    Mat *z;//卷积+偏置的结果
    Mat *a;//激活+池化后的输出矩阵
//    Mat *p;//池化的结果
    Mat p_vector;//将池化结果转成矢量,仅仅在卷积层的最后一层使用

};
class NeuronNet//全连接神经网络
{
public:
    Mat input;
    Mat b;//偏置项
    Mat nw;
    Mat z;
    Mat out_a;
    Mat expect_a;
};

class DNN
{
public:
    DNN()
    {
        //初始化全连接网络的权重
        nnet.nw=Mat(10,16*6*2,CV_32F,Scalar(0));
        nnet.b=Mat(10,1,CV_32F,Scalar(0));
        cv::RNG  rng;
        rng.fill(nnet.nw,RNG::UNIFORM,1,-1);
        rng.fill(nnet.b,RNG::UNIFORM,1,-1);
        layers[0].initWeightAndBias(1,1);
        layers[1].initWeightAndBias(1,6);
        layers[2].initWeightAndBias(6,12);
        //z、a、p的初始化
        layers[0].a=new Mat[1];
        layers[1].a=new Mat[6];
        layers[1].z=new Mat[6];

        layers[2].a=new Mat[12];
        layers[2].z=new Mat[12];
    }
    MNIST mnist;//图片库
    Mat *img;//该指针指向mnist的图片库
    DnnLayer layers[3];//两层卷积网络
    NeuronNet nnet;//一层全连接网络
    //    Mat cnnOutvecs;//卷积层所有不同权重卷积结果
public:
    void readImgLib(string labelpath,string imgpath)
    {
        readMnist(mnist,labelpath,imgpath);
        img=mnist.m;//将m指向图像库
        int i=3;
        layers[0].a[0]=img[i].clone();
        imshow("what we learned picture!",img[i]);
        layers[0].a[0].convertTo(layers[0].a[0],CV_32F);
//        normalize(layers[0].a[0],layers[0].a[0],1,0,NORM_MINMAX);

        //对全连接网络初始化"期望输出"
        int label=mnist.label[i];
        nnet.expect_a=Mat(10,1,CV_32F,Scalar(0));
        nnet.expect_a.ptr<float>(label)[0]=1;
    }
    void clipAround(Mat& layer_z,Mat layer_w)//根据卷积核,裁剪卷积结果
    {
        int y=layer_w.rows/2;
        int x=layer_w.cols/2;
        int width=layer_z.cols-x*2;
        int height=layer_z.rows-y*2;
        Mat temp=layer_z(Rect(x,y,width,height));
        layer_z=temp.clone();
    }
    //l层第k个权重w的偏微分书上704页,公式(12.105)
    void updateWeight(Mat&D_l,Mat&previosOuta,Mat lwk,float&alpha)
    {
        Mat temp,wd;
        wd=myConv(previosOuta,D_l,lwk);
        lwk -=alpha*wd;//更新第l层权重,书上是减去偏微分项wd,不知道为什么,用加法反倒合适。
    }

    void calcForeward()
    {
        int L=3;//卷积层的层数
        Mat dst;
        //卷积+偏置+激活,池化
        int l=1;
        for(int i=0;i<layers[l].inaNum;i++)
        {
            for(int j=0;j<layers[l].outaNum;j++)
            {
               layers[l].z[j]= convolution(layers[l-1].a[0],//第0层,仅仅用来接收输入图像,输出a即原图像
                            layers[l].w[i][j],//第l层的卷积核,或权重。
                       layers[l].b[i][j]);//卷积后叠加偏置项
                //裁剪边缘,clip around
                clipAround(layers[l].z[j],layers[l].w[i][j]);
                layers[l].a[j]= sigmoid(layers[l].z[j]);//激活输出a
                //池化
                layers[l].a[j]=pooling(layers[l].a[j]);;//池化输出a
            }
        }
        vector<vector<Mat> > Z;
        vector<Mat> Zj;
        for(int l=2;l<L;l++)//2层网络循环计算
        {
            for(int i=0;i<layers[l].inaNum;i++)
            {
                for(int j=0;j<layers[l].outaNum;j++)
                {
                    Mat lzj;//用于保存临时输出变量
                    Mat w_r180;//卷积核
                    rotate(layers[l].w[i][j],w_r180,ROTATE_180);

                    filter2D(layers[l-1].a[i],//第1层的输出a
                            lzj,//卷积结果
                            CV_32F,
                            w_r180,//第l层的卷积核,或权重。
                            Point(-1,-1),
                            layers[l].b[i][j],
                            BORDER_CONSTANT);
                    //裁剪边缘,clip around
                    clipAround(lzj,layers[l].w[i][j]);
                    Zj.push_back(lzj);//Zj矢量保存第i个输入的12个输出
                }
                Z.push_back(Zj);//将6个Zj保存到Z
            }
        }
        l=2;
        for(int j=0;j<layers[l].outaNum;j++)
        {
            for(int i=1;i<layers[l].inaNum;i++)
            {
                Z[0][j] +=Z[i][j];
            }
            layers[l].z[j]=Z[0][j];
            //激活输出a
            layers[l].a[j]=sigmoid(layers[l].z[j]);
            //池化
            layers[l].a[j]=pooling(layers[l].a[j]);
        }

        Mat cnnOutvecs;
        for(int i=0;i<layers[L-1].outaNum;i++)
        {
            Mat  outavec=layers[L-1].a[i].reshape(1,16);
            cnnOutvecs.push_back(outavec);
        }
        layers[L-1].p_vector= cnnOutvecs;
        //初始化全连接网络的输入端,以及
        nnet.input=cnnOutvecs;
        nnet.z=nnet.nw*nnet.input+nnet.b;
        nnet.out_a=sigmoid(nnet.z);
        cnnOutvecs.release();
    }
    void calcBackward(float alpha=0.01)
    {
        int L=3;
        //D[4]表示四个层上的误差,D[0]废弃。
        int d2num=layers[2].outaNum;//第2层特征映射的个数
        Mat **D=new Mat*[L+1];
        D[L]=new Mat[1];
        D[2]=new Mat[d2num];
        D[1]=new Mat[d2num];

        /*************计算各层误差********************/
        /////计算最后一层D[3]误差,该层是全连接层
        D[L][0]=(nnet.out_a-nnet.expect_a).mul(sigmoid_d(nnet.z));//691页,公式(12.78),D[3]

        /***计算倒数第二层误差D[2],该层是卷积层,也是卷积层与全连接层的衔接层。*/

        //反向传播到衔接层的误差,依然采用全连接计算
        Mat nn2cnn_delt=(nnet.nw.t()*D[L][0]).mul(sigmoid_d(layers[L-1].p_vector));//692页公式(12.79),全连接网络误差计算
        //卷积层的多特征矢量组合的总矢量nn2cnn_delt,分解成12个单独矢量,并且每个矢量被reshape成4×4的矩阵
        int height=layers[L-1].a[0].rows*layers[L-1].a[0].cols;//矢量高度
        for(int i=0;i<d2num;i++)//d2num=12
        {
            D[L-1][i]=nn2cnn_delt(Rect(0,i*height,1,height));
            D[L-1][i]=D[L-1][i].reshape(1,layers[L-1].a[0].rows);
            D[L-1][i]=poolingUp(D[L-1][i]);//反向池化,即上采样,此时尺寸为8×8
            copyMakeBorder(D[L-1][i],D[L-1][i],2,2,2,2,BORDER_REPLICATE);//在D1四周补边,此时尺寸为12×12
//            cout<<D[L-1][i]<<endl<<endl;
        }

        /*********计算倒数第三层误差,D[1]*******/
        int l2num_w=layers[L-1].outaNum;
        int l1num_w=layers[L-1].inaNum;
        Mat delt_l1[6][12];
        for(int i=0;i<l1num_w;i++)
        {
            for(int j=0;j<l2num_w;j++)
            {
                filter2D(D[L-1][j],delt_l1[i][j],CV_32F,layers[L-1].w[i][j],Point(-1,-1),0,BORDER_CONSTANT);
                delt_l1[i][j]=poolingUp(delt_l1[i][j]);//反向池化,即上采样
                Mat sigd=sigmoid_d(layers[L-2].z[i]);
                delt_l1[i][j]=delt_l1[i][j].mul(sigd);
                copyMakeBorder(delt_l1[i][j],delt_l1[i][j],2,2,2,2,BORDER_REPLICATE);//在delt_l1[i][j]四周补边,此时尺寸为28×28
            }
        }
        ///在第1层中的反传误差delt_l1[i][j],共有6×12个误差项,而在第1层中只有6个权重

        ////        /*************更新权重********************/
        ////        //1.计算误差对卷积核W的偏微分,即书上704页,公式(12.104)、(12.105),这部分大概是最难理解的部分
        ////        //首先计算第1层。

        for(int i=0;i<l1num_w;i++)//l1num_w=6
            for(int j=0;j<l2num_w;j++)//l2num_w=12
            {
                updateWeight(delt_l1[i][j],layers[0].a[0],layers[1].w[0][i],alpha);
                //倒数第三层,偏置项更新
                layers[L-2].b[0][i] -=sum(delt_l1[i][j])[0];
            }

        //计算第2层对卷积核w的偏微分,及更新
        for(int i=0;i<l1num_w;i++)
            for(int j=0;j<l2num_w;j++)
            {
                updateWeight(D[2][j],layers[1].a[i],layers[2].w[i][j],alpha);
                layers[L-1].b[i][j] -= sum(D[L-1][j])[0];//倒数第二层,偏置项更新,L-1=2
            }        

        //计算第3层权重nw的更新
        Mat Lw_d=D[L][0]*layers[L-1].p_vector.t();
        nnet.nw -=alpha*Lw_d;
        //计算第3层偏置项nnet.b的更新
        Mat bias_L;
        reduce(D[L][0],bias_L,1,REDUCE_AVG);//全连接网络层,偏置项更新
        nnet.b -=bias_L;
    }
};

 

将要学习的图片,手写数字1

下面是演示代码:

int main()
{
    string labelpath="D:/Qt/MyImage/MNIST/train-labels.idx1-ubyte";
    string imgpath="D:/Qt/MyImage/MNIST/train-images.idx3-ubyte";
    //构建神经网络
    DNN dnn;
    dnn.readImgLib(labelpath,imgpath);
    // 下面是230次循环训练所有权重
    for(int i=0;i<1;i++)
    {
        dnn.calcForeward();
        dnn.calcBackward(0.01);
    }
    cout<<"the real output of dnn!"<<endl;
    cout<<dnn.nnet.out_a<<endl;
    cout<<"the expected output of dnn!"<<endl;
    cout<<dnn.nnet.expect_a<<endl;

        waitKey();
    return 0;
}

 

 

下面是输出结果:

 

标签:最简,Mat,int,dst,DNN,C++,r180,num,delt
From: https://www.cnblogs.com/phoenixdsg/p/16590777.html

相关文章

  • C++之运算符重载
    1运算符重载运算符  +  -  *  /  ++  --  %  &&  ->  >  <等classPerson{public: Person(){} Person(int......
  • C++ 输入一句话,然后把这个字符串以单词为单位,逆转输出。(腾讯笔试题) 比如将“Alice cal
    #include<iostream>#include<string>#include<windows.h>usingnamespacestd;intmain(){stringstr;inti=0;//访问字符数组的下标intcoun......
  • C++易忘知识点记录
    隐藏的默认构造函数没有参数的构造函数称为【默认构造函数】如果没有手动定义构造函数,编译器会给你一个【“隐藏的默认构造函数”】如果数据成员使用了【类内初始值】......
  • C++ 输入一个英文字符串(一句话),统计输入的单词个数
    #include<iostream>#include<string>#include<windows.h>usingnamespacestd;intmain(){stringline;inti=0;//访问字符数组的下标intcoun......
  • C++ Linux下使用共享内存
    在Linux下可以使用SystemV共享内存段实现共享内存,一共有4个API:创建共享内存段或使用已经创建的共享内存段-shmget()将进程附加到已经创建的共享内存段-shmat()从已......
  • C++动态链接库(DLL)文件的创建和调用
    出处:蓟_可爱的叔https://www.cnblogs.com/wjq13752525588/p/16364956.html 一、什么是库    我们在编写C/C++等语言程序的时候,经常会遇到很多反复使用的或者......
  • c++标准IO 中的string流
    c++标准IO中的string流sstream头文件sstream头文件定义了三个类型来支持内存和string之间的IO,在用户看来,string类就像是一个IO流一样。istringstream处理行内的多......
  • 基于C++的OpenGL 10 之光照贴图
    1.引言本文基于C++语言,描述OpenGL的光照贴图前置知识可参考:基于C++的OpenGL09之材质-当时明月在曾照彩云归-博客园(cnblogs.com)笔者这里不过多描述每个名词......
  • C++学习day1
    1.1 HelloWord的实现#include<iostream>usingnamespacestd;intmain(){cout<<"HelloWord"<<endl;system("pause");return0;} 1.2注释符号单行注......
  • c/c++求时间差
    clock_t clock(),clock()   获取的是计算机启动后的时间间隔,得到的是CPU时间,精确到1/CLOCKS_PER_SEC秒。   测试程序如下:[c-sharp]  viewplain copy......