c语言之二级指针

今天给大家分享一下最近学习到的关于二级指针方面的知识。

首先说明一下二级指针的三种内存模型,即指针数组,指向指针的指针,二维数组。

首先来看指针数组,指针数组的定义方式

    //数组 数组中的每一个元素是指针 指针数组
    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)

 二维数组和二级指针 - 苏苏苏紫Sue - 博客园 (cnblogs.com)

为什么不能用二级指针直接指向二维数组_yongheng_1999的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值