C语言学习!
? ? ? ? 上一篇博文C语言 指针-CSDN博客简单介绍了指针,本篇文章是对指针内容的补充。
- 数组:一组相同类型元素的集合。
- 指针变量:是一个变量,存放的是地址。
- 数组可以通过指针访问。
? ? ? ? arr 是数组,表达式 arr 的值就与 arr[0] 的地址,即 &arr[0] 一致,如果数组 arr 的元素类型为 int 型,那么不管元素个数是多少,表达式 arr 的类型就是 int* 型。
代码示例:
#include <stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("&a[%d] = %p p+%d = %p\n", i, &arr[i], i, p + i);
}
return 0;
}
运行结果:
&a[0] = 00AFFEAC p+0 = 00AFFEAC
&a[1] = 00AFFEB0 p+1 = 00AFFEB0
&a[2] = 00AFFEB4 p+2 = 00AFFEB4
&a[3] = 00AFFEB8 p+3 = 00AFFEB8
&a[4] = 00AFFEBC p+4 = 00AFFEBC
&a[5] = 00AFFEC0 p+5 = 00AFFEC0
&a[6] = 00AFFEC4 p+6 = 00AFFEC4
&a[7] = 00AFFEC8 p+7 = 00AFFEC8
&a[8] = 00AFFECC p+8 = 00AFFECC
&a[9] = 00AFFED0 p+9 = 00AFFED0
? ? ? ? 代码声明了数组 arr 和指针 p ,指针 p 的初始值是 arr ,因为数组名 arr 会被解释为 &arr[0],所以存入 p 的值为 &arr[0] 的值,也就是指针 p 会被初始化为指向数组 arr 的起始元素 arr[0]。
? ? ? ? 由运行结果也可看出,指向个元素的指针 p+i 和 &arr[i] 是等价的。 &arr[i] 是指向元素 arr[i] 的指针,其值是?arr[i] 的地址。
指向数组元素的指针,有以下规则成立:
指针 p 指向数组中的元素 e 时
- p+i 为指向元素 e 后第 i 个元素的指针。
- p-i?为指向元素 e 前第 i 个元素的指针。
数组名在以下两种情况下不被视为指向起始元素的指针:
1.作为 sizeof 运算符的操作数出现时。
? ? ? ? sizeof(数组名) 不会生成指向起始元素的指针的长度,而是生成数组整体的长度。
2.作为取地址运算符 & 的操作数出现时。
? ? ? ? & 数组名 不是指向起始元素的指针的指针,而是指向数组整体的指针。
指向数组内部元素的指针 p+i 前加指针运算符 *?
? ? ? ? 因为 p+i 是指向 p 所指元素后第 i 个元素的指针,所以在其前加上指针运算符后得到的 *(p+i) 就是该元素的别名。若 p 指向 a[0] ,那么表达式 *(p+i) 就表示 a[i] 本身。
指针 p 指向数组中的元素 e 时,
- 指向元素 e 后第 i 个元素的 *(p+i),可以写成 p[i]。
- 指向元素 e 前第 i 个元素的 *(p-i),可以写成 p[-i]。
????????关于指针的运算可参考上篇博文C语言 指针-CSDN博客
代码示例:
#include <stdio.h>
int main()
{
int i = 0;
int arr[5] = { 1,2,3,4,5 };
int* p = arr;//arr是首元素地址
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
printf("arr[%d] = %d *(arr+%d) = %d p[%d] = %d *(p+%d) = %d\n", i, arr[i], i, *(arr + i), i, p[i], i, *(p + i));
}
for (i = 0; i < sz; i++)
{
printf("&arr[%d] = %p arr+%d = %p &p[%d] = %p p+%d = %p\n", i, &arr[i], i, (arr + i), i, &p[i], i, (p + i));
}
return 0;
}
运行结果:
arr[0] = 1 *(arr+0) = 1 p[0] = 1 *(p+0) = 1
arr[1] = 2 *(arr+1) = 2 p[1] = 2 *(p+1) = 2
arr[2] = 3 *(arr+2) = 3 p[2] = 3 *(p+2) = 3
arr[3] = 4 *(arr+3) = 4 p[3] = 4 *(p+3) = 4
arr[4] = 5 *(arr+4) = 5 p[4] = 5 *(p+4) = 5
&arr[0] = 004FFD38 arr+0 = 004FFD38 &p[0] = 004FFD38 p+0 = 004FFD38
&arr[1] = 004FFD3C arr+1 = 004FFD3C &p[1] = 004FFD3C p+1 = 004FFD3C
&arr[2] = 004FFD40 arr+2 = 004FFD40 &p[2] = 004FFD40 p+2 = 004FFD40
&arr[3] = 004FFD44 arr+3 = 004FFD44 &p[3] = 004FFD44 p+3 = 004FFD44
&arr[4] = 004FFD48 arr+4 = 004FFD48 &p[4] = 004FFD48 p+4 = 004FFD48
访问各元素的4个表达式:?arr[i] 、*(arr + i) 、 p[i] 、*(p + i) 。
指向各元素指针的4个表达式:?&arr[i] 、arr + i 、&p[i] 、p + i 。
总结:
? ? ? ? int* 型指针 p 指向 int 型数组 arr 的起始元素?arr[0] 时,指针 p 的行为就和数组 arr 本身一样。
????????这里的类型可以是 char 、double、int?等等。
????????数组传参传的是首元素地址。
数组名传参代码示例:
#include <stdio.h>
void text(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 0 };
text(arr, 10);
return 0;
}
运行结果:
0 0 0 0 0 0 0 0 0 0
指针传参代码示例:
#include <stdio.h>
void text(int* p, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
}
int main()
{
int arr[10] = { 0 };
text(arr, 10);
return 0;
}
运行结果:
0 0 0 0 0 0 0 0 0 0
? ? ? ? 上述两个代码等效。
????????指针变量也是变量,是变量就有地址,那指针变量的地址也可以存放在指针里。?就是二级指针。
代码示例:
#include <stdio.h>
int main()
{
int a = 0;
int* pa = &a;
int** ppa = &pa;
**ppa = 6;
printf("%d", a);
return 0;
}
运行结果:
6
pa是一个指针变量,一级指针变量。
ppa是一个二级指针变量。
对ppa解引用 *ppa ,找到 pa;再解引用 **ppa 才可以找到 a。
int* pa = &a;
pa前面的int表示 pa 指向的对象是int类型的,*说明 pa 是指针变量。
int** ppa = &pa;
int* 是说明 ppa 指向的对象是 int* 类型,后面的 * 是说明 ppa 是指针。
总结:
? ? ? ? 二级指针变量是用来存放一级指针变量的地址的。
? ? ? ? 存放指针的数组就是指针数组。
代码示例:
#include <stdio.h>
int main()
{
int arr[5] = { 0,1,2,3,4 };
int* parr[5] = { &arr[0],&arr[1], &arr[2], &arr[3], &arr[4] };
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", *(parr[i]));
}
return 0;
}
运行结果:
0 1 2 3 4
普通二维数组的使用代码示例:
#include <stdio.h>
int main()
{
int arr[3][4] = { 1,2,3,4,2,3,4,5,3,4,5,6 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
运行结果:
1 2 3 4
2 3 4 5
3 4 5 6
二维指针数组代码示例:
#include <stdio.h>
int main()
{
int arr1[4] = { 1,2,3,4 };
int arr2[4] = { 2,3,4,5 };
int arr3[4] = { 3,4,5,6 };
int* parr[3] = { arr1,arr2,arr3 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
运行结果:
1 2 3 4
2 3 4 5
3 4 5 6
? ? ? ? parr 指针数组指向3个数组 arr1、arr2、arr3 的数组首元素地址 arr1[0]、 arr2[0]、 arr3[0]。
parr 因为是指向 int 型数组的指针,所以 parr 类型为 int* 。
? ? ? ? 指针数组 parr 把三个独立的一维数组 arr1、arr2、arr3 串在一起管理。可以运行出上述普通二维数组的代码结果。
注:在 printf 函数打印数组时操作符 [ ] 就相当于解引用操作符 * ,arr[i] 等价于 *(arr+i) 。
????????以上就是今天要讲的内容,本文仅仅简单介绍了指针和数组、二级指针、指针数组的内容。