数组指针,指针数组
#include<stdio.h> int main() { int a = 100; int *p1 = &a; // 整型指针 char ch = 'A'; char *p2 = &ch; // 字符型指针 int arr[5] = {1, 3, 5, 7, 9}; int *p3 = arr; // 整型指针,指向整型1 int (*p4)[5] = &arr; // arr整个数组的地址 // 数组指针 int *p5[5]; printf("size: %ld\n", sizeof(p5)); // 5*8=40字节 char *str1 = "hello"; printf("str1: %s\n", str1); // 字符串数组 char *str[5] = {"hello", "world", "nihao", "hahaha", "xixixi"}; printf("str[0]: %s\n", str[0]); printf("str[1]: %s\n", str[1]); printf("str[2]: %s\n", str[2]); printf("str[3]: %s\n", str[3]); printf("str[4]: %s\n", str[4]); return 0; }
函数指针,指针函数
#include<stdio.h> // 计算和(函数的声明) int func_sum(int a, int b); int *func_1(int a); int main() { // 函数调用原理:根据<函数入口地址>去执行对应函数。 int c1 = func_sum(100, 200); printf("c1: %d\n", c1); // 函数类型:返回值 + 形参列表(函数头) // 函数名就是函数的入口地址。 int (*p1)(int, int) = func_sum; int c2 = p1(300, 400); printf("c2: %d\n", c2); // 假设已知某个函数的入口地址为 0x000000FF // (一般用于硬件代码中,因为软件程序中函数的地址都是随机分配的。) // int (*p2)(int, int) = 0x000000FF; // int c3 = 0x000000FF(300, 400); // 直接调用入口地址为 0x000000FF的函数 // printf("c3: %d\n", c3); int *p2 = func_1(100); printf("p2: %p\n", p2); return 0; } int *func_1(int a) { int *p1 = &a; printf("p1: %p\n", p1); return p1; } // 计算和(函数的定义) int func_sum(int a, int b) { return a+b; }
函数的传递
#include<stdio.h> // 值传递(只是将数值100, 200传参) void func_swap1(int a, int b); // 地址传递(将数值本身的地址传递过去) void func_swap2(int *a, int *b); int main() { int n1=100, n2=200; printf("n1:%d n2:%d\n", n1, n2); // func_swap1(n1, n2); // 值传递,不能修改变量本身 func_swap2(&n1, &n2); printf("n1:%d n2:%d\n", n1, n2); return 0; } // 地址传递(将数值本身的地址传递过去) // int *a = &n1; // int *b = &n2; void func_swap2(int *a, int *b) { int c; c = *a; *a = *b; *b = c; printf("func_swap: a:%d b:%d\n", *a, *b); } // 值传递(只是将数值100, 200传参) // int a = n1; // int b = n2; void func_swap1(int a, int b) { int c; c = a; a = b; b = c; printf("func_swap: a:%d b:%d\n", a, b); }
1.地址偏移量概念
指针算术运算,可以跟数组形式相互转换。
*(p+i) <==> p[i]
备注:
数组名不能作为等号的左值。
int a[5]; printf("%d ", *(a++)); printf("%d ", *(a=a+1));
- []的优先级是高于解引用*
- 对数组地址进行解引用,会得到数组的首元素地址。
- 数组首元素地址和数组本身地址:
int a[5] = {1, 3, 5, 7, 9}; printf("a : %p\n", a); // 数组首元素地址 printf("&a : %p\n", &a); // 数组本身地址 // 上述两个地址在数值上是一样的,但是类型不相同。 printf("a+1 : %p\n", a+1); // 向右偏移4字节(类型:int *) printf("&a+1: %p\n", &a+1); // 向右偏移20字节(类型:int (*)[5])
2.数组指针、指针数组、函数指针、指针函数
- 数组指针:指向数组的指针。(也称为行指针,指向二维数组一行数据)
int (*p4)[5]; // 该指向指向 int [5]类型的数组
作用:一般用于二维数组访问。
- 指针数组:存储着一系列的相同类型指针的数组。
int *p4[5]; // 该数组存储着5个指针(类型为 int *)
(数组三要素:连续内存+具体长度+相同类型)
作用:存储多个值,指向多个数据
- 函数指针:指向函数类型的指针。
int (*p1)(int, int) = func_sum; // 该指针指向函数 func_sum
作用:直接通过指针调用函数。(如回调函数)
- 指针函数:返回值为指针的函数(返回地址)
int *func_1(int a) // 返回值为int *
如果返回值为 void *,表示返回无值型指针(任意类型指针)。
循环遍历二维数组
#include<stdio.h> // *(p+i) <==> p[i] int main() { // int arr[2][3] = {1, 3, 5, 2, 4, 6}; int arr[2][3] = {{1, 3, 5}, {2, 4, 6}}; //更为规范的写法 // int *p1 等同于 int (*p1) // int *p1 = arr; // 错误写法。类型不匹配。 // int * = int (*)[3] // 整型指针 = 数组指针 int *p2 = &arr[0][0]; // 类型匹配 // int * = int * // 整型指针 = 整型指针 int (*p3)[3] = arr; // 类型匹配 // int (*)[3] = int (*)[3] // 数组指针 = 数组指针 // 1.通过数组名访问 int i, j; for(j=0; j<2; j++) { for(i=0; i<3; i++) printf("%d ", arr[j][i]); // printf("%d ", *(*(arr+j)+i)); // printf("%d ", *(arr[j]+i)); // printf("%d ", (*(arr+j))[i]); // 上述四种写法效果一模一样。 // printf("%d ", *(arr+j)[i]); // 错误写法。因为[]优先级高于解引用* printf("\n"); } // 2.通过整型指针访问 printf("==============================\n"); for(i=0; i<2*3; i++) // printf("%d ", *p2++); // printf("%d ", *(p2+i)); printf("%d ", p2[i]); printf("\n"); // 3.通过数组指针访问 printf("==============================\n"); for(j=0; j<2; j++) { for(i=0; i<3; i++) // printf("%d ", p3[j][i]); // arr[j][i] printf("%d ", *(*(p3+j)+i)); // printf("%d ", *(p3[j]+i)); // printf("%d ", (*(p3+j))[i]); // 上述四种写法效果一模一样。 printf("\n"); } return 0; }
循环遍历一维数组
#include<stdio.h> int main() { int a[5] = {1, 3, 5, 7, 9}; // int *p1 = &a[0]; // 定义指针,指向首元素a[0] int *p1 = a; // 数组名就是首元素地址 // int * = int * 类型匹配! printf("1: %p\n", p1); for(int i=0; i<5; i++) // 0 1 2 3 4 { // 写法1.1:指针本身进行偏移 // printf("%d ", *p1); // 对指针进行解引用 // p1++; //p1 = p1+1; //p1+=1; // 写法1.2 // printf("%d ", *p1++); // ++优先级更高,但是它作为后缀,必须在运算结束后再自加 // printf("%d ", *(p1++)); // 等同于上一行 // printf("%d ", (*p1)++); // 错误写法。解引用后都是获得数据1。 // 写法2:指针进行运算 // printf("%d ", *p1+i); // 错误写法。解引用*的优先级高于+ // printf("%d ", *(p1+i)); // 正确写法。 // printf("%d ", *(i+p1)); // 正确写法。 // 写法3:指针运算(数组形式,地址偏移量) // printf("%d ", p1[i]); // printf("%d ", i[p1]); // printf("%d ", a[i]); // printf("%d ", i[a]); // printf("%d ", *(a+i)); // printf("%d ", *(i+a)); // printf("%d ", *(a++)); //错误写法:数组名不能自增自减。*(a=a+1) } printf("\n"); int arr[2][3] = {1, 3, 5, 2, 4, 6}; printf("2: %p\n", p1); return 0; }