通过指针引用数组
数组元素的指针
-
数组指针:数组中的第一个元素的地址,也就是数组的首地址。
-
指针数组:用来存放数组元素地址的数组,称之为指针数组。
// 定义一个一般数组 int a[] = {1,4,9}; // 使用指针变量存储数组的第一个元素的首地址,也就是数组的首地址 int *p = &a[0];// 数组首地址 // 在C语言中,由于数组名代表数组的首地址,因此,数组名实际上也是指针。 int *p = a; // 意味着:int *p = &a[0] 完全等价于 int *p = a; printf("%d\n",*p); // 1
注意:虽然我们定义了一个指针变量接收了数组地址,但不能理解为指针变量指向了数组,而应该理
解为指向了数组的元素。
指针的运算
指针运算:指针变量必须要指向数组的某个元素。
序号 | 指针运算 | 序号 |
---|---|---|
1 | 自增:p++、++p、p=p+1|p+=1 | 让指针变量指向下一个元素 |
2 | 自减:p-- 、--p 、p-=1 | 让指针变量指向上一个元素 |
3 | 加一个数:p+1 | 下一个元素的(首)地址 |
4 | 减一个数:p- 1 | 上一个元素的(首)地址 |
5 | 指针相减:p1 - p2 | p1,p2之间相差几个元素 |
6 | 指针比较:p1 <p2 | 前面的指针小于后面的指针 |
案例1:
#include <stdio.h> int main() { // 一般数组 int a[] = {1,3,5,7,9}; // 计算数组中元素的个数 // sizeof用法:sizeof(运算数) 或者 sizeof 运算数 int len = sizeof a / sizeof a[0]; // 创建指针变量 int *p = a; // 创建循环变量 register int i = 0; // 遍历 for(;i < len; i++) { printf("[1] %d ",a[i]); // 下标法 printf("[2] %d ",*(a+i));// 指针法,但是这种写法,需要注意,a+i无法修改数组,只读 printf("[3] %d ",*(p+i));// 指针法,这种更为灵活,可读可写,建议这种写法 p++; // printf("%d\n",*p); // 等价于上面写法 // p++; } printf("\n"); return 0; }
案例2:
#include <stdio.h> int main() { int a[] = {10,22,33,44,55,66,77,88}; int *p = a;// 等价于 int *p = &a[0] 元素:10 p++;// 指针+1,元素值不改变 元素:22 printf("%d\n",*p);// p = p + 1 元素:22 int x = *p++;// x = 22,p++ -- *p:33 printf("%d,%d\n",x,*p);// *p++:先*p,在p++, 元素:22,33 int y = *(++p);// ++p, y = 44; printf("%d,%d\n",y,*p); // *(++p):先p++,再*p,元素:44,44 (*p)++;// 元素值+1,指针不改变 printf("%d\n",*p);// index为3的元素值:44 + 1 = 45 return 0; }
数组名做函数参数
表现形式:
-
形参和实参都用数组名
-
实参用数组名,形参用指针变量
-
实参形参都用指针变量
void fun(int *p1){} void main() { // 注意:如果实参和形参都是指针,我们的实参需要初始化 int arr[2] = {23,34}; int *p0 = arr; fun(p0); }
-
实参为指针变量,形参为数组名
案例1:
/** * 需求:将数组a中n个整数按相反顺序存放。 */ #include <stdio.h> /* 数组的反转:数组实现*/ void inv(int arr[],int len) { // 反转思路:将第0个和n-1个进行对掉,将第1个和n-2个对掉.. // 定义循环变量i,临时变量temp int i = 0,temp; // 遍历数组 for(;i < len/2;i++) { // 交换 temp = arr[i]; arr[i] = arr[len-1-i]; arr[len-1-i] = temp; } } /* 数组的反转:指针实现 关键字:const 给变量的数据类型前面添加const,代表这个变量是只读变量,无法对此作出修改 */ void inv2(int *arr,const int len) { // 反转思路:将第0个和n-1个进行对掉,将第1个和n-2个对掉.. // 定义循环变量i,临时变量temp *j = &arr[len -1] 等价于 arr + len -1 int *i = arr,*j = &arr[len-1],temp; // 遍历数组 for(;i < j;i++,j--) { // 交换 temp = *i; *i = *j; *j = temp; } } int main() { int array[10] = {12,23,45,55,66,77,88,26,34,32}; int len = sizeof(array)/sizeof(int); inv2(array,len); // 测试是否反转 for(int i = 0;i < len;i++) printf("%d,",array[i]); printf("\n"); return 0; }
数组指针
数组指针:指向一维数组的指针变量。
数组指针定义:假定该指针变量指向具有N个元素的一维数组,则数组指针变量定义如下:
数据类型 (*数组指针变量名)[N];
一维数组:
int a[N] = {1,2,3}; int (*p)[N] = &a;
二维数组:
int a[][N] = {1,3,5,7}; int (*p)[N] = a[0];// &a[0][0]
分析:
int arr[3] = {1,2,3}; int *p = arr;// &arr[0] 首地址:第1个元素的首地址 int (*p)[3] = &arr; // p = &arr[0]; int arr[][3] = {1,2,3,4,5,6}; int *p = arr[0]; // &arr[0][0] 首地址:第1行第1列元素的首地址 int (*p)[3] = &arr[0]; // p = &arr[0][0]
案例:
/** * 数组指针: 用指向元素的指针变量输出二维数组元素的值 */ #include <stdio.h> int main() { // 定义一个普通的二位数组 int a[3][4] = {1,3,5,7,9,11,13,15,17,19,21,23}; int *p = &a[0][0];// 二维数组 等价于 a[0] // 循环遍历 for(;p < a[0]+12;p++) { if((p - a[0]) % 4 == 0) { printf("\n"); } printf("%4d",*p); } printf("\n"); return 0; }
案例:
/** * 数组指针:输出二维数组任一行任一列元素的值。 此时:我们需要将二维数组看作是一个特殊的一维数组 */ #include <stdio.h> int main() { int a[3][4] = {1,3,5,7,9,11,13,15,17,19,21,23}; int (*p)[4]; // 我们把行使用指针表示 p = &a[0]; // 等价于 p = a int i,j;// 代表我们要显示的数据对应的行号和列号 printf("请输入行号和列号:\n"); scanf("i=%d,j=%d",&i,&j); printf("a[%d][%d]=%d\n",i,j,*(*(p+i)+j)); return 0; }
函数的传参
-
值传递:一般发生在函数形参的类型为char、short、int、long、float、double这样的类型,它的传递,一般是实参将自己的值复制一份给形参,也就是实参变量和形参变量的变量空间是分开的。此时形参无法改变实参的数据。
-
引用传递:一般发生在函数形参的类型为数组、指针这样的类型,它的传递,一般是实参将自己的内存首地址复制一份给形参,也就是实参变量和形参变量对应内存空间