指针(2)

目录

一.数组名的理解

1.通关代码举例:

(1)讨论数组名到底是不是首元素的地址?

(2)整个数组的地址和数组首元素的地址的区别:

二.使用指针访问数组

三.一维数组传参的本质

四.冒泡排序

2.练习

五.二级指针

1.二级指针

2.二级指针用法

六.指针数组

七.指针数组模拟二维数组


一.数组名的理解

1.通关代码举例:

(1)讨论数组名到底是不是首元素的地址?

int main()
{
	char arr[10] = "0";

	printf("%p\n", arr[0]);//007AFE3C
	printf("%p\n", arr);   //007AFE3C

	printf("%d\n", sizeof(arr));//10
//1.数组名不是传递首元素地址吗?sizeof计算出来应该首元素的大小才对,但这里计算的是整个数组大小。

	printf("%p\n", &arr);  //007AFE3C
//2.&数组名表示是整个数组,取出的是整个数组的地址。


	return 0;
}

特例:有2个数组名取的是整个数组的地址
1.sizeof(数组名)内部单独放一个数组名的时候,数组名表示整个数组,计算的是整个数组的大小,单位是字节。
2. & 数组名,这的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组的元素
的地址是有区别的)。
除此之外,遇到的所有数组名都是数组元素的地址。

特点:不管取的首元素地址,还是取的整个元素地址,他们拿到的都是首元素地址。
arr[0];//007AFE3C
arr;    //007AFE3C
&arr;  //007AFE3C

(2)整个数组的地址和数组首元素的地址的区别:

int main()
{
	int arr[10] = { 0 };
	//(1)
	printf("%p\n", &arr[0]);//int*类型
	printf("%p\n", &arr[0] + 1);//跳过4个字节
	//(2)
	printf("%p\n", arr);//int*类型
	printf("%p\n", arr + 1);//跳过4个字节
	//(3)
	printf("%p\n", &arr);//类型?
	printf("%p\n", &arr + 1);//跳过40个字节,类型不一样

	return 0;
}

讨论:指针+1取决于类型,所以&arr取数组名到底是什么类型?
注意:取出数组的地址和取出数组首元素的地址,从值上来看是一样的,但有很大的区别。

二.使用指针访问数组

(1)因为数组在内存中是连续存放的。
(2)数组名就是首元素的地址(方便找到起始位置)。
(3)可以使用指针访问数组。

代码举例:指针访问数组

总结:
1.上面4种写法,只是写法不同,编译器都是转换成第二种写法计算的。
2.我平常使写代码,一般只用1,2种写。
3.数组名就是地址,数组访问元素依然通过指针找的,数组的本质就是指针。
4.所有关于指针的运算,底层最终都是指针( + -)整数,指针解引用相关运算。

补充:
因为数组名和指针等价 pa < == > arr 等价
scanf:
&arr[i] = &pa[i];
pa + i = arr + i;
&i[pa] = &i[arr];

printf:
arr[i] = pa[i];
*(arr + i) = *(pa + i);
i[arr] = i[pa]

三.一维数组传参的本质

先从一个问题开始,我们之前都是在函数外部计算数组的元素个数,那我们可以把数组传给个函
数后,函数内部求数组的元素个数吗?用sizeof计算 。

void fufu(int arr[])//数组形式
{
	int sz = sizeof(arr) / sizeof(arr);// 4 / 4 =1
	//sizeof这里拿到的只是第一个元素的地址

	printf("%d", sz);//? 1
}
void fufu(int* arr)//指针形式
{
	int sz = sizeof(arr) / sizeof(arr);// 4 / 4 =1
	printf("%d", sz);//? 1
}
int main()
{
	int arr[10] = { 0 };
	fufu(arr);//这里数组名就是数组首元素的地址
	return 0;
}

最终通过代码发现传参之后的值不一样,为什么?

