二级指针
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();
}