今天给大家分享一下最近学习到的关于二级指针方面的知识。
首先说明一下二级指针的三种内存模型,即指针数组,指向指针的指针,二维数组。
首先来看指针数组,指针数组的定义方式
//数组 数组中的每一个元素是指针 指针数组
char *myArray[] = { "aaaa","cccc","bbb","1111" };
由于[]和*的优先级一致,但是变量是自右向左进行结合的,所以先与[]结合,再与*结合,所以myArray是一个数组,每个数组中存储的char 类型的指针。
先来看看如何打印该变量。代码如下
void printArray(char **myArray,int num)
{
int i = 0;
for (i = 0;i < num;i++)
{
printf("%s \n", *(myArray + i));
}
}
利用*取到数组中的首元素的地址,打印出字符串。
接下来是排序操作,代码如下
void sortMyArray(char **myArray, int num)
{
int i = 0, j = 0;
char *tmp = NULL;
//排序
for (i = 0;i < num;i++)
{
for (j = i;j < num;j++)
{
if (strcmp(myArray[i], myArray[j])>0)
{
//交换的是数组元素,即指针的值
tmp = myArray[i];
myArray[i] = myArray[j];
myArray[j] = tmp;
}
}
}
}
这边需要注意的是交换元素交换的是指针变量中储存的地址,即指针的指向。
接下来看一下二维数组的排序操作和打印操作。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//打印 排序
//内存越界
//myArray+1和第一种的不一样
//指针的步长不一样,指针所指向的内存空间的数据不一样
void printArray31(char myArray[10][30], int num)
{
int i = 0;
for (i = 0;i < num;i++)
{
printf("%s \n", *(myArray + i));
}
}
void sortMyArray32(char myArray[10][30], int num)
{
int i = 0, j = 0;
char myBuf[30];
for (i = 0;i < num;i++)
{
for (j = i + 1;j < num;j++)
{
//交换的是内存块
if (strcmp(myArray[i], myArray[j])>0)
{
strcpy(myBuf, myArray[i]);
strcpy(myArray[i], myArray[j]);
strcpy(myArray[j], myBuf);
}
}
}
}
int main(int argc, char *argv[])
{
int num = 4;
char myArray[10][30] = { "aaaa","cccc","bbbb","111111111" };
//myArray:编译器只会关心:有10行,每行30列
{
int len1 = sizeof(myArray);
int len2 = sizeof(myArray[0]);
int size = len1 / len2;
printf("len1:%d,len2:%d,size:%d\n", len1, len2, size);
}
printf("排序之前\n");
//打印
printArray31(myArray, num);
sortMyArray32(myArray, num);
printf("排序之后\n");
//打印
printArray31(myArray, num);
system("pause");
return 0;
}
二维数组在进行传参的时候不能利用二级指针来传,主要原因是因为两者之间的步长不一致,在进行排序操作的时候,由于数组名是个常量,所以只能利用内存拷贝的方式来交换值。
接下来是二级指针
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **getMem41(int num)
{
char **p2 = NULL;
int i = 0;
p2 = (char **)malloc(sizeof(char *)*num);
if (p2 == NULL)
{
return p2;
}
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;
}
void printArray41(char **myArray, int num)
{
int i = 0;
for (i = 0;i < num;i++)
{
printf("%s \n", *(myArray + i));
}
}
void sortMyArray41(char **myArray, int num)
{
int i = 0, j = 0;
char *tmp = NULL;
//排序
for (i = 0;i < num;i++)
{
for (j = i;j < num;j++)
{
if (strcmp(myArray[i], myArray[j])<0)
{
//交换的是数组元素,即指针的值
tmp = myArray[i];
myArray[i] = myArray[j];
myArray[j] = tmp;
}
}
}
}
void getMem_Free41(char **p2,int num)
{
int i = 0;
//释放内存
for (i = 0;i < num;i++)
{
if (p2[i] != NULL)
{
free(p2[i]);
p2[i] = NULL;
}
}
if (p2 != NULL)
{
free(p2);
}
}
int main(int argc,char *argv[])
{
int i = 0, j = 0;
char **p2 = NULL;
char *tmp = NULL;
int num = 5;
char tmpbuf[100];
p2 = getMem41(num);
printf("排序之前\n");
printArray41(p2, num);
//排序,交换的是内存
sortMyArray41(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;
}
}
}
*/
printf("排序之后\n");
printArray41(p2, num);
//p2是一个野指针
getMem_Free41(p2, num);
system("pause");
return 0;
}
接下来看一下这三种模型的内存图
这边需要注意是当实参是二维数组的时候,形参不能是二级指针,这边做个简单的讲解。
首先来看编译器的提醒。
“char **”与“char [10][30]”的间接级别不同,说明两者之间的类型是不一致的。
当运行的时候会发现
直接出现dump的情况。
这时候我们进行调试
我们会发现myArray[0]存储的地址是0x61616161, 而实参数组中myArray[0]中存储的地址明显不是这个值。
这边做个推演。
int a[2][3]={1,2,3,4,5,6};
int **p = a;
这时候p=&a[0];
又由于a[0]中存储的又是&a[0][0],所以p=&a[0][0];
这时候如果直接*p的话就是数字1,再加一个*号的话就是代表1地址中的值,对应之前调试的结果,*myArray的值是0x61616161,这是由于aaaa在内存中的ascii值是97,97的十六进制即是61,一个指针变量的大小是4个字节,如果这样取的话那结果就是取未知内存0x61616161的值,就出现dump的情况。
这边感谢一下三位大佬提供的资料,附上他们的链接。
二维数组和指向指针的指针 - Leo.Z - 博客园 (cnblogs.com)