关于地址,指针,指针变量可以参考这篇文章:
地址,指针,指针变量是什么?他们的区别?符号(*)在不同位置的解释?_juechen333的博客-CSDN博客https://blog.csdn.net/qq_57342311/article/details/129225045关于指针变量作为函数参数可以参考这篇文章:
指针变量作为函数参数详解,形参和实参之间的值传递如何传递?如何改变指针变量所指向的变量?_juechen333的博客-CSDN博客https://blog.csdn.net/qq_57342311/article/details/129231880
目录
一、数组元素的指针
1.1引入
1.2实例
二、在引用数组元素时指针的运算
2.1引入
2.2实例
2.3详细说明
三、通过指针引用数组元素
3.1引入
3.2举例说明
3.3拓展
一、数组元素的指针
1.1引入
一个数组包含若干元素,每个数组元素都占用存储单元,所以他们都有相应的地址,所谓数组元素的指针就是数组元素的地址。
1.2实例
下面用指针变量指向一个数组元素
int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; //定义包含10个数据的整型数组
int* p; //定义1个整型指针变量
p = &a[0]; //将数组元素a[0]的地址赋值指针变量
以上是将指针变量 p 指向 a 数组的第 0 号元素。
引用数组元素可以使用下标法,也可以使用指针法,即通过指向数组元素的指针找到所需的元素,使用指针法能使目标程序质量高(占内存少,运行速度快)。
在 C 语言中,数组名(不包含形参数组名)代表数组中首元素(即序号为 0 的元素)的地址,所以下面两个语句等价
p = &a[0]; //p的值是a[0]的地址
p = a; //p的值是数组a首元素(即a[0])的地址
注意:数组名不代表整个数组,只代表数组首元素的地址。
二、在引用数组元素时指针的运算
2.1引入
可以对数值型数据进行算数运算,那么可以对指针型数据进行算数运算吗?指针就是地址,显然对地址进行乘和除是没有意义的,只有在一定条件下进行的加和减才有意义。
当指针指向数组元素的时候,能够对指针进行加和减运算;例如指针变量 p 指向数组元素 a[0],则 p+1表示指向下一个数组元素 a[1]。
2.2实例
在指针已指向一个数组元素时,可以对指针进行以下运算:
①加一个整数( p + i ),如 p += 1;
②减一个整数( p - i ),如 p -= 1;
③自加运算,如 p++
④自减运算,如 p--
⑤两个指针相减,如 p1 - p2 (只有p1和p2都指向同一个数组中的元素时才有意义)
2.3详细说明
(1)如果指针变量 p 已指向数组中的一个元素,则 p+1 指向同一数组中的下一个元素,p-1 指向同一数组中的上一个元素。执行 p+1 时并不是将 p 的值(地址)简单地加 1 ,而是加上一个数组元素所占用的字节数。例如,数组元素是 float 型,每个元素占4个字节,则 p+1 意味着使 p 的值(地址)加4个字节,以使它指向下一元素。p+1所代表的地址实际上是 p+1×d ,d 是一个数组元素所占的字节数(在Visual C++ 中,对 int 型,d=4;对 float 和 long 型,d=4;对 char 型,d=1 )。若 p 的值是2000,则 p+1的值不是2001,而是2004。
那么系统怎么知道要把这个 1 转换为 4,然后与 p 的值相加呢?因为在定义指针变量时必须要指定基类型,如:float* p。
(2)如果 p 的初值为 &a[0],则 p+i 和 a+i 就是数组元素 a[i] 的地址,或者说,它们指向 a 数组序号为 i 的元素。 a 代表数组首元素的地址,a+1 也是地址,它的计算方法同 p+1 ,实际地址为 a+1× d。例如,p+9 和 a+9 的值是 &a[9],它指向a[9]。
(3)*(p+i) 或 *(a+i) 是 p+i 或 a+i 所指向的数组元素,即 a[i],例如 *(p+5),*(a+5) 和 a[5] 三者等价,实际上,在编译时,对数组元素 a[i] 就是按 *(a+i) 处理的,即按数组首元素的地址加上相对位移量得到要找元素的地址,然后取出存储单元中的内容。
[ ]实际上是变址运算符,即将 a[i] 按 a+i 计算地址,然后找出此地址单元中的值。
(4)如果指针变量 p1 和 p2 都指向同一数组中的元素,如执行 p2 - p1,结果是 p2 - p1 的值(两个地址之差)除以该数组元素类型所占的字节长度。假设,p2 指向实型数组元素 a[5],p2 的值为2020;p1 指向 a[3],其值为2012,则 p2-p1 的结果是 (2020-2012)/4 = 2 。这个结果是有意义的,表示 p1 所指向的元素与 p2 所指的元素之间差 2 个元素。这样就不需要具体地知道p1和 p2的值,然后去计算它们的相对位置,而是直接用 p2-p1 就可知道它们所指元素的相对距离。
两个地址不能相加,如 p1+p2 是无实际意义的。
三、通过指针引用数组元素
3.1引入
引用数组元素,存在下面两种方法:
①下标法,如 a[i] ;
②指针法(数组名法和指针变量法),如 *(a+i) 或 *(p+i) ,其中 a 是数组名,p 是指向数组元素的指针变量,其初值为 p=a;
3.2举例说明
有一个整型数组 a,有10个元素,要求输出数组的全部元素
(1)下标法
#include<stdio.h>
int main()
{
int a[10] = { 1,3,5,7,9,2,4,6,8,10 };
for (int i = 0; i < 10; i++)
{
printf("%d ", a[i]); //通过下标表示
}
printf("\n");
return 0;
}
(2)通过数组名和元素序号计算数组元素的地址
#include<stdio.h>
int main()
{
int a[10] = { 1,3,5,7,9,2,4,6,8,10 };
for (int i = 0; i < 10; i++)
{
printf("%d ", *(a + i)); //通过数组名和元素序号计算
}
printf("\n");
return 0;
}
(3)用指针变量指向数组元素
#include<stdio.h>
int main()
{
int a[10] = { 1,3,5,7,9,2,4,6,8,10 };
int* p;
for (p = a; p < (a + 10); p++)
{
printf("%d ", *p); //用指针指向当前的数组元素
}
printf("\n");
return 0;
}
三种方法的比较:
①第(1)和第(2)种方法的执行效率是相同的,编译系统将 a[i] 转换为 *a[i+1] 处理的,第(3)种方法比前面两种更快,用指针直接指向元素,不必每次都重新计算地址,大大提高执行效率。
②用下标法比较直观,能直接知道是第几个元素;用地址法或指针变量的方法不直观,难以很快的判断出当前处理的是哪一个元素。
需要注意的是:不能通过改变数组名a的方式(例如:a++ )来改变所指向的变量,因为 a 代表的是数组首元素的地址,他是一个指针型常量,它的值是固定不变的。
3.3拓展
(1)指向数组元素的指针变量也可以带下标,如 p[i] ;因为程序在编译时,对下标的处理方法是转换为地址,p[i] 处理成 *(p+i) ,需要注意的是此时 p[i] 的指向,若 p 指向 a[0],则 p[2] 代表 a[2],若 p[i] 指向 a[3],则 p[2] 代表 a[5],建议少用,容易出错。
(2)利用指针引用数组元素,比较灵活方便,可以使用一些技巧使程序更加简洁。
① *p++ :由于++和 * 同优先级,结合方向为自右而左,因此它等价于 *(p++),即先引用p的值,实现 *p 的运算,然后再使 p 自加1。
#include<stdio.h>
int main()
{
int a[3] = { 2,5,8 };
int* p;
for (p = a; p < (a + 3);)
{
printf("%d ", *p++);
}
}
② *(p++) 和 *(++p) 的作用不相同,前者先取 *p 的值,然后再自加 1,后者先使 p+1,再取 *p 的值。
#include<stdio.h>
int main()
{
int a[3] = { 2,5,8 };
int b[3] = { 2,5,8 };
int* p, * q;
for (p = a; p < (a + 3); )
{
printf("%d ", *(p++));
}
printf("\n");
for (q = b; q < (b + 3); )
{
printf("%d ", *(++q));
}
}
后着因为没有定义数组 b 的第 4 个元素 b[4],所以指向了一个不确定的位置。
③ (*p)++ 和 ++(*p) 作用不相同,但都是先得到 (*p) 所指向元素的值,前者先把 (*p) 所指向的元素值作为表达式的值后,再自加 1;后着是自加 1 后再作为表达式的值。但需要注意的是:他们都是使 p 所指向的元素加 1 ,而不是使指针 p 的值加 1 。
#include<stdio.h>
int main()
{
int a[3] = { 2,5,8 };
int b[3] = { 2,5,8 };
int* p, * q;
for (p = a; p < (a + 3); p++)
{
printf("%d", (*p)++);
}
printf("\n");
for (q = b; q < (b + 3); q++)
{
printf("%d", ++(*q));
}
}