深入了解指针(2) 指针与数组,冒泡排序,二级指针,指针数组

1.数组名的理解

int arr[10]={1,2,3,4,5,6,7};
int *p=&arr[0];

这里&arr[0]取得的是第一个元素的地址。但其实数组名名本来就是地址,而且是首元素的地址。下面就验证一下。

int main()
{
	int arr[10] = {1,2,3,4,5,6};
	printf("%p\n",arr);
	printf("%p\n", &arr[0]);
	return 0;
}

在这里插入图片描述
我们可以发现数组名和首元素地址相同,但也有例外

int main()
{
	
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	printf("%d",sizeof(arr));
	return 0;
}

在这里插入图片描述
如果arr首元素的地址的话那么应该是4/8个字节,但显然不是。那这是怎么回事呢?

其实数组名就是数组⾸元素(第⼀个元素)的地址是对的,但是有两个例外:
• sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,单位是字节
• &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素的地址是有区别的)除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。

下面就用代码那看看

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%p\n",arr);
	printf("%p\n", &arr[0]);
	printf("%p\n", &arr);
	return 0;
}

在这里插入图片描述

从这里看出来地址首元素地址和数组的地址又有什么区别呢?
我们从下面的代码来看看吧。

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("  &arr[0]==   %p\n", &arr[0]);
	printf("  &arr[0]+1== %p\n", &arr[0]+1);
	printf("  arr==       %p\n", arr);
	printf("  arr+1==     %p\n", arr+1);
	printf("  &arr==      %p\n", &arr);
	printf("  &arr+1==    %p\n", &arr+1);

	return 0;
}


由此可以看出对于&arr[0]和arr加一都是变化4个字节,即1个字节,但是对于&arr则是变化40个字节,即10个整形。因此对于&arr[0]和arr加一都是加一个元素,而对于&arr则是变化了一个数组的大小。

2.使用指针访问数组

int main()
{
	int arr[10] = {0};
	int i = 0;
	int* p= arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		scanf("%d",p+i);
		//也可以写成scanf("%d",arr+i);  因为p与arr都代表首元素地址
		//这里是可以灵活变化的
	}
	for (i = 0; i < sz; i++)
	{
		printf("%d ",p[i]);
		//p[i]也可以用下面代替
		//*(p+i)
		//*(arr+1)
		//arr[i]
		//p[i]
	}
	return 0;
}

在这里插入图片描述

3.一维数组传参的本质

#include <stdio.h>

void test(int arr[])
{
	int sz2 = sizeof(arr) / sizeof(arr[0]);
	printf("sz2 = %d\n", sz2);
}
 int main()
 {
	 int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	 int sz1 = sizeof(arr) / sizeof(arr[0]);
	 printf("sz1 = %d\n", sz1);
	 test(arr);
	 return 0;
	 }

在这里插入图片描述
从此看出在函数内部没有算出正确的大小。
这就要学习数组传参的本质了,上个⼩节我们学习了:数组名是数组⾸元素的地址;那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参本质上传递的是数组⾸元素的地址。所以算不出来正确的元素个数。

4,冒泡排序

#define _CRT_SECURE_NO_WARNINGS 1
//本函数是将乱序的数排列成正序
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void sort(int arr[], int sz)
{
    //确定冒泡排序的趟数
    int i = 0;
    for (i = 0; i < sz - 1; i++)  //趟数等于元素个数减1,所以i<sz-1
    {
        //一趟冒泡排序
        int flag = 1;//假设数组是有序的     flag的出现是为了优化程序,使得当已经满足要求时不再进行交换
        int j = 0;
        for (j = 0; j < sz - 1 - i; j++)  //j<sz-1-i  的原因:例如有1,2,3  要排序,按照冒泡排序是将1与2交换再与3交换得到2,3,1,进行了2次比较
        {   //这就是进行了一趟冒泡排序,再下一次将2与3交换,这里2就不要再与1比较了,所以进行了1次比较,得到3,2,1
            //因此每经过一趟冒泡排序就少一次比较次数,而i从0开始所以sz在减去i后要再减去1
            if (arr[j] > arr[j + 1])
            {
                //交换
                int tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
                flag = 0;//不是有序
            }
        }
        if (flag == 1)
        {
            break;
        }

    }
}
void print(int* arr, int sz)
{
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        printf("%d ", arr[i]);
    }
}
int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    int sz = sizeof(arr) / sizeof(arr[0]);  //在main函数中将数组大小算出来
    sort(arr, sz);
    print(arr, sz);
    return 0;
}

5.二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪⾥?

下面就是一个二级指针的示意图:
在这里插入图片描述
对于⼆级指针的运算有:
*ppa 通过对ppa中的地址进⾏解引⽤,这样找到的是 pa , *ppa 其实访问的就是 pa

**ppa 先通过 *ppa 找到 pa ,然后对 pa 进⾏解引⽤操作: *pa ,那找到的是 a

6.指针数组

指针数组是指针还是数组?
我们类⽐⼀下,整型数组,是存放整型的数组,字符数组是存放字符的数组。
那指针数组呢?是存放指针的数组。
在这里插入图片描述

7.指针模拟二维数组

#include <stdio.h>
 int main()
{
int arr1[] = {1,2,3,4,5};
 int arr2[] = {2,3,4,5,6};
 int arr3[] = {3,4,5,6,7};
 //数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中
 int* parr[3] = {arr1, arr2, arr3};
 int i = 0;
 int j = 0;
 for(i=0; i<3; i++)
 {
 for(j=0; j<5; j++)
 {
 printf("%d ", parr[i][j]);
 }
 printf("\n");
 }
 return 0;
 }

在这里插入图片描述
parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型⼀维数组,parr[i][j]就是整型⼀维数组中的元素。
上述的代码模拟出⼆维数组的效果,实际上并⾮完全是⼆维数组,因为每⼀⾏并⾮是连续的.

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南子北游

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值