C语言 - 详解 指针 和 数组 的联系

指针的概念:

1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。
3. 指针是有类型的,指针的类型决定了指针的加减整数的步长,指针的类型也决定了指针解引用操作的时候,访问的权限。

数组的概念:

1.数组是一组相同类型元素的集合。

1.字符指针

在指针的类型中我们知道有一种指针类型为字符指针 char*。

图1.1

1.把字符‘w’赋值给字符变量ch,对ch进行取地址并赋值给指针 pc,指针 pc 是字符指针,再对pc进行解引用,然后把字符‘a’赋值给它,最后用printf( )函数进行打印。

图1.2

1.把arr数组中第1个元素的地址放在 p2 里。

2.把字符串"abcdef"的第1个字符的地址放在 p 里,内存中 a 的地址为:0x000A7BD0。

图1.3

1.无论是 const char* p1 = "abcdef" 还是 char const * p1 = "abcdef",在这两种情况下被const修饰,就意味着,指针 p1 所指向的内容不能修改,否则就会报错。

图1.4

1.内存中有块空间放着 a b c d e f \0 ,假设字符串中第1个字符的地址,即 a 的地址是0x0012ff40,那么 p1 就等于 0x0012ff40,p2 就等于 0x0012ff40,所以 if 语句中p1 == p2的条件成立,故打印 p1 == p2。

2.内存为arr1开辟一块空间,放着 a b c d e f \0,然后从 arr1 的起始地址开始,分别放着 a b c d e f \0,内存再为arr2开辟另一块空间,放着 a b c d e f \0,然后从 arr2 的起始地址开始,分别放着 a b c d e f \0。arr1 和 arr2 在内存中开辟的空间不一样,起始地址是不会相同的,所以if 语句中p1 == p2的条件不成立,故打印 arr1 != arr2。

2.指针数组

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

图2.1

1.整型数组 arr[10] 存放10个int 类型的变量。

2.字符数组 arr2[5]存放5个char 类型的变量。

3.指针数组 arr1[10]存放10个 int* 类型的变量,arr2[10]存放10个 int** 类型的变量,arr3[4]存放4个char* 类型的变量,arr4[5]存放5个 char** 类型的变量。

图2.2

1.首先 arr[3]是个指针数组,存放p1、p2、p3这三个指针, 这三个指针分别指向a、b、c三个整型变量,在for循环中,用printf( )函数分别打印三个变量的数值和地址。

图2.3

1.首先 parr[3]是个指针数组,存放arr1、arr2、arr3这三个指针, 这三个指针分别指向arr1、arr2、arr3三个整型数组(),在for循环中,用printf( )函数分别打印三个整型数组的数值。

2.在 parr[3] 这个指针数组中,存放着 arr1 这个指针,虽然 arr1 这个指针是该数组的首元素的地址,不是整个数组的地址。这个点在下面会进行强调并运用,这里先进行提示。

3.这类似于二维数组,将 printf("%d ", *(parr[ i ] + j)) 改成 printf("%d ", parr[ i ][ j ]),打印结果保持不变。

3.数组指针

数组指针的定义:

数组指针,是指针,指向数组的指针。

图3.1

1.整形指针: int* p,是能够指向整型数据的指针。

2.字符指针: char* pc,是能够指向字符数据的指针。

3.同理,那数组指针应该是:能够指向数组数据的指针。

图3.2

在  int* p1[ 10 ]  和  int(*p2)[ 10 ]  中,p1 和 p2 分别是什么?

解释如下:

1. 在  int* p1[10]  中, [ ] 的优先级高于 * , p1 先和 [10] 结合,所以 p1 是数组!数组 p1[10] 中存放10个 int* 类型的指针变量。

2.在  int(*p2)[10]  中,( )的优先级高于 [ ], p2 在 ( ) 里先和 * 结合 ,所以 p2 是指针!指向一个大小为10的整型数组,故叫数组指针。

3.在  int(*p2)[10]  中,p2 这个指针不是数组的首元素的地址,而是整个数组的地址。这个点在下面会进行强调并运用,这里先进行提示。

