二级指针做输入的三种内存模型

二级指针作输入,有三种内存模型,以字符型指针为例:

第一种内存模型:

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内存函数易造成实参野指针,如何避免?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容