0
点赞
收藏
分享

微信扫一扫

指针(详解)

乐百川 2022-03-12 阅读 70

1.指针就是一个变量(指的是指针变量),指针是用来存放地址的,地址唯一标识一块内存空间。(也就是说,内存会划分为小的内存单元,每个内存单元都有一个编号,这个编号就被称为地址,也把地址叫做指针)。

2.指针的大小是固定的,在32位系统下是4个字节,在64位系统下是8个字节。

3.指针是有类型的,指针的类型决定了指针的+-整数的步长(+1或者-1会跳过几个字节),指针解引用操作的时候的权限。

一、字符指针

指针类型有一种类型为char*(字符指针)

一般情况下,我们将一个字符的地址存放在一个字符指针变量中

int main()
{
    char ch = 'a';
    char* pc = &ch;
    *pc = 'a';
    return 0;
}

pc就是一个指针变量,里面存放的是ch的地址,当我们对指针变量pc进行解引用,就可以的到我们的字符'a';

 

这个我们很容易理解,但是我们还有一种常用的写法,

#include<stdio.h>
int main()
{
    const char* str = "hello";
    printf("%s\n",str);
    return 0;
}

在这里,我们就会想到,这是将一个字符串放在str的指针变量里了吗?

在这里,我们并不是将一整个字符串放在str的指针变量中了,而是将字符串的首字符的地址存放在了str中,当我们去向后访问时,访问到\n就访问结束。

#include<stdio.h>
int main()
{
	char str1[] = "hello bit";
	char str2[] = "hello bit";
	const char* str3 = "hello bit";
	const char* str4 = "hello bit";
	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;
}

 这里的运行结果应该是什么呢?

str1 str2是在内存中内存中开辟了两个空间,分别用来存储字符串str1 和 str2,因此str1!=str2。在str3 与 str4比较时,这里就需要注意了,这里是将hello bit这个字符串的地址分别存放在str3 和 str4中,因此这里str4 和 str3 是相同的。

二、指针数组

我们了解到数组,数组是一个存放相同类型元素的集合,我们之前学习到有

int* arr1[10];//整型指针数组
char* arr2[10];//字符指针数组
char* * arr3[10];//二级字符指针数组

指针数组,是一个用来存放指针的数组。

三、数组指针

1.数组指针的定义

当我们看到数组指针时,数组指针是数组还是指针?他应该是指针,也就是一个数组的地址,

int* p1[10];

int(*p2)[10];

在这里p1和p2分别是指的什么?

p1指的是一个整型指针数组,p1是一个数组,里面存放了10个int*类型的元素;

p2是一个指针,在这里表示p2是一个指针变量,P2指向的是一个大小为10的一个整型数组,p2因为指向一个数组,也是一个数组指针。

2.&数组名和数组名

在之前我们了解到,数组名是数组首元素地址,但是有两个情况例外,一个是将数组名在sizeof里面使用时,另一个就是&数组名,在这两种情况下数组名不代表数组首元素地址。

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr);
	return 0;
}

上面一串代码,我们输出的时arr的地址,还有&arr的地址,当我们运行时,我们会看到

输出的结果是一样的,但是它的本质上是一样的吗?

接下来将arr与&arr分别加1我们来看一下结果

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr);

	printf("arr+1 = %p", arr + 1);
	printf("&arr+1 = %p", &arr + 1);
	return 0;
}

 当我们对arr和&arr分别+1时,我们看到了不同,006FF8F0与006FF914之间相差了36个字节,因此我么们不由的想到arr和&arr的值是一样的,但是其本质的意义有所不同。本质上&arr表示的是数组的地址,当我们对&arr+1时,我们跳过了arr整个数组,arr数组里面存储了10个int类型的元素,因此&arr+1我们这个操作跳过了40个字节,&arr的类型是int(*)[10],是一种数组指针类型。

 

3.数组指针的使用

我们了解到了数组指针,但是数组指针具体有什么用处呢?

#include<stdio.h>
void print(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 };
	print(arr, 3, 5);
	return 0;
}

我们创建一个二维数组,写一个打印函数print 将二维数组打印出来

我们在传参时将二维数组arr传进去,当我们接收时可以用一个数组指针来接受,我们知道二维数组其实在存储是还是以一维数组的方式存储的(应该可以这样子理解);

只是我们理解为一个二维数组,但是编译器在处理时还是当作一个一维数组处理的,编译器是认为这样子的

 数组名arr,表示首元素的地址,但是二维数组的首元素是二维数组的第一行,所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址,因此可以用数组指针来接收。

四、 数组传参、指针参数

 1、一维数组传参

include<stdio.h>
int main()
{
	int arr1[10] = { 0 };
	int* arr2[20] = { 0 };
	test1(arr1);
	test2(arr2);
	return 0;
}

当我们创建两个数组arr1  arr2  我们要将这两个数组当作实参传入到函数test1与test2中,这个我们应该怎样来写test1,2的形参呢?

void teat1(int arr[])
{}
void test1(int arr[10])
{}
void test1(int* arr)
{}

当test1时,我们用一个整型数组来接受,是没有任何问题的,当然这里我们可以不写数组的大小,因为在数组传参时我们本质上传入的是首元素的地址,在传参的时候并不会创建一个新的数组,因此不写大小,也可以直接遍历。当然我们也可以用一个指针的形式来接收

void test2(int* arr[20])
{}
void test2(int** arr)
{}

当test2时,我们用一个int*类型的数组来接收,也可以用一个指针变量来接收

2、二维数组传参

void test(int (*arr)[5])
{}
int main()
{
	int arr[3][5] = { 0 };
	test(arr);
	return 0;
}

在二维数组传参时,我们可以用数组指针的形参来接收,但是这里需要注意的是,二维数组传参,函数形参的设计只能省略第一个[]中的数字,也就是只能省略行,但不能省略列,因为并不知道一行中有多少个元素,但是对于行,当我们对数组指针进行解引用时,我们对其加1,数组指针加1跳过的是一个数组,因此就可以找到第二行的首元素的地址,这样子我们就可以找到每一行的每一个元素,也就可以找到每一个元素,因此行可以省略,但是列不能省略。

3、一级指针传参与二级指针传参

这里的指针传参比较简单,当一级指针传参时,我们用一个一级指针变量来接收就好了,同理,二级指针用二级指针变量来接收就可以了

五、函数指针

函数指针,顾名思义,函数指针就是指向函数的指针。

#include<stdio.h>
void test()
{
	printf("hello bit");
}
int main()
{
	printf("%p\n", test);
	printf("%p\n", &test);
	return 0;
}

上面一串代码,我们分别打印test的地址和&test的地址

 我么看到,打印出来的结果竟然是一样的,那是不是和上面说的arr和&arr类似,只是地址一样,但是本质上不一样呢?

其实test==&test,他们两个在本质上是一样的(这也太神奇了,hahaha)。

那么这里我们应该将函数的地址保存起来,应该怎样保存呢?这时我们应该用到函数指针,函数指针应该是什么样子的?

首先创建一个变量p我们再将指针变量与*结合起来,表示p是一个指针,那么然后指针指向的是一个函数,指向的函数无参数(*p)(),函数的返回值类型为void因此应该为void(*p)();

例如

int ADD(int x,int y)
{
    return x+y;
}

这个函数的指针应该为int (*ADD)(int x,int y)

函数的指针数组

今天先到这,明天在写

举报

相关推荐

0 条评论