二級(jí)指針作輸入,有三種內(nèi)存模型,以字符型指針為例:
第一種內(nèi)存模型:
1、char *pointer[10],pointer自動(dòng)退化為一個(gè)二級(jí)指針,其實(shí)質(zhì)是char **pointer。這種用法是指針數(shù)組的用法,編譯器在棧區(qū)分配內(nèi)存。
需要掌握:1、排序;2、指針做函數(shù)參數(shù)排序;3、畫(huà)出內(nèi)存分配圖。
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]); // 對(duì)數(shù)組求長(zhǎng)度;
for (i=0; i<num; i++)
{
? ? printf("%s \n", myArray[i]);
? ? //printf("%s \n", *(myArray+i)); 兩種方式都可以
}
//排序1,交換數(shù)組元組,即交換指針而非內(nèi)存。
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)); 兩種方式都可以
}
}
////////指針做函數(shù)參數(shù)
void printMyArray11(char **myArray, int num) //數(shù)組做函數(shù)參數(shù),會(huì)退化為指針,因此需要將數(shù)組長(zhǎng)度傳進(jìn)來(lái)。
{
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]); // 對(duì)數(shù)組求長(zhǎng)度;
printMyArray11(myArray, num);
//排序1,交換數(shù)組元組,即交換指針而非內(nèi)存。
sortMyarray12(myArray, num);
//打印
printf("排序后\n");
printMyArray11(myArray, num);
}
第一種內(nèi)存模型,內(nèi)存分配圖:指針數(shù)組在棧區(qū),字符串在常量區(qū),交換指針數(shù)組達(dá)到排序的目的。因?yàn)樽址诔A繀^(qū),故不能通過(guò)交換內(nèi)存的方式進(jìn)行排序。

第二種內(nèi)存模型:
2、char pointer[10][30]={“hello”, "world", "Tony"}; 字符串存儲(chǔ)在常量區(qū),并拷貝到棧區(qū),結(jié)尾附帶'\0'。高位維數(shù)必須指定。這種用法決定了數(shù)組名+1的步長(zhǎng)。實(shí)參數(shù)組名+1的步長(zhǎng)為第二維個(gè)char單位;形參若使用char ** 接收,步長(zhǎng)xxx;形參若用char [][]接收, 形參+1步長(zhǎng)為第二維個(gè)char單位。
第二種內(nèi)存模型和第一種內(nèi)存模型不同的是,1、第一種內(nèi)存模型排序時(shí),改變的是指針的指向,第二種是交換內(nèi)存塊;2、兩者的形參的數(shù)據(jù)類(lèi)型不一樣,導(dǎo)致指針的步長(zhǎng)不一樣。(猜想可能由于棧區(qū)的內(nèi)存塊大小不一樣所致。)3、兩者的內(nèi)存四區(qū)分配不一樣。第一種在棧區(qū)分配內(nèi)存存儲(chǔ)指針數(shù)組,數(shù)組元素指向靜態(tài)區(qū)的字符串;第二種在棧區(qū)分配內(nèi)存,將靜態(tài)區(qū)的字符串全部拷貝到棧區(qū)(拷貝包括字符串結(jié)尾符‘\0’),同時(shí)靜態(tài)區(qū)保留一份備份。
兩種內(nèi)存模型的數(shù)據(jù)類(lèi)型,做函數(shù)參數(shù)時(shí)牽扯到多級(jí)指針的退化問(wèn)題,需特別注意形參定義的不同。
需掌握:打印、排序、封裝成函數(shù);
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]);
????}
}
//封裝成函數(shù)
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)); // 問(wèn)題本質(zhì):二級(jí)指針輸入的第二種內(nèi)存模型的 myArray+1? 和第一種內(nèi)存模型的 myArray+1 不一樣,即指針?biāo)赶虻膬?nèi)存空間的數(shù)據(jù)類(lèi)型不一樣,導(dǎo)致指針的步長(zhǎng)不一樣,導(dǎo)致第二種內(nèi)存模型 myArray+1非法的內(nèi)存訪問(wèn)。這種問(wèn)題是多級(jí)指針做函數(shù)參數(shù)的退化問(wèn)題。解決辦法如:形參char **myArray 改為char myArray[10][30]。后續(xù)有更好的處理方法。
}
} //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)); // 多級(jí)指針做函數(shù)參數(shù)的退化問(wèn)題。解決辦法如:形參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]);? // 交換的是內(nèi)存塊。
strcpy(myArray[i], myArray[j]);
strcpy(myArray[j],?tmpBuf);
????}
????}
}
}
第三種內(nèi)存模型:
3、char **pointer是第三種內(nèi)存模型??傊羔樤跅^(qū),數(shù)組元素即一維指針在堆區(qū),一維指針的指向的元素也在堆空間。
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個(gè)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
*/
//排序,交換內(nèi)存:
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
// 釋放內(nèi)存:先申請(qǐng)的后釋放。
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
//***************指針做函數(shù)參數(shù)***************
char **getMem(int num)
{
char **p2=NULL;
int i;
p2=(char **)malloc(sizeof(char*) * num); // num=5個(gè)(char * )類(lèi)型大小的空間,即4*5=20個(gè)字節(jié),32位系統(tǒng)。p2+1,步長(zhǎng)為char **個(gè)字節(jié),即4個(gè)字節(jié),因此正好跳到了下一個(gè)“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)? //交換指針和交換內(nèi)存都可?,F(xiàn)在時(shí)交換指針。
{
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)
{
// 釋放內(nèi)存:先申請(qǐng)的后釋放。
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);//分配內(nèi)存
//排序之前:
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
*/
//排序,交換內(nèi)存:
/*
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);
// 釋放內(nèi)存:先申請(qǐng)的后釋放。
getMemFree(p2,num);//注意,此時(shí)p2是野指針!
}//main end

第一種內(nèi)存模型:指針數(shù)組;第二種內(nèi)存模型:多維數(shù)組;第三種內(nèi)存模型:自己分配內(nèi)存;
第三種內(nèi)存模型:交換指針排序和交換內(nèi)存空間排序都可以;打?。嚎梢詮?fù)用第一種內(nèi)存模型的api函數(shù);注意使用函數(shù)釋放空間時(shí),可能造成實(shí)參野指針現(xiàn)象!
留下的疑問(wèn):1、第二種內(nèi)存模型,調(diào)用函數(shù)時(shí),函數(shù)形參的形式;2、第二種內(nèi)存模型,調(diào)用函數(shù)時(shí),形參的步長(zhǎng)?實(shí)參的步長(zhǎng)?3、一維或多維數(shù)組做函數(shù)參數(shù)時(shí)的退化問(wèn)題,及其步長(zhǎng)問(wèn)題;4、第三種內(nèi)存模型,free內(nèi)存函數(shù)易造成實(shí)參野指針,如何避免?