主页链接: 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;
}
总结:二维数组传参,形参的部分可以写成数组,也可以写成数组指针的形式。
本文是对指针的进一步理解。
&spm=1001.2101.3001.5002&articleId=155498533&d=1&t=3&u=928883aa0a3d40f48fc9bffffab02040)
1676

被折叠的 条评论
为什么被折叠?



