【C语言】深入理解指针(中)

请添加图片描述
主页链接: LSR的主页
专栏链接: 《C语言》


前言

以下是对指针板块的进一步理解,希望可以帮助到你。


一、数组名的理解

&arr[0]和arr本质上是等价的,都是指数组首元素的地址。示例代码如下:

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

输出结果:

&arr[0] = 004FF9CC
arr     = 004FF9CC

因此,我们一般认为数组名arr就是表示首元素的地址。
但是有两种结果情况除外:
1.sizeof(数组名),其中的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
2.&数组名,这里的数组名表示整个数组,那么取出的就是整个数组的地址(这里在指针±整数的时候会有所体现)。
除此之外,数组名都表示首元素的地址。


二、使用指针访问数组

先说结论:
arr[i]等价于*(arr+i)
同理,我们将arr放入 int* p中

int* p = arr;

那么p存放的就是首元素的地址,所以arr[i]同样等价于p[i]等价于*(p+i)
那我们访问数组的方式就有很多了:

int arr[] = {1, 2, 3};
int* p = arr;
sz = sizeof(arr)/sizeof(arr[0]);
for(i = 0;i<sz;i++)
{
        printf("%d", p[i]);//可以用上面形式等价代换
}

三、一维数组传参的本质

1.函数内部不可以求数组的元素个数,示例代码如下:

 void test1(int arr[])
 {
        int sz1 = sizeof(arr)/sizeof(arr[0]);
        printf("sz1 = %d\n", sz1);
 }
 void test2(int* arr)
  {
        int sz2 = sizeof(arr)/sizeof(arr[0]);
        printf("sz2 = %d\n", sz2);
 }
#include<stdio.h>
int main()
{
         int arr[] = {1, 2, 3, 4, 5};
         int sz = sizeof(arr)/sizeof(arr[0]);
         printf("sz = %d\n", sz);
         test1();
         test2();
}

输出结果:

sz  = 5;
sz1 = 1;
sz2 = 1;

arr[]等价于*arr,所以我们传入的是一个地址,而sizeof(arr)计算的是一个地址的大小,并不是数字的大小,而地址的大小是固定的,只和系统平台有关(详见深入理解指针(上)),所以在函数内部是无法计算数组元素个数的。
总结:一维数组传参,形参部分可以写成数组形式,也可以写成指针形式。


四、冒泡排序

核心思想:两两相邻的元素进行比较。

//升序
void bubble_sort(int arr[], int sz)//参数接收数组元素个数
{
 int i = 0;
 for(i=0; i<sz-1; i++)//需要进行的趟数
 {
 int flag = 1;//假设这一趟已经有序了
 int j = 0;
 for(j=0; j<sz-i-1; j++)//每一趟需要比较的次数,随着趟数增加,排好序的数字增多,需要比较的次数就减少
 {
 if(arr[j] > arr[j+1])
 {
 flag = 0//需要交换就说明还无序
 int tmp = arr[j];
 arr[j] = arr[j+1];
 arr[j+1] = tmp;
 }
 }
 if(flag == 1)//有序了后续就不需要继续排序了
 break;
 }
}
int main()
{
 int arr[] = {3,1,7,5,8,9,0,2,4,6};
 int sz = sizeof(arr)/sizeof(arr[0]);
 bubble_sort(arr, sz);
 for(i = 0;i < sz - 1;i++)
 {
     printf("%d ", *(arr+i));
 }
 return 0;

五、二级指针

二级指针就是用来存放指针变量的地址。
在这里插入图片描述

int b = 20;
int* pb = &b;
int** ppb = &pb;
*ppb  == &b;//等价于pb == &b
**ppb == 30;//等价于*pb == 30,b == 30;

六、指针数组

顾名思义,指针数组就是用来存放指针(地址)的数组。
在这里插入图片描述
指针数组的每个元素都是地址,又可以指向一块区域。


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

#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*
     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]);//等价于*(*(parr+i)+j)
          }
     }
}

在这里插入图片描述
上述代码知识模拟出了二维数组的效果,实际上并非完全是二维数组,因为每一行并非是连续的,而二维数组在内存中是连续存放的。


八、字符指针变量

const char* pstr = "hello bit.";

把字符串hello bit.首字符的地址放到了pstr中。
放在代码中:

#include <stdio.h>
int main()
{
 char str1[] = "hello bit.";
 char str2[] = "hello bit.";
 const char *str3 = "hello bit.";
 const char *str4 = "hello bit.";
 if(str1 ==str2)
 printf("str1 and str2 are same\n");
 else
 printf("str1 and str2 are not same\n");
 
 if(str3 ==str4)
 printf("str3 and str4 are same\n");
 else
 printf("str3 and str4 are not same\n");
 
 return 0;
}

在这里插入图片描述
这里str1 和 str2指向不同的地址,为两块不同的空间,str3和str4指向相同的地址,指向相同的内容。


九、数组指针变量

基本形式:

int (*p)[10];

作用:用来存放数组地址:

int arr[10] = {0};
&arr;//整个数组的地址
//如果要存放数组的地址,就得引入数组指针变量
int (*p)[10] = &arr;

这里p和&arr的类型完全一致,都是int*。

数组指针类型解析:
int (*p) [10] = &arr;
| | |
| | |
| | p指向数组的元素个数
| p是数组指针变量名
p指向的数组的元素类型


十、二维数组传参本质

二维数组传参给一个函数:

#include<stdio.h>
void test(int a[3][5], int r, int c)
{
       int i = 0;
       int j = 0;
       for(i = 0;i<r;i++)
       {
              for(j = 0;j<c;j++)
              {
                       printf("%d ", a[i][j]);
              }
              printf("\n");
       }
}

int main()
{
       int arr[3][5] = {{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};
       test(arr,3, 5);
       return 0;
}

arr的首元素为第一行,把每一行看作一个一维数组,这里就可以使用数组指针类型实现:

#include<stdio.h>
void test(int (*p)[5], int r, int c)
{
       int i = 0;
       int j = 0;
       for(i = 0;i<r;i++)
       {
              for(j = 0;j<c;j++)
              {
                       printf("%d ",*(*(p+i)+j));
              }
              printf("\n");
       }
}

int main()
{
       int arr[3][5] = {{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};
       test(arr,3, 5);
       return 0;
}

总结:二维数组传参,形参的部分可以写成数组,也可以写成数组指针的形式。


本文是对指针的进一步理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值