一.字符指针
1.讲解
在指针的类型中我们知道有一种指针类型为字符指针 char* ;
其一般的使用场景为:这样
#include<stdio.h> int main() { char a = 'z'; char* pa = &a; return 0; }
还有这样:
int main() { char* arr = "hello"; printf("%s", arr); return 0; }1. int maiint main() { char* arr = "hello"; printf("%s", arr); return 0; }
针对char* arr = "hello";这个语句,特别容易让各位以为是把字符串 hello放到字符指针 arr 里了,但是本质是把字符串 hello首字符的地址放到了arr中
2.例题
下面来看一个例题加深理解:大家可以先思考一下再进行答案的比对
int main() { char str1[] = "hello"; char str2[] = "hello"; const char* str3 = "hello"; const char* str4 = "hello"; if (str1 == str2) printf("str1 and str2 are same\n"); else printf("str1 and str2 are not same\n"); if (str3 == str4) printf("str3 and str4 are same\n"); else printf("str3 and str4 are not same\n"); return 0; }
答案:
各位对了吗?
- 使用"=="运算符比较指针时,实际上比较的是指针所指向的地址是否相同,而不是比较字符串的内容是否相同
- 这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针。指向同一个字符串的时候,他们实际会指向同一块内存
- 用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4不同
二.指针数组
1.讲解
- 指针数组是一个数组,其中的每个元素都是指针。
- 它可以存储多个指针,每个指针可以指向不同类型的数据。
- 声明指针数组的语法为:type *ptr[size],其中type是指针指向的数据类型,size是数组的大小
示例:int num1 = 10, num2 = 20, num3 = 30;
int *ptr[3] = {&num1, &num2, &num3};
// 声明一个包含3个整型指针的数组
2.练习
用指针数组来模拟二维数组
int main() { int arr1[4] = { 1,2,4,5 }; int arr2[4] = { 2,2,5,5 }; int arr3[4] = { 1,1,4,4 }; int* pa[3] = { &arr1,&arr2,&arr3 }; for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { printf("%d ", pa[i][j]); } printf("\n"); } return 0; }
三.数组指针
1.数组指针的定义
- 数组指针是指向数组的指针变量。
- 它可以指向一个数组的首元素,也可以指向整个数组。
- 声明数组指针的语法为:type (*ptr)[size],其中type是数组元素的类型,size是数组的大小
示例:int arr[5] = {1, 2, 3, 4, 5};
int (*ptr)[5] = &arr; // 声明一个指向包含5个整数的数组的指针
2.数组指针与指针数组在语法上的对比
int *p1[10];
int (*p2)[10];
int (*p)[10];为数组指针
//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。
//这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合
int *p1[10];为指针数组
//解释:p先和[]结合,说明p是一个数组,然后数组的类型为int*
3.&数组名VS数组名
- &arr和arr,虽然值是一样的,但是意义应该不一样的
- &arr 表示的是数组的地址,而不是数组首元素的地址,数组的地址+1,跳过整个数组的大小
- 数组名是数组首元素的地址,但有两个例外:
1.sizeof(数组名),这里的数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小,单位是字节。
2.&数组名,这里的数组名表示整个数组,取出的是数组的地址
4.数组指针的使用
void print_arr(int(*arr)[5], int row, int col) { for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { printf("%d ", arr[i][j]); } printf("\n"); } } int main() { int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 }; //数组名arr,表示首元素的地址 //但是二维数组的首元素是二维数组的第一行 //所以这里传递的arr,其实相当于第一行的地址,是一维数组(有五个元素)的地址 //可以数组指针来接收 print_arr(arr, 3, 5); return 0; }
- int arr[5]; arr是一个能够存放5个整型数据的数组
- int *parr1[10]; parr1是一个数组,数组有10个元素,每个元素的类型是int*
- int (*parr2)[10]; parr2是一个指针,该指针是指向数值的,指向的数组有10个元素,每个元素的类型是intint (*parr2)[10]; parr2是一个指针,该指针是指向数值的,指向的数组有10个元素,每个元素的类型是int
- int (*parr3[10])[5]; parr3是一个数组,是存放数组指针的数组,这个数组有10个元素,存放的这个数组指针指向的数组有5个元素,每个元素是int类型。
理解:parr3[10]可知是一个数组,int (* )[5]是一个数组指针类型,所以总的看是一个存放数组指针类型的数组。
四.数组参数、指针参数
1.一维数组传参
- 数组传参,形参是可以写成数组形式
- 数组传参的本质是传递了数组首元素的地址,形参也可以是指针
void test(int arr[])//可以 数组传参,形参是可以写成数组形式的 {} void test(int arr[10])//可以 {} void test(int* arr)//可以 数组传参的本质是传递了数组首元素的地址,形参也可以是指针 {} void test2(int* arr[20])//可以 {} void test2(int** arr)//可以 传过来的是int* 的地址,就用int**来接收 {} int main() { int arr[10] = { 0 }; int* arr2[20] = { 0 }; test(arr); test2(arr2); }
2.二维数组传参
形参为二维数组或者数组指针
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。 //因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。 //这样才方便运算。 void test(int arr[3][5])//可以 {} void test(int arr[][])//不可以:只能省略行,不能省略列 {} void test(int arr[][5])//可以 {} void test(int* arr)//不可以 {} void test(int* arr[5])//不可以 {} void test(int(*arr)[5])//可以 {} void test(int** arr)//不可以 {} int main() { int arr[3][5] = { 0 }; test(arr); }
3.一级指针传参
形参的部分写成一级指针就行了
void print(int* p, int sz) //形参的部分写成一级指针就行了 { int i = 0; for (i = 0; i < sz; i++) { printf("%d\n", *(p + i)); } } int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9 }; int* pa = arr; int sz = sizeof(arr) / sizeof(arr[0]); //一级指针p,传给函数 print(pa, sz); return 0; }
4.二级指针传参
就用二级指针来接收
void test(int** ptr) { printf("num = %d\n", **ptr); } int main() { int n = 10; int* p = &n; int** pp = &p; test(pp);//传过来的是二级指针 test(&p); return 0; }
思考:当函数的参数为二级指针的时候,可以接收什么参数
只要是一级指针的地址就行:
int a=10;
int* p=&a;
int** pp=&p;
test(&p); test(pp);
int* arr[10]; 指针数组,首元素为一级指针,传过来首元素的地址
test(arr);
这次的内容梳理就先到这里了,我会加快更新后续内容的,感谢大家的支持!!!