C语言变量指针、指针变量、数组指针、指针数组
变量指针与指针变量
指针变量指向数组
通过指针引用数组元素
引用一个数组元素,可以用:
①下标法:a[i]
②指针发:*(a+i)、 *(p+i)其中a数组名,p是指向数组元素的指针变量,其初值:p = a
案例:
需求有一整型数组a,有十个元素。输出数组中全部元素。
分析:要输出各元素的值,有三种方法
- 下标法:通过改变下标输出所有元素
#include <stdio.h>
void main()
{
int arr[10];
//初始化数组
for(int i = 0;i < 10;i++)
scanf("%d",&arr[i]);
//遍历元素
for(int j = 0;j < 10;j++)
printf("%-4d",a[j]);
printf("\n");
}
- 指针法(地址法):通过数组名计算数组元素地址,找出数组元素
#include <stdio.h>
void main()
{
int arr[10];
//初始化数组
for(int i = 0;i < 10;i++)
scanf("%d",&arr[i]);
//遍历元素
for(int j = 0;j < 10;j++)
printf("%-4d",*(a+j));
printf("\n");
}
- 指针法(指针变量):用指针变量指向数组元素
#include <stdio.h>
void main()
{
int arr[10];
int *p=a;
//初始化数组
for(int i = 0;i < 10;i++)
scanf("%d",&arr[i]);
//遍历元素
for(;p < (a + 10);p++)
printf("%-4d",*p);
printf("\n");
}
以上三种写法比较:
- 第一种写法和第二种写法执行效率相同,系统是将a[i]转换成*(a+i)处理,即先计算处地址,因此比较费时。
- 第三种比第一二中方法快,用指针变量直接指向数组元素,不必每次重新计算地址。(p++)可以大大提高执行效率
- 第一张写法比较直观而已地址法或指针变量方法难以很快判断出当前处理元素。
使用指针变量指向数组元素时(第三种写法),注意以下三点:
*(p--)相当于a[i--],先*p,再 p--
*(++p)相当于a[++i],先++p,再*
*(--p)相当于a[--i],先--p,再*
数组名作函数参数
表现形式:
-
形参和实参都是数组名
void fun (int arr[],int len){...} void main() { int arr[] = {1,2,3}; fun(arr,sizeof(arr)/sizeof(arr[0])) }
-
实参用数组名,形参用指针变量
void fun (int *p,int len){...} void main() { int arr[] = {1,2,3}; fun(arr,sizeof(arr)/sizeof(arr[0])) }
-
实参形参都用指针变量
void fun (int *p,int len){...} void main() { int arr[] = {1,2,3}; int *p = arr; fun(p,sizeof(arr)/sizeof(arr[0])) }
-
实参为指针变量,形参为数组名
void fun (int arr[],int len){...} void main() { int arr[] = {1,2,3}; int *p = arr; fun(p,sizeof(arr)/sizeof(arr[0])) }
案例
需求:将数组a中n个整数按相反顺序存放
#include <stdio.h>
/*
数组的反转
*/
void inv(int arr[], int len)
{
int temp;
// 反转思路:将第0个和n-1个进行对调
for (int i = 0; i < len / 2; i++)
{
temp = arr[i];
arr[i] = arr[len - i - 1];
arr[len - i - 1] = temp;
}
}
void getarr(const int arr[], int len)
{
for (int i = 0; i < len; i++)
{
printf("%-3d", arr[i]);
}
printf("\n");
}
/*
数组的反转:指针实现
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;
}
}
int main()
{
int arr[] = {1, 2, 3, 4, 5};
getarr(arr, sizeof(arr) / sizeof(arr[0]));
inv2(arr, sizeof(arr) / sizeof(arr[0]));
getarr(arr, sizeof(arr) / sizeof(arr[0]));
return 0;
}
数组指针与指针数组
数组指针
概念:数组指针是指向数组的指针,本质上还是指针
特点:
- 先有数组,后有指针
- 它指向的是一个完整的数组
一维数组指针:
数据类型 (*指针变量名)[容量];
案例:
#include <stdio.h>
/*
数组指针:指向数组的指针(并不是指向数组元素的指针)
*/
int main()
{
// 一维数组指针
// 现有数组,再有指针
int arr[] = {11, 22, 33, 44, 55, 66, 77, 88, 99};
int len = sizeof(arr) / sizeof(arr[0]);
// int *p = arr; // 指向数组的第一个元素 p++(指针变量)
int(*p)[9] = &arr; // 此时p不是指向arr数组第一个元素,而是指向arr数组本身
printf("%p\n", p);
//p++;此时p++会跳出整个数组,访问到一块未知的内存程序中尽量避免
//如何访问数组指针
printf("%d\n",(*p)[0]);//(*p)注意括号
//遍历
for (int i = 0; i < len; i++)
{
printf("%-3d",(*p)[i]);
}
return 0;
}
指向数组元素的指针,本质上还是指针变量;现在指向数组的指针,叫做数组指针。
二维数组指针:
数据类型 (*指针变量名)[行容量][列容量];
案例:
写法一:
#include <stdio.h>
int main()
{
int arr[][2] = {10, 20, 100, 200};
// 创建二维数组指针
int(*p)[2][2] = &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("%-5d",(*p)[i][j]);
}
printf("\n");
}
return 0;
}
写法二:
#include <stdio.h>
int main()
{
int arr[][2] = {10, 20, 100, 200};
// 创建二维数组指针
int(*p)[2][2] = &arr;
int(*q)[2] = arr;
// 遍历
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,%-4d,%-4d", *(*(q + i) + j), *(q[i] + j), q[i][j]);
}
printf("\n");
}
return 0;
}
- 指针和数组中符号优先级:() > [ ] > *
- 通过指针引用多维数组
案例
需求:用指向元素的指针变量输出二维数组元素的值
#include <stdio.h>
int main()
{
int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int *p = a[0]; // 或者&arr[0][0]
printf("%d", *a[0]); //a[0]中的a是行[]是列
// 循环遍历
for (; p < a[0] + 9; p++)
{
if ((p - a[0]) % 3 == 0)
{
printf("\n");
}
printf("%-4d",*p);
}
printf("\n");
return 0;
}
案例
需求:数组指针输出二维数组任意行任意列元素的值
#include <stdio.h>
int main()
{
int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int(*p)[4] = a; // 或者&arr[0]数组指针[]写列的大小
//创建两个行列对应行于列
int row,col;
printf("请输入行号列号:\n");
scanf("%d%d",&row,&col);
printf("arr[%d][%d]=%d\n",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;
}
建议:指针数组处理字符串