指针+1/指针-1:把内存地址往后或者往前移动一个步长,步长和数据类型有关
二级指针定义:
int a=10;
int b=20;
int* p=&a; //一级
int **p=&p; //二级
数组指针:
一维数组:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>void swap(void* p1, void* p2, int len);
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9,10 };
int len;len = sizeof(a) / sizeof(int);
int* p = &a[0];for (int i = 0; i < len; i++)
{
printf("%d\n", *p++);//printf("%d\n", *p1); p1++;
}/*循环解释:
printf("%d\n", *p1) //结果:1
printf("%d\n", *(p1+1)) //结果:2
printf("%d\n", *p1+1) //结果:2 ,仅是在1的基础上加1,而不是向下遍历
*/
}
二维数组:
情况一:分开定义
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>int main()
{
int arr1[5] = { 1,2,3,4,5 };
int arr2[5] = { 11,22,33,44,55 };
int arr3[5] = { 111,222,333,444,555 };int* arr[3] = {arr1 ,arr2,arr3};
int** p = arr;//第一个*表示存放的是内存地址,第二个*表示指针的标志
/*
arr:表示数组首元素的地址(即 &arr[0]),类型是 int**(指向第一个 int* 元素的指针)。
&arr:表示整个数组的地址,类型是 int*(*)[3](指向 “包含 3 个 int * 元素的数组” 的指针),与 p 的类型(int**)不匹配。*/
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", *(*p+j));
}
printf("\n");
p++;
}
}
情况二:合并定义
方法一:
int main() {
int arr[3][3] = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
int sum = 0;
int i;
int *p = &arr[0][0]; // 将二维数组转换为指向首元素的指针(int*类型)
for (i = 0; i < 3; i++) {
sum += *(p + i * 3 + i); // 指针访问主对角线元素:第i行的对角线元素位置是 i*3 + i
}
printf("3×3数组主对角线元素的和为:%d\n", sum); // 结果为1+5+9=15
return 0;
}
方法二:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>int main()
{
int arr[3][5] =
{
{1,2,3,4,5},
{11,22,33,44,55},
{111,222,333,444,555}
};int (*p)[5] = arr; //原型:int[5] *p=arr
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", *(*p+j));
}
printf("\n");
p++;
}
}
两种定义方法得到的结果相同,但意义不同:
int *p = &arr[0][0];
int * 是 “指向单个 int 元素的指针”,&arr[0][0] 是二维数组首元素的地址
(即 arr[0][0] 这个具体元素的地址)
int (*p)[5] = arr;
int (*)[5] 是 “指向包含 5 个 int 元素的数组的指针”,也称 “行指针”。
arr 是二维数组名,在 C 语言中会隐式转换为指向首行的指针
(即指向 arr[0] 这一行的指针,arr[0] 是包含 5 个元素的一维数组)。
行指针(int (*)[n])指向一整行数组,适配二维数组的 “行 - 列” 逻辑;
元素指针(int *)指向单个元素,适配二维数组在内存中连续存储的特性。
情况三:每组数量不同的数组定义
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>int main()
{
int arr1[3]={1,2,3};
int arr2[6]={1,2,3,4,5,6};
int arr3[9]={1,2,3,4,5,6,7,8,9};int len1 = sizeof(arr1) / sizeof(int);
int len2 = sizeof(arr2) / sizeof(int);
int len3 = sizeof(arr3) / sizeof(int);int len[3] = { len1,len2,len3 }; //
int* arr[3] = { arr1,arr2,arr3 }; //存的是一维数组的内存地址,因此用int*
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < len[i]; j++)
{
printf("%d\t", arr[i][j]);
}
printf("\n");
}
}
函数指针:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>void method1();
int method2(int a, int b);
int main()
{
void(*p1)()= method1; //定义函数指针
int(*p2)(int a, int b) = method2;/*定义的方法:
1.复制函数,如void method1(),int method2(int a, int b);
2.将函数名替换成指针(*p),得到:
void (*p)()=函数名method1,int ()(int a, int b)=method2;*/
/*调用第一个函数*/
p1();//输出“模式1”printf("\n");
/*调用第二个函数*/
int x=p2(1, 2); //定义一个数去接收返回值
printf("%d\n", x); //输出返回值
return 0;
}void method1()
{
printf("模式1");
}int method2(int a, int b)
{
return a + b;
}
总结:
一维数组的情况:何时加 & ?
1.当用指针指向一维数组的首元素时:
int arr[5] = {1,2,3,4,5};
int* p = arr; // 正确(arr 是首元素地址,无需 &)
等价于 int* p = &arr[0]; // 也正确(&arr[0] 显式取首元素地址)
2.当用指针指向整个一维数组时(数组指针):
int (*p)[5] = &arr; // 必须加 &,因为 &arr 是整个数组的地址(类型为 int(*)[5])
二维数组的情况:何时加 & ?
1.当用行指针指向二维数组时:
int arr[3][5];
int (*p)[5] = arr; // 正确(arr 代表首行地址,无需 &)
2.当用元素指针指向二维数组的首元素时:
int* p = &arr[0][0]; // 必须加 &,因为 arr[0][0] 是普通元素(不是地址)