前言
在步入正文前,我们先回顾一下指针的概念:
1.指针是个变量,用于存放地址,地址唯一标识一块内存空间。
2.指针大小为两种,固定的4/8个字节(32位平台/64位平台)
3.指针是有类型的,指针的类型决定了指针的±整数的步长,解引用操作的时候的权限
4.指针的运算
回顾结束,进入更深层次的指针
一、字符指针
先来介绍一个简单,字符指针-----char*,
常规使用:
int main()
{
char str='w';
char* p=&str; //在p存放的是str的地址
*p='w'; //利用地址直接修改str的值;
return 0;
}
另一种使用方法:
int main()
{
const char* p="abcdef";
printf("%s",p); //打印出abcdef;
return 0;
- 1
- 2
- 3
- 4
- 5
虽然可以打印出abcdef,但是不代表字符指针存放的是字符串abcdef;指针只能存放地址,而这里的本质是将字符串“abcdef”的首字符的地址存放在了p中。(注:const和指针的联系)
二、指针数组
int arr[10]; 存放整形的数组----整形数组
char arr[10]; 存放字符的数组-----字符数组
int* arr[10]; 存放指针的数组-----指针数组
指针数组存放的是指针;如:int* p[3]={&a,&b,&c};存在三个指针分别指向a,b,c的地址。
三、数组指针
1.数组指针的定义
数组指针是一个指向数组的指针,容易与指针数组弄混,区分小技巧(看最后2个字,如果是数组,则是数组,如果是指针则是指针)
int* p[10]; //指针数组
int(*p1)[10]; //数组指针
- 1
- 2
注:为什么要括号呢?因为[]的优先级高于* ,所以会先和[]结合,变成数组,存放指针的数组;而如果有了括号,则是指针指向了一个大小为10个整形的数组
2.数组名和&数组名的区别
众所周知:数组名表示数组的首元素地址,那么&数组是什么呢?和数组名有什么关系?我们现在举行一个例子。
注:sizeof(数组名)表示整个数组
int main()
{
int arr[10]={0};
printf("%p",arr); //打印地址
printf("%p",&arr); //打印地址
return 0;
}
废话不多说,先看运行结果:
事实证明:数组名和&数组名的地址是一样的,而且&是取地址符号,那么两个真的没区别嘛?不不不,让我们再看一段代码:
int main()
{
int arr[10]={0};
printf("arr=%p\n\n",arr); //打印地址
printf("&arr=%p\n\n",&arr); //打印地址
printf("arr+1=%p\n\n",arr+1); //打印地址
printf("&arr+1=%p\n",&arr+1);
return 0;
}
- 8
- 9
我们可以发现,虽然arr和&arr的地址相同,但是他们加1之后地址却不相同,所以他们的意义应该不一样。
分析:int代表4个字节,arr+1和arr相差4,但是&arr和&arr+1却相差40(数组有10个整形元素,每一个都是4个字节)。
解释:&arr代表的是数组的地址,而不是首元素的地址,所以当&arr+1则是跳过整个数组的大小,地址相差了40。
注:其实&arr的类型是:int(*)[10],是一种数组指针类型数组的地址。例如:int(*p)[3]={&arr,&arr1,&arr2}; 其中的arr1、arr、arr2都是数组。
3.数组指针的使用
数组指针是指针指向了数组,那么存放的是数组的地址。
代码使用:
int main()
{
int arr[5]={1,2,3,4,5};
int(*p)[10]=&arr;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
但是我们一般很少使用这种模式,一般数组指针都用于函数传参,如下:
void print_arr2(int(*arr)[5], int row, int col) {
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (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 };
print_arr1(arr, 3, 5);
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
//可以数组指针来接收
print_arr2(arr, 3, 5);
return 0;
}
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
数组指针一般用于二维数组的传参,而数组指针的数组大小取决于二维数组的列。
四、数组、指针参数
说到底,我们会发现指针和数组环环相扣,尤其涉及到函数传参时,但是面对不同的传参,函数应该如何接收呢?现在我们来详细讲解讲解。
1.一维数组传参
#include <stdio.h>
void test(int arr[])
{} //可以
void test(int arr[10])
{} //一和二是一样的道理,数组传参,数组接收,只不过没有规定数组大小
void test(int* arr)
{} //可以,传得地址,指针接收
void test2(int* arr[20])
{} //可以,数组传参,数组接收
void test2(int** arr)/
{} //传过来的是一个数组,元素类型是int*
//二级指针就是用来存放一级指针的地址,当然也是可以的
int main()
{
int arr[10] = { 0 };
int* arr2[20] = { 0 };
test(arr);
test2(arr2);
return 0;
}
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
数组传参中最简单的就是数组传参,数组接收。一维数组传参时,接收也可以是一级指针,但不能是二级指针,因为二级指针存放的是一级指针的地址。
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);
return 0;
}
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
二维数组传参时,数组接收时,行可以省略,列不能。
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* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
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); //pp和&p是相同的地址
return 0;
}
- 8
- 9
- 10
- 11
- 12
- 13
传参小结
当函数参数是一级指针,可接收:同类型的地址、同类型的指针、同类型的数组名
void test1(int* p)
{}
//test1函数能接收什么参数?
//int的类型的地址
//int类型的指针
//int 类型的数组名
void test2(char* p)
{}
//test2函数能接收什么参数?
- 8
- 9
- 10
当函数参数是二级指针,可接收:一级指针的地址、同类型的数组名、同类型的二级指针
void test(char** p) {
}
//一级指针的地址
//char*类型的数组名
//二级指针
int main()
{
char c = 'b';
char* pc = &c;
char** ppc = &pc;
char* arr[10];
test(&pc);
test(ppc);
return 0;
}
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
结束语
由于指针太深奥了,因此分为2部分写,下部是函数和指针的联系,不需要翻来覆去的,方便理解,若有不懂可在评论区留言,也可以私信我。
-----------小白tq
- 1