数组与指针

数组与指针

arr、&arr、&arr[0]、*P 的区别

  1. 首先,他们指向的都是数组首元素的地址。单纯的打印他们的值,都是相同的。例如以下代码段:

    // 假定以下伪代码在内存中的起始地址是从0x0开始的
    
    int main()
    {
    	int arr[3] = {1,2,3};
    	int* p = arr;
        
    	printf("%p", arr);		// 输出地址为0x0
    	printf("%p", &arr[0]);	// 输出地址为0x0
        printf("%p", p);		// 输出地址为0x0 
    	printf("%p", &arr);		// 输出地址为0x0
    	
    	return 0;
    }
    
  2. 但是,他们的数据类型是不同的。

    • arr:表示数组类型,或者说是数组本身
    • &arr[0]:是一个指针类型(匿名指针),该指针指向arr数组的首地址,上文代码段中的&arr[0]int* p可以认为除了匿名和非匿名的区别,其余的特性都是等价的
    • int* p:是一个指针类型,该指针指向arr数组的首地址
    • &arr:是一个数组类型的指针(匿名指针),该指针指向一个int类型的数组,等价于匿名的int (*arr)[];

    虽然他们指向的地址相同,但是当对不同的数据类型做操作时,他们的差异就会体现出来,例如以下代码段:

    // 假定以下伪代码在内存中的起始地址是从0x0开始的
    
    int main()
    {
    	int arr[3] = {1,2,3};
    	int* p = arr;
        
    	printf("%p", arr + 1);		// 错误代码,编译会失败! 数组本身是不能地址偏移的
    	printf("%p", p+ 1);			// 输出地址为0x4,因为是一个int类型的指针,每次+1偏移4字节
        printf("%p", &arr[0] + 1);	// 输出地址为0x4,等价于p,但是是匿名的
       	printf("%p", p + 1);		// 输出地址为0xC,因为是数组类型的指针,所以偏移了一整个数组的地址
    	
    	return 0;
    }
    

常见的数组与指针结合

int arr[];表示一个数组,数组中的元素都是int类型

int (*arr)[];表示数组类型的指针 ,这个指针指向一个int类型的数组

int* arr[]={};表示数组中的元素都是指向int类型的指针

int* (*arr)[];表示数组类型的指针,这个指针指向的数组中的元素都是指针类型,且数组中的元素指向的都是int类型

逻辑关系梳理

不要死记硬背奥,核心原因,就是因为按照运算符的优先级,( ) > [ ] > * > 数据类型。

  • int arr[]:首先,因为运算符的优先级原因,变量名arr先与[ ]结合,表明这是一个数组。其次arr[]再与数据类型int相结合,表明数组中的元素都是int类型。
  • int (*arr)[]:首先()先生效,导致*arr先结合,表明这个变量是一个指针。其次, (*arr)再与[]相结合,表明这个指针是指向数组的。最后,(*arr)[]再与int相结合,表明这个指针指向的数据中的元素都是int类型。
  • int *arr[]:首先[]先生效,导致arr[]先结合,表明这个变量是一个数组。其次, arr[]再与*相结合,表明这个数组数组中的元素都是指针。最后,*arr[]再与int相结合,表明这个数组中的元素都是指向int类型的指针。
  • int* (*arr)[]:首先()先生效,导致*arr先结合,表明这个变量是一个指针。其次, (*arr)再与[]相结合,表明这个指针是指向数组的,最后, (*arr)[]再与最前面的*相结合,表示这个指针指向的数组中的元素都是指针类型。最最后,* (*arr)[]再与int相结合,表示这个指针指向的数组中的元素都是int类型的指针类型。

数组作为形参

一维函数形参接收数组的几种方式

void test1(int arr[], int arrSize){}

void test2(int arr[4], int arrSize){}

void test3(int* p, int arrSize){}

int main()
{
    int arr[4] = {1,2,3,4};
    int arrSize = sizeof(arr);
    test1(arr, arrSize);
    test2(arr, arrSize);
    test3(arr, arrSize);
    return 0;
}

说明:

  1. 上述代码段中,形参int arr[]int arr[4]int* p都可以用来接收一维数组。
    • 如果被调函数预期想要接收一个数组,建议使用int arr[],便于提高代码可读性。
    • int arr[4]一般不推荐,如果被调函数对接收的数组有预期大小,才建议使用。
    • int *p这种声明方式更通用,因为它不限制指针所指向的数据类型,只是指向具体的内存地址。指针的本质是存储内存地址的变量,而内存地址是通用的,不区分数据类型。
void test1(int arr[][3], int arrSize){}

void test2(int (*arr)[], int arrSize){}

void test3(int** p, int arrSize){}

int main()
{
    int arr[][3] = {{1,2,3},{4,5,6},{7,8,9}};
    int arrSize = sizeof(arr);
    test1(arr, arrSize);
    test2(arr, arrSize);
    test3(arr, arrSize);
    return 0;
}

说明:

  1. 上述代码段中,形参int arr[][3]int (*arr)[]int** p都可以用来接收二维数组。
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值