第三天2017/03/30(上午:二级指针的(输入)内存模型:(共三种模型))

二级指针
char a[10][10];     char (*a)[10];
char *a[10];        char **a;
char **a;           char **a;

这里写图片描述
字符数组的操作易犯错误:
1.字符数组在使用前是否分配空间
2.字符数组能否返回地址
3.定义char* p;临时变量p,保存strstr等函数返回的地址。
这里写图片描述
【注】我们只有在使用指针所指向的内存空间的时候,我们才去关心“指针的类型”。

二级指针作“输入”时,有下面三种内存模型


//内存模式一:函数原型下面4个(哪个正确,哪个错误?)
void print_s1(char **p,  int n)    //正确
//void print_s1(char *p[4],int n)  //正确:形参和实参格式一样
//void print_s1(char (*p)[30],int n)    //错误:类型不一致,编译失败
//void print_s1(char p[4][30],int n)  //错误:类型不一致,编译失败
{
    for(int i = 0;i<n;i++)
    {
        cout<<*(p+i)<<endl; //等价于 cout<<p[i]<<endl; 
    }
}

void sort_s1(char **p,  int n)    //正确
//void sort_s1(char *p[4],int n)  //正确
//void sort_s1(char (*p)[30],int n)  //错误  
//void sort_s1(char p[4][30],int n)  //错误
{
    char *temp;
    for(int i = 0;i<n;i++)
        for(int j = i+1;j<n;j++)
        {
            if(strcmp(p[i],p[j])<0)
            {
                //交换的是指向字符串首地址的指针
                temp = p[i];  p[i] = p[j];  p[j] = temp;
            }
        }
}


//内存模式二:函数原型下面4个(哪个正确,哪个错误?)
//void print_s2(char **p,  int n)    //错误,类型不一致,编译失败
//void print_s2(char *p[4],int n)  //错误,类型不一致,编译失败
//void print_s1(char (*p)[30],int n)    //正确,char (*p)[4]相当于char p[][4]
void print_s2(char p[][30],int n)  //正确:形参和实参格式一样
{
    for(int i = 0;i<n;i++)
    {
        cout<<*(p+i)<<endl; //等价于 cout<<p[i]<<endl; 
    }
}

//void sort_s2(char **p,  int n)    //错误
//void sort_s2(char *p[30],int n)  //错误
void sort_s2(char (*p)[30],int n)  //正确
//void sort_s2(char p[][30],int n)  //正确
{
    char temp[100];  
    //char *temp;  //报错,因为没有分配内存就用strcpy往temp中复制元素,肯定崩溃
    for(int i = 0;i<n;i++)
        for(int j = i+1;j<n;j++)
        {
            if(strcmp(p[i],p[j])<0)
            {
                //此处不是(交换的是指向字符串首地址的指针),而是用函数strcpy进行复制
                strcpy(temp,p[i]);
                strcpy(p[i],p[j]);
                strcpy(p[j],temp);              
            }
        }
}

//内存模式三:函数原型下面4个(哪个正确,哪个错误?)==>类似于内存模式
//void print_s3(char **p,  int n)    //正确
void print_s3(char *p[4],int n)  //正确!
//void print_s3(char (*p)[30],int n)   //错误
//void print_s3(char p[4][100],int n)  //错误:类型不一致,编译失败
{
    for(int i = 0;i<n;i++)
    {
        cout<<*(p+i)<<endl; //等价于 cout<<p[i]<<endl; 
    }
}

