C语言:指针相关知识的细节刨析

一:数组名取地址方式不同相关内存分析

在平常,对于一个数组,虽然我们取地址的方式不同,但是有可能会得到相同的地址,那么我们是不是就可以随便拿出一个方式来用呢,这肯定是不行的。

基于此,我们首先需要分析的是下面的一段简单代码,给出判断。下面的代码是对 arr[9] 的三种不同的形式进行取地址分析(为了方便观察,下面代码是在32位平台上跑的程序):

#include<stdio.h>
int main()
{
	int arr[9] = { 1,2,3,4,5,6,7,8,9 };
	//第一种: &arr[0]的地址本质
	printf("&arr[0]    = %p\n", &arr[0]);
	printf("&arr[0]+1  = %p\n", &arr[0]+1);
	//第二种: arr的地址本质
	printf("arr        = %p\n", arr);
	printf("arr+1      = %p\n", arr+1);
	//第三种:&arr的地址本质
	printf("&arr       = %p\n", &arr);
	printf("&arr+1     = %p\n", &arr+1);
	return 0;
}

 

对于结果的分析,我们可以看出,1、3、5的地址结果相同,它们分别对应着:

&arr[0] arr , &arr 。

是不是这三个的内部含义一样呢,可以看下面的分析:

对于这个分析结果,可以清楚的知道,当各自的数组名+1时,有的增加了一个int的字节(4个字节),有的增加了一个数组arr[9]的字节(36个字节)。

1.对于&arr[0]和 arr,取出的是首元素的地址&arr[0]+1 和 arr+1,是首元素地址+1,取出的地址当然是arr[1]的地址啦。


2.对于 &arr,它们的地址和首元素的地址一样,但是,它们的地址是整个数组的地址,&arr+1都是增加整个数组的字节大小(代码中是9个int的大小),所有地址要加36

二:指针数组(存储地址的数组

很简单,我们知道整型指针存储的是整型的地址,类型是int*字符指针存储的是字符的地址,类型是char *,那么我们当然也有数组指针,数组指针存储的是一个数组的地址,如下图:

用法一:int  *str[4]是整型类型的数组指针,每个元素的类型是int *,可以存储4个整型变量的地址

#include<stdio.h>
int main()
{
	//整型指针
	int a = 3;
	int* p_int = &a;
	//字符指针
	char c = 'a';
	char* p_char = &c;
	//数组指针
	int x1 = 1, x2 = 2, x3 = 3, x4 = 4;
	int *str[4] = { &x1,&x2,&x3,&x4 };
}

 

用法二:int *arr[3]是整型类型的指针数组(就是存储地址的数组),类型是 int *,可以存储3个整型变量的数组的地址

 三:数组指针(存储数组的地址

在下图中,如果我们想存储二维数组的地址,那么我们怎么来写呢,用int  *a[3]来表示显然不可以,因为int *p[3]是一个指针数组,不能存储一个数组的地址.

其实,二维数组本质也是一个数组,如下图:

我们用int (*p)[3]来存储 int a[2][3]的地址,下图中,可以将a数组的行数作为一个一维数组来存储,我们一般用int *p来存储一维数组的首地址,而每一个首地址又是一个数组,这时,用(*p)[3]来表示存储的这个数组地址,每个元素是int类型,所以用 int (*p)[3]来存储int a[2][3] 的地址,类型为int (*)[3]

当行数+1时,int (*p+1)[3] 表示下一行的数组地址。

#include<stdio.h>
int main()
{
	int a[2][3] = { 1,2,3,4,5,6 };
	int(*p)[3] = a;
	printf("%d ", p[0][0]);
	printf("%d ", p[0][1]);
	printf("%d ", p[0][2]);
	printf("%d ", p[1][0]);
	printf("%d ", p[1][1]);
	printf("%d ", p[1][2]);
	printf("\n=========================\n");
	printf("%d ", *((*p) + 0) );
	printf("%d ", *((*p) + 1) );
	printf("%d ", *((*p) + 2) );
	printf("%d ", *(*(p+1) + 0) );
	printf("%d ", *(*(p+1) + 1) );
	printf("%d ", *(*(p+1) + 2) );
}

从这里可以看出,两种表示方式的结果相同,p[1][1]*(*(p+1)+1)表示的方式相同(这里的[]可以理解为是一个 * , * 是解引用操作符),这里第一种是最好理解的,但是在计算机中,全部都是转换成第二种方式来继续操作的,在做题的时候可以相互借鉴使用. 

 四:函数指针(存储函数的地址 


 有时候,我们会遇到存储函数的地址的问题,(比如:回调函数,qsort函数也需要传函数的地址),我们首先得存储相对用函数得地址,方法如下(以加法函数Add为列子):

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值