数组名该怎么理解呢?

通常情况下,我们说的数组名都是数组首元素的地址。
但是有2个例外:
1. sizeof(数组名),这里的数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,&数组名,取出的是整个数组的地址。

解释如下:

图3.3

1.表面上,数组名和&数组名打印的地址是一样的。实际上,数组名 表示的是数组首元素的地址,而 &数组名 表示的是整个数组的地址,不是数组首元素的地址。

2.数组 arr[5] 有5个元素,每个元素占4个字节,那么数组 arr[5] 共占 20 个字节,arr表示数组首元素的地址,arr+1 地址跳过4个字节,即一个整型变量的大小,&arr表示整个数组的地址,&arr+1 地址跳过20个字节,即整个数组的大小。

3.补充:%p - 打印地址,打印的地址以十六进制方式显示。

4.所以可以写成这样:  int(*p2)[5] = &arr ,p2 这个指针存放的是整个数组的地址,并指向一个大小为5的整型数组,故叫数组指针。

数组指针该如何使用?

写一个函数,打印arr数组的内容,代码如下:

图3.4

1.在主函数中创建 arr[10] 的数组,并进行赋值,sz为arr数组的元素个数,对 print1( )、print2( )、print3( ) 这三个函数进行传参,然后这三个函数分别对 arr 数组进行打印。

2.在 print1(arr, sz) 的传参过程中,arr:把数组首元素的地址传过去,sz:把数组的元素个数传过去。在 void print1(int arr[], int sz) 的参数接收的过程中,可以用数组进行接收,把形参写成数组的形式。进入print1()函数,在for循环中,用printf()函数对数组分别进行打印。补充如下:
在 void print1(int arr[], int sz) 中,对 int arr[]进行解释:传参时 arr 把 arr 数组的首元素传过去,首先,用数组接收,写成 arr[],其次,这个数组接收的元素的类型是 int 类型,写成 int arr[],最后,int arr[] 这个数组就成为了接收 arr 的形参。

3.在 print2( arr,  sz)  的传参过程中,arr:把数组首元素的地址传过去,sz:把数组的元素个数传过去。在void print2 (int* arr ,  int sz) 的参数接收的过程中,可以用整型指针进行接收,把形参写成指针的形式。进入print2()函数 ,在for循环中,用  printf( ) 函数对解引用的指针分别进行打印。补充如下:
在 void print2(int* arr, int sz) 中,对 int* arr 进行解释:传参时 arr 把 arr 数组的首元素传过去,首先,用指针接收,写成 * arr ,其次,这个指针接收的元素的类型是 int 类型,写成 int* arr,最后,int * arr 这个指针就成为了接收 arr 的形参。

4.在 print3(&arr, sz) 的传参过程中, &arr:把整个数组的地址传过去,sz:把数组的元素个数传过去。在void print3(int(*p)[10], int sz) 的参数接收的过程中,可以用数组指针进行接收,把形参写成数组指针的形式。补充如下:
在void print3(int(*p)[10], int sz) 中,对 int(*p)[10] 进行解释:传参时 &arr 把 arr 数组的10个元素传过去,首先,用指针接收,写成(*p) ,其次,这个指针接收10个元素,写成(*p)[10],接着,所接收的每个元素是int 类型,写成 int(*p)[10],最后,int(*p)[10] 这个数组指针就成为了接收 &arr 的形参。

图3.5

 请问 arr 、parr1、parr2、parr3 分别是什么?

1. arr 是一个数组,数组有5个元素 ,每个元素是int类型,所以 arr 是整型数组。

2. parr1 是一个数组,数组有10个元素,每个元素的类型是int*,所以 parr1 是指针数组。

3. parr2 是一个指向数组的指针,指向的数组有10个元素,每个元素的类型是int,所以 parr2 是数组指针。

4. parr3 是一个数组,数组有10个元素,每个元素的类型是:int( * )[5] ,所以 parr3 是存放数组指针的数组。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值