void sort_s3(char **p,  int n)    //正确
//void sort_s3(char *p[4],int n)  //正确
//void sort_s1(char (*p)[30],int n)   //错误
//void sort_s3(char p[4][100],int n)  //错误
{
    char *temp;
    for(int i = 0;i<n;i++)
        for(int j = i+1;j<n;j++)
        {
            if(strcmp(p[i],p[j])<0)
            {
                //交换的是指向字符串首地址的指针
                temp = p[i];  p[i] = p[j];  p[j] = temp;
            }
        }
}
int main()
{
//内存模式一:
    char *p1[4] = {"AAAAAA","CCCC","BBBB","DDDD"};
    //p1[3][3] = 'F';  //崩溃,因为p[i]指针指向的是字符串常量(例如“AAAAA”),该字符串常量“AAAAA”(存放在常量区)不能被修改

    cout<<"排序之前"<<endl;
    print_s1(p1,4);
    cout<<"排序之后"<<endl;
    sort_s1(p1,4);
    print_s1(p1,4);
    cout<<endl;


//内存模式二:
    char p2[4][30] = {"AAAAAA","CCCC","BBBB","DDDD"};
    p2[3][3] = 'F';  //正确,p[i]="AAAAA"(是静态分配字符数组p[30])在此处相当于给字符数组初始化,“AAAAA”存放在在栈中,可以被修改

    cout<<"排序之前"<<endl;
    print_s2(p2,4);
    cout<<"排序之后"<<endl;
    sort_s2(p2,4);
    print_s2(p2,4);
    cout<<endl;

//内存模式三:
    char **p3 = (char**)malloc(10*sizeof(char*));
    if(p3==NULL) //如果内存分配失败
        return 0;
    for(int i = 0;i<10;i++)
    {
        *(p3+i) = (char*)malloc(30*sizeof(char));//p3[i] = (char*)malloc(30*sizeof(char));
        if(p3[i]==NULL)  //如果内存分配失败
            return 0;
        sprintf(p3[i],"String%d",i);
    }
    p3[3][3] = 'F';//正确,p[i](是动态分配的字符数组p[30]),在堆中,可以被修改

    cout<<"排序之前"<<endl;
    print_s3(p3,4);
    cout<<"排序之后"<<endl;
    sort_s3(p3,4);
    print_s3(p3,4);

    //使用完malloc分配的内存,记得释放,防止内存泄漏
    for(int i=0;i<10;i++)
    {
        free(p3[i]);
        p3[i] = NULL; //防止野指针
    }
    free(p3);
    p3 = NULL; //防止野指针



    getchar();
}

【总结——二级指针的解决问题方案】
(1)先判断:是输入?输出?
(2)若是输入?
_则:根据具体情况进行套用是三种模型中的哪一种模型!

作业题:

/*  作业题1:key~value
    查找指针数组中的字符串是否有key?
    如果有,把key~value输出来(去掉空格)  */
int strlen_trimSpace2(char *p,char *q)
{//两头堵模型:求出除去前后空格的字符串的长度
    int count = 0;
    int i = 0,j = 0;
    j = strlen(p)-1;  //记得 -1(减1)
    while(isspace(p[i]) && p[i]!='\0')  //从前往后
    {   //isspace(c)检查参数c是否为空格字符
        i++;
    }
    while(isspace(p[j]) && j>0)   //从后往前
    {
        j--;
    }
    count = j-i+1;
    memcpy(q,p+i,count);
    q[count] = '\0';

    cout<<q<<endl; //为了不修改输入的p字符数组,定义q作为接受数组

    return 0;
}

