C语言:指针(第二天)
变量指针与指针变量
指针变量指向数组
通过指针引用数组元素
引用一个数组元素,可以用:
① 下标法:如a[i]形式。
② 指针法:如*(a+i)
或者*(p+i)
。其中a是数组名,p是指向数组元素的指针变量,其初值:p = a;
案例
需求:有一整型数数组a,有10个元素。输出数组中的全部元素。
分析:要输出个元素的值,有三种方法。
-
下标法:通过改变下标输出所有元素
#include <stdio.h> void main() { int arr[10]; int i; // 给数组元素赋值 for(i = 0;i < 10;i++) { scanf("%d",&arr[i]); } // 遍历数组元素 for(i = 0;i < 10;i++) { printf("%-4d",arr[i]); } printf("\n"); }
-
指针法:通过数组名计算出数组元素的地址,找出数组元素值
#include <stdio.h> void main() { int arr[10]; int i; // 给数组元素赋值 for(i = 0;i < 10;i++) { scanf("%d",&arr[i]); } // 遍历数组元素 for(i = 0;i < 10;i++) { printf("%-4d",*(arr+i)); } printf("\n"); }
-
指针法:用指针变量指向数组元素
#include <stdio.h> void main() { int arr[10]; int *p,i; // 给数组元素赋值 for(i = 0;i < 10;i++) { scanf("%d",&arr[i]); } // 遍历数组元素 for(p = arr;p < (arr+10);p++) { printf("%-4d",*p); } printf("\n"); }
以上3种写法:
- 第一种写法和第二种写法执行效率相同。系统是将arr[i]转换为*(arr+i)处理的,即先计算出地址,因此比较费时。
- 第三种写法比第一和第二种方法块,用指针变量直接指向数组元素,不必每次都重新计算地址。(p++)能大大提高执行效率。
- 用第一种写法比较直观,而用地址或指针变量的方法难以很快判断出当前处理的元素。
使用指针变量指向数组元素时,(上面第三种写法),注意一下三点:
①
(p--)相当于arr[i--],先*p,再p--
②
*(++p)相当于arr[++i],先++p,再*
③
*(--p)相当于arr[--i],先--i,再*
数组名作函数参数
表现形式:
-
形参和实参都是数组名
void fun(int arr[],int len){...} void main() { int arr[] = {11,22,33}; fun(arr,sizeof(arr)/sizeof(arr[0])); }
-
实参用数组名,形参用指针变量
void fun(int *p,int len){...} void main() { int arr[] = {11,22,33}; fun(arr,sizeof(arr)/sizeof(arr[0])); }
-
实参形参都用指针变量
void fun(int *p,int len){...} void main() { int arr[] = {11,22,33}; int *p = arr; fun(p,sizeof(arr)/sizeof(arr[0])); }
-
实参为指针变量,形参为数组名
void fun(int arr[],int len){...} void main() { int arr[] = {11,22,33}; int *p = arr; fun(p,sizeof(arr)/sizeof(arr[0])); }
案例
需求:将数组a中n个整数按相反顺序存放(数组中的元素反转)
#include <stdio.h>
void inv(int arr[],int len)
{
// 反转思路:将第0和n-1个进行对调,将第1个和n-2个对调
// 定义循环变量
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 *p,const int len)
{
// 定义循环变量
int *i = p,*j = &p[len-1],temp;
// 遍历数组
for(;i<j;i++,j--)
{
// 反转数组
temp = *i;// 这里的*是解引用
*i = *j;
*j = temp;
}
}
// 遍历数组
void get(int arr[],int len)
{
for(int i=0;i<len;i++)
{
printf("%-3d",arr[i]);
}
printf("\n");
}
int main(int argc,char *argv)
{
int arr[] = {11,22,33,44,55};
get(arr,sizeof(arr)/sizeof(arr[0]));
inv2(arr,sizeof(arr)/sizeof(arr[0]));
get(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
数组指针与指针数组
数组指针
概念:数组指针是指向数组的指针,本质上还是指针
特点:
-
先有数组,后有指针
-
它指向的是一个完整的数组
-
一维数组指针:
-
语法:
数据类型(*指针变量名)[容量];
-
案例:
/** * 数组指针:指向数组的指针(这里不是指向数组元素的指针) */ #include <stdio.h> int main(int argc,char *argv) { // 一维数组指针 // 先有数组,再有指针 int arr[] = {100,200,300}; // 获取数组的元素个数 int len = sizeof(arr) / sizeof(arr[0]); // 定义一个数组指针,指向arr[]这个数组 // int *p = arr;实际上指向了数组的第一个元素 int(*p)[3] = &arr;// &arr[0] 等价于 arr;此时p不是指向arr数组的第一个元素,而是指向arr这个数组本身 printf("%p\n",p); // p++;此时会跳出整个数组 // printf("%p\n",p); // 如何访问数组指针 printf("%d\n",(*p)[2]);// 此时就拿到了数组中的第三个元素300 // 遍历 for(int i = 0;i < len;i++) { printf("%d\n",(*p)[i]); } printf("\n"); return 0; }
我们之前所学的是指向数组元素的指针,本质山还是指针变量;现在学的是指向数组的指针,叫做数组指针。
-
-
二维数组指针:
-
语法:
数据类型(*指针变量名)[行][列];
-
案例:
写法1:
#include <stdio.h> int main(int argc,char *argv[]) { // 创建一个普通的二维数组 int arr[][3] = {10,20,30,100,200,300,1000,2000,3000}; // 创建一个二维数组指针 // 一个二维数组本质上还是一个一维数组,只不过它的元素也是数组 int (*p)[3][3] = &arr; printf("%d\n",(*p)[1][0]); // 遍历 for(int i = 0;i < sizeof(arr)/sizeof(arr[0]);i++) { int len = sizeof(arr[i])/sizeof(int); for(int j = 0;j < len;j++) { printf("%-4d",(*p)[i][j]); } printf("\n"); } return 0; }
写法2:
#include <stdio.h> int main(int argc, char *argv[]) { // 创建一个普通的二维数组 int arr[][3] = {10, 20, 30, 100, 200, 300, 1000, 2000, 3000}; // 创建一个二维数组指针 // 一个二维数组本质上还是一个一维数组,只不过它的元素也是数组 int(*p)[3] = arr; // 取二维数组的第一个元素 {10,20,30} 数组名本身就代表数组首元素(地址) printf("%d\n", (*p)[0]); // 10 // 获取元素2000 printf("2000-%d,%d,%d",*(*(p+2)+1),*(p[2]+1),p[2][1];// *(*(p+1)+2) 300 return 0; }
-
-
-
指针和数组中符号优先级:
() > [] > *
-
通过指针引用多维数组
案例1
需求:用指向元素的指针变量输出二维数组元素的值
#include <stdio.h>
int main(int argc,char *argc[])
{
// 定义一个普通的二维数组
int a[3][4] = {1,3,5,7,9,11,13,15,17,19,21,23};
// 定义一个指针变量,用来接收二维数组的元素值
int *p = a[0];// a[0][0]
// 循环遍历
for(;p < a[0]+12;p++);
{
// 每4个换行
if((p-a[0]) % 4 == 0)
{
printf("\n");
}
printf("%-4d",p);
}
printf("\n");
return 0;
}
案例2
需求:数组指针-输出二维数组任一行任一列元素的值
/**
*
*/
#include <stdio.h>
int main()
{
// 定义一个二维数组
int a[3][4] = {1,3,5,7,9,11,13,15,17,19,21,23};
// 创建一个一维的数组指针指向一个二维的数组
int (*p)[4] = arr;// 等价于&arr[0]
// 创建两个变量,代表我们对应数据的行和列
int row,col;
// 通过控制台输入
printf("请输入行号和列号:\n");
scanf("%d,%d",&row,&col);
printf("arr[%d][%d]=%d\n",row,col,*(*p+row)+col);// *(*p+row)+col | *(p[row]+col) | p[row][col]
return 0;
}
指针数组
概念:指针数组是一个数组,数组中的每一个元素都是一个指针。
特点:
- 先有指针,后有数组
- 指针数组的本质是一个数组,只是数组中的元素类型为指针
语法:
数据类型 *数组名[容量];
案例:
#include <stdio.h>
int main()
{
// 定义三个变量
int a = 10,b = 20,c = 30;
// 定义指针数组,指针数组是用来存放指针的
int *arr[3] = {&a,&b,&c};
// 获取元素大小
int len = sizeof arr / sizeof arr[0];
// 遍历数组
for(int i = 0;i < len;i++)
{
printf("%-3d",*arr[i]);
}
printf("\n");
return 0;
}
建议:我们一般使用指针数组处理字符串