二级指针作输入,有三种内存模型,以字符型指针为例:
第一种内存模型:
1、char *pointer[10],pointer自动退化为一个二级指针,其实质是char **pointer。这种用法是指针数组的用法,编译器在栈区分配内存。
需要掌握:1、排序;2、指针做函数参数排序;3、画出内存分配图。
void main21()
{
int i=0, j=0;
int num = 0;
char * tmp=NULL; //辅助指针变量
char * myArray[10]={"aaa", "bbb", "ccc", "111"};
//打印
printf("排序前\n");
num = sizeof(myArray)/sizeof(myArray[0]); // 对数组求长度;
for (i=0; i<num; i++)
{
printf("%s \n", myArray[i]);
//printf("%s \n", *(myArray+i)); 两种方式都可以
}
//排序1,交换数组元组,即交换指针而非内存。
for (i=0; i<num; i++)
{
for (j=i+1; j<num; j++)
{
if (strcmp(myArray[i], myArray[j])>0)
{
tmp = myArray[i];
myArray[i] = myArray[j];
myArray[j] = tmp;
}
}
}
//打印
printf("排序后\n");
for (i=0; i<num; i++)
{
printf("%s \n", myArray[i]);
//printf("%s \n", *(myArray+i)); 两种方式都可以
}
}
////////指针做函数参数
void printMyArray11(char **myArray, int num) //数组做函数参数,会退化为指针,因此需要将数组长度传进来。
{
int i=0;
for (i=0; i<num; i++)
{
printf("%s \n", myArray[i]);
//printf("%s \n", *(myArray+i)); 两种方式都可以
}
} //printMyArray11
void sortMyarray12(char **myArray, int num)
{
int i=0, j =0;
char * tmp=NULL;
for (i=0; i<num; i++)
{
for (j=i+1; j
{
if (strcmp(myArray[i], myArray[j])>0)
{
tmp = myArray[i];
myArray[i] = myArray[j];
myArray[j] = tmp;
}
}
}
} // sort end
void main()
{
int i=0, j=0;
int num = 0;
char * tmp=NULL; //辅助指针变量
char * myArray[10]={"aaa", "bbb", "ccc", "11111"};
//打印
printf("排序前\n");
num = sizeof(myArray)/sizeof(myArray[0]); // 对数组求长度;
printMyArray11(myArray, num);
//排序1,交换数组元组,即交换指针而非内存。
sortMyarray12(myArray, num);
//打印
printf("排序后\n");
printMyArray11(myArray, num);
}
第一种内存模型,内存分配图:指针数组在栈区,字符串在常量区,交换指针数组达到排序的目的。因为字符串在常量区,故不能通过交换内存的方式进行排序。
第二种内存模型:
2、char pointer[10][30]={“hello”, "world", "Tony"}; 字符串存储在常量区,并拷贝到栈区,结尾附带'\0'。高位维数必须指定。这种用法决定了数组名+1的步长。实参数组名+1的步长为第二维个char单位;形参若使用char ** 接收,步长xxx;形参若用char [][]接收, 形参+1步长为第二维个char单位。
第二种内存模型和第一种内存模型不同的是,1、第一种内存模型排序时,改变的是指针的指向,第二种是交换内存块;2、两者的形参的数据类型不一样,导致指针的步长不一样。(猜想可能由于栈区的内存块大小不一样所致。)3、两者的内存四区分配不一样。第一种在栈区分配内存存储指针数组,数组元素指向静态区的字符串;第二种在栈区分配内存,将静态区的字符串全部拷贝到栈区(拷贝包括字符串结尾符‘\0’),同时静态区保留一份备份。
两种内存模型的数据类型,做函数参数时牵扯到多级指针的退化问题,需特别注意形参定义的不同。
需掌握:打印、排序、封装成函数;
void main31()
{
int i=0, num =4;
char myBuf[30];
char tmpBuf[30];
char myArray[10][30]={"aaaaaa", "cccc", "bbbbb", "11111111"};
// 打印
printf("排序前");
for (i=0; i<num; i++)
{
printf("%s\n", myArray[i]);
}
// 排序
for (i=0; i<num; i++)
{
for (j=i+1; j<num; j++)
{
if ( strcmp(myArray[i], myArray[j])>0 )
{
strcpy(tmpBuf, myArray[i]);
strcpy(myArray[i], myArray[j]);
strcpy(myArray[j], tmpBuf);
}
}
}
// 打印
printf("排序后");
for (i=0; i<num; i++)
{
printf("%s\n", myArray[i]);
}
}
//封装成函数
void main()
{
int i=0, num =4;
char myBuf[30];
char tmpBuf[30];
char myArray[10][30]={"aaaaaa", "cccc", "bbbbb", "11111111"};
// 打印
printf("排序前");
// printMyArray21_1(myArray, num); // 程序download掉
printMyArray21_2(myArray, num); // 程序正常
// 排序
sortMyarray21(myArray[10][30], num);
// 打印
printf("排序后");
// printMyArray21_1(myArray, num); // 程序download掉
printMyArray21_2(myArray, num); // 程序正常
}
void printMyArray21_1(char **myArray, int num)
{
int i=0;
for (i=0; i<num; i++)
{
// printf("%s \n", myArray[i]);//
printf("%s \n", *(myArray+i)); // 问题本质:二级指针输入的第二种内存模型的 myArray+1 和第一种内存模型的 myArray+1 不一样,即指针所指向的内存空间的数据类型不一样,导致指针的步长不一样,导致第二种内存模型 myArray+1非法的内存访问。这种问题是多级指针做函数参数的退化问题。解决办法如:形参char **myArray 改为char myArray[10][30]。后续有更好的处理方法。
}
} //printMyArray21_1
void printMyArray21_2(char **myArray, int num)
{
int i=0;
for (i=0; i<num; i++)
{
// printf("%s \n", myArray[i]);//
printf("%s \n", *(myArray+i)); // 多级指针做函数参数的退化问题。解决办法如:形参char **myArray 改为char myArray[10][30]
}
} //printMyArray21_2
void sortMyarray21(char myArray[10][30], int num)
{
int i, j =0;
char tmpBuf[30];
for (i=0; i<num; i++)
{
for (j=i+1; j<num; j++)
{
if ( strcmp(myArray[i], myArray[j])>0 )
{
strcpy(tmpBuf, myArray[i]); // 交换的是内存块。
strcpy(myArray[i], myArray[j]);
strcpy(myArray[j], tmpBuf);
}
}
}
}
第三种内存模型:
3、char **pointer是第三种内存模型。总指针在栈区,数组元素即一维指针在堆区,一维指针的指向的元素也在堆空间。
void main03()
{
int i = 0, j=0;
char ** p2 = NULL;
int num=5;
char * tmp;
char tmpbuf[100];
p2=(char **)malloc(sizeof(char)*num);
for (i=0;i<num;i++)
{
p2[i]=(char *)malloc(sizeof(char) * 100); //定义了num个buf[100]
sprintf(p2[i], "%d%d%d", i+1, i+1, i+1);//sprintf(),将字符串输入到p2中。
} //for end
//排序之前:
for (i=0;i<num;i++)
{
printf("%s \n", p2[i]);
}//for end
//排序,交换指针指向;
/*
for (i=0;i<num;i++)
{
for (j=i+1;j<num;j++)
{
if(strcmp(p2[i], p2[j])<0)
{
tmp=p2[i];
p2[i]=p2[j];
p2[j]=tmp;
}
}//for end
}//for end
*/
//排序,交换内存:
for (i=0;i<num;i++)
{
for (j=i+1;j<num;j++)
{
if(strcmp(p2[i], p2[j])<0)
{
strcmp(tmpbuf, p2[i]);
strcmp(p2[i], p2[j]);
strcmp(p2[j], tmpbuf);
}
}//for end
}//for end
// 释放内存:先申请的后释放。
for (i=0;i<num;i++)
{
if(p2[i]!=NULL)
{
free(p2[i]);
p2[i]=NULL;
}
}//for end
if(p2!=NULL)
{
free(p2);
p2=NULL;
}
}//main end
//***************指针做函数参数***************
char **getMem(int num)
{
char **p2=NULL;
int i;
p2=(char **)malloc(sizeof(char*) * num); // num=5个(char * )类型大小的空间,即4*5=20个字节,32位系统。p2+1,步长为char **个字节,即4个字节,因此正好跳到了下一个“char *”的指针的首地址。
if(p2==NULL)
{
return NULL;
}
for (i=0;i<num; i++)
{
p2[i]=(char *)malloc(sizeof(char)*100);
sprintf(p2[i], "%d%d%d", i+1, i+1, i+1);
}
return p2;
}//getMem end
void printArray03(char ** myArray, int num)
{
int i=0;
for (i=0;i<num;i++)
{
// printf("%s\n", myArray[i]);
printf("%s \n", *(myArray+i));
}
}//printArray03 end
void sortArray03(char ** myArray, int num) //交换指针和交换内存都可。现在时交换指针。
{
int i, j=0;
char *tmp=NULL;
for(i=0;i<num;i++)
{
for(j=i+1;j<num;j++)
{
tmp=myArray[i];
myArray[i]=myArray[j];
myArray[j]=tmp;
}
} //for loop end
}//sortArray03 end
void getMemFree(char **p2, int num)
{
// 释放内存:先申请的后释放。
for (i=0;i<num;i++)
{
if(p2[i]!=NULL)
{
free(p2[i]);
p2[i]=NULL;
}
}//for end
if(p2!=NULL)
{
free(p2);
p2=NULL;
}
}//getMemFree
void main()
{
int i = 0, j=0;
char ** p2 = NULL;
int num=5;
char * tmp;
char tmpbuf[100];
p2=getMem(num);//分配内存
//排序之前:
printArray03(p2, num);
sortArray03(p2, num);
//排序,交换指针指向;
/*
for (i=0;i<num;i++)
{
for (j=i+1;j<num;j++)
{
if(strcmp(p2[i], p2[j])<0)
{
tmp=p2[i];
p2[i]=p2[j];
p2[j]=tmp;
}
}//for end
}//for end
*/
//排序,交换内存:
/*
for (i=0;i
{
for (j=i+1;j<num;j++)
{
if(strcmp(p2[i], p2[j])<0)
{
strcmp(tmpbuf, p2[i]);
strcmp(p2[i], p2[j]);
strcmp(p2[j], tmpbuf);
}
}//for end
}//for end
*/
//排序后
printArray03(p2, num);
// 释放内存:先申请的后释放。
getMemFree(p2,num);//注意,此时p2是野指针!
}//main end
第一种内存模型:指针数组;第二种内存模型:多维数组;第三种内存模型:自己分配内存;
第三种内存模型:交换指针排序和交换内存空间排序都可以;打印:可以复用第一种内存模型的api函数;注意使用函数释放空间时,可能造成实参野指针现象!
留下的疑问:1、第二种内存模型,调用函数时,函数形参的形式;2、第二种内存模型,调用函数时,形参的步长?实参的步长?3、一维或多维数组做函数参数时的退化问题,及其步长问题;4、第三种内存模型,free内存函数易造成实参野指针,如何避免?