int key_value(char* input/*key*/,char **array,char* output/*找到的结果字符串*/,int *outstrLen)
{
    int i = 0;
    char* p ;//保存查找到的地址
    if(input==NULL||output==NULL /*||&outstrLen==NULL*/)
    {
        cout<<"input、output有一个为NULL"<<endl;
        return -1; //返回-1表示出现bug
    }
    //在array中查找子串input
    for(i=0;array[i]!=NULL;i++)
    {
        p = strstr(array[i],input);
        if(p!=NULL) //如果查找到
            break;//查找成功(此时查找到的字符串是array[i])就跳出for循环
    }
    if(p==NULL) //如果没查找到
    {
        //cout<<"在array[i]中查找input失败"<<endl;
        return -2; //返回-2表示没查找到
    }
    p = p + strlen(input); //跳过查找到的input字符
    //查找 = 号
    p = strstr(p,"=");
    p++; //跳过 = 号

    char temp[100];
    //两头堵:去掉字符串前后的空格
    strlen_trimSpace2(p,temp);

    strcat(input,"=");
    strcat(input,temp);
    strcpy(output,input);

    *outstrLen = strlen(output)+1;

    return 0; //返回0表示查找到
}
int main()
{
/*  作业题:key~value
    查找指针数组中的字符串是否有key?
    如果有,把key~value输出来(去掉空格)
*/
    char *array[5] = 
        {
            "key1 =     AAAA      ",
            "key2 =     BBBBBBBB",
            "key3 =CC",
            "key4 =  DDD  ",
            "key5 =     EE  "
        };
    char  input[100] = "key111" ;
    char output[100];

    int outstrLen = 0;

    int ret = 0; 
    ret = key_value(input,array,output,&outstrLen);
    if(ret==-2)
    {//返回-2表示没查找到
        cout<<"array中没有input,查找失败"<<endl;
        getchar();
        return 0;
    }
    else if(ret == -1)
    {
        cout<<"程序错误"<<endl;
        getchar();
        return 0;
    }
    else
    {
        cout<<"      找到字符串 :"<<output<<endl;
        cout<<"找到字符串的长度 : "<<outstrLen<<endl;
    }

    getchar();
}

两个指针挖字符串模型
这里写图片描述

//作业题2:有一个字符串:形如“aaaa,bbbbb,ccccc,dddd”。
//      以逗号为分隔符,把aaaa\bbbbb\ccccc\dddd保存到一个二维字符数组中
int array2outarray(char* array,char outarray[10][30],int *count_)  //自己写
{
    strcat(array,",");
    int N = 0; //N表示返回的子串的个数
    if(array==NULL) //如果array是空的字符串
    {
        N = 0;
        return N;
    }
    int count = 0;
    int len = 0;

    char *p = array;
    char *h = p ; //始终指向“子字符串”的头部

    while(*p!='\0')
    {
        p = strstr(h,","); //在字符串中找逗号
        if(p==NULL)
            break;
        len = p-h;
        strncpy(outarray[count],h,len); //count表示第几个子字符串
        outarray[count][len] = '\0';
        len = 0;
        count++;
        p++;
        h = p;

    }

    *count_ = count;

    return 0;

}
int spitString(char* array,char ch /*分隔符*/,char buf[10][30],int *count)  //扫地僧答案
{//两个辅助指针变量“挖字符串”
    //1、p和ptemp初始化,都指向子串首地址
    char *p = array;
    strcat(p,",");
    char *ptemp = p;
    int p_ptemp = 0;
    int count_temp = 0;

    //2、执行strstr或者strchr,结果保存到p中
        //如果找到,那么p和ptemp正好形成一个差值p_ptemp
    //3、再次让p和ptemp都达到检索条件的开始位置
    //4、循环1.2.3,直到不符合while条件退出循环
    while(*p!='\0')
    {
        p = strchr(p,',');
        if(p==NULL)
            break;
        p_ptemp = p-ptemp;

        memcpy(buf[count_temp],ptemp,p_ptemp);
        buf[count_temp][p_ptemp] = '\0';

        p++;
        ptemp = p;
        count_temp++;
        p_ptemp = 0;
    }
    *count = count_temp;
    return 0;
}
int main()
{
    //作业题:有一个字符串:形如“aaaa,bbbbb,ccccc,dddd”。
    //  以逗号,为分隔符,把aaaa\bbbbb\ccccc\dddd保存到一个二维字符数组中
    int count = 0;
    char array[] = "aaaa,bbbbb,ccccc,dddd,ee,,,";
    char buf[10][30];

    //spitString(array,',',buf,&count); //扫地僧写
    array2outarray(array,buf,&count);  //自己写


    cout<<"打印二维数组"<<endl;
    for(int i=0;i<count;i++)
    {
        cout<<*(buf+i)<<endl;
    }
    getchar();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值