1.数组传参的时候,传递的是并非是整个数组。
2.传递的是数组首元素的地址。做不到传递整个数组。
3.数组传参,形参部分可以写成数组的形式,也可以写成指针形式,只是形式上的差异,本质上一模一样。
4.使用sizeof计算数组个数,要在没传参之前求,求完之后以参数形式传给函数。如果想在函数里面求做不到,一旦传参就变了。
5.没传参之前是个数组,传参之后就是首元素地址。
6.数组变成首元素地址了,这叫(降级)。

数组传参和变量传参区别:
1.数组传参,形参部分写成数组,也不会创建数组,本质是指针,还是访问实参的数组。
2.变量传参:形参和实参不是同一块空间。

讨论:为啥不传递整个数组 ,代价非常大,从空间节省来说
假设一个数组放了一个1000个元素。
实参传给形参,形参要自己创建一块空间,要是传递整个数组,那我是不是又要创建能放下1000个元素的空间。所以只需要传递首元素地址,访问主函数里面元素就行。

四.冒泡排序

排序的方法很多:
1.冒泡排序
2.选择排序
3.插入排序
4.希尔排序
5.快速排序……等等。

2.练习

题目:写一个函数,对一个整形数组的数据进行排序。

冒泡排序讲解:
核心思想:相邻的两个元素比较,如果不满足顺序就交换!

函数实现:

int count = 0;//比较的次数
void fufu(int* arr, int sz)
{
	int flag = 1;//假设已经有序
	//1.趟数:sz-1
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		//2.一趟冒泡排序的过程
		int j = 0;
		//3.一趟冒泡排序进行比较的对数:sz-1-i
		for (j = 0; j < sz - 1 - i; j++)
		{
			//4.一对数的比较,和交换
			if (arr[j] > arr[j + 1])
			{
				//5..交换
				int tmp = 0;
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				//6.一但交换,flag变为0
				flag = 0;//还不是有序的
				count++;//比较一次count++
			}
		}
		if (flag == 1)
		{
			break;

		}
	}
}
void PrintfAdd(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	fufu(arr, sz);//冒牌排序的实现
	PrintfAdd(arr, sz);//打印数组的实现

	printf("\ncount = %d\n", count);//count = 45

	return 0;
}

五.二级指针

一级指针:
char* pc
int* pi
double* pd;只有一颗*都是一级指针。

1.二级指针

代码举例:

2.二级指针用法

代码举例:

int main()
{
	int a = 10;
	int* p = &a;
	int** pp = &p;

	printf("%d\n", **pp);//10

	return 0;
}

第一次解引用得到p,第二次解引用得到a的值。

总结:
指针变量也是变量!只是用来存放地址的,除此之外没啥nb的了。
指针变量也有地址,也可以被其他指针变量存起来!
语法虽然支持多级指针写法,但一般用到二级指针差不多了。
二级指针就是一个普通的变量而已,这个变量只不过用来存放一级指针变量地址。

补充:错误写法
当二级指针,指针变量的类型写错了,少写一颗星,可以存放一级指针的地址,但解引用和(+-)权限也会有变化,所以类型写错了,计算也会有问题。

六.指针数组

指针数组是指针还是数组?是数组,是指针类型的数组。

整形数组 - 存放整形数据的数组(数组中每个元素是整形类型)
字符数组 - 存放字符数据的数组(数组中每个元素是字符类型)
指针数组 - 存放指针的数组(数组中的每个元素是指针类型)
int arr[10]; 整形数组
char ch[5]; 字符数组

希望有一个数组,数组有4个元素,每个元素是整形指针
int* arr[4];每个元素是整形指针,所以是指针数组。
总结:指针数组每个元素都是指针。

七.指针数组模拟二维数组

模拟写出二维数组的效果,但不是二维数组。
代码举例:
补充:二维数组的每一行是一个一维数组

int main()
{
	//1.这3个一维数组当做二维数数组每一行
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };

	//2.用指针数组,包装3个数组
	int* arr[3] = { arr1,arr2,arr3 };//整形指针数组

	//3.打印元素
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0;j < 5; j++)
		{
			//第一种写法:数组方式
			printf("%d ", arr[i][j]);
			//第二种写法:解引用方式
			printf("\n%d ", *(*(arr+i)+j);


		}
	}

	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值