第一个 printf() 语句中,arr[i] 表示获取第 i 个元素的值,该元素是一个指针,还需要在前面增加一个 * 才能取得它指向的数据,也即 *arr[i] 的形式 。
第二个 printf() 语句中,parr+i 表示第 i 个元素的地址,*(parr+i) 表示获取第 i 个元素的值(该元素是一个指针),**(parr+i) 表示获取第 i 个元素指向的数据 。
指针数组还可以和字符串数组结合使用,请看下面的例子:
#include <stdio.h>int main(void){char *str[3] ={"hello C","hello C++","hello JAVA"};printf("%sn%sn%sn", str[0], str[1], str[2]);return 0;}
运行结果为:
hello Chello C++hello Java
3、二维数组指针
二维数组指针:指向二维数组的指针 。如:
int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };int (*p)[4] = a;
a [3] [4]表示一个3行4列的二维数组,其所有元素在内存中是连续存储的 。
请看如下程序:
#include <stdio.h>int main(void){int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };int i,j;for( i = 0; i < 3; i++ ){for( j = 0; j < 4; j++ ){printf("a[%d][%d]=%dn", i, j, &a[i][j]);}}return 0;}
运行结果为:
a[0][0]=6422216a[0][1]=6422220a[0][2]=6422224a[0][3]=6422228a[1][0]=6422232a[1][1]=6422236a[1][2]=6422240a[1][3]=6422244a[2][0]=6422248a[2][1]=6422252a[2][2]=6422256a[2][3]=6422260
可见,每个元素的地址都是相差4个字节,即每个连续在内存中是连续存储的 。
按照以上定义可归纳出如下4个结论:
(1)p指向数组a的开头,也即第1行;p+1前进一行,指向第2行 。
(2)*(p+1)表示取第2行元素(一整行元素) 。
(3)*(p+1)+1表示第2行第2个元素的地址 。
(4)((p+1)+1)表示第2行第2个元素的值 。
综上4点,可得出如下结论:
a+i == p+i *(a+i) == *(p+i)a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j)== *(*(p+i)+j)
以上就是数组与指针常用的三种结合形式 。
指针与数组的区别数组与指针在多数情况是可以等价的,比如:
int array[10]={0,1,2,3,4,5,6,7,8,9},value;value=https://www.isolves.com/it/cxkf/yy/C/2020-02-27/array[0]; //也可写成: value=*array;value=array[3]; //也可写成: value=*(array+3);value=array[4]; //也可写成: value=*(array+4)
但也有不等价的时候,比如如下三种情况:
- 数组名不可以改变,而指向数组的指针是可以改变的 。
- 字符串指针指向的字符串中的字符是不能改变的,而字符数组中的字符是可以改变的 。
- 求数组长度时,借用数组名可求得数组长度,而借用指针却得不到数组长度 。
数组名的指向不可以改变,而指向数组的指针是可以改变的 。
请看如下代码:
#include <stdio.h>int main(void){int a[5] = {0, 1, 2, 3, 4}, *p = a;char i;// 数组遍历方式一for ( i = 0; i < 5; i++ ){printf("a[%d] = %dn", i, *p++);}// 数组遍历方式二for ( i = 0; i < 5; i++ ){printf("a[%d] = %dn", i, *a++);}return 0;}
数组遍历方式一:使用指针遍历数组元素,* p++等价于*(p++),即指针指向的地址每次后移一个单位,然后再取地址上的值 。这里的一个单位是sizeof(int)个字节 。数组遍历方式二:使用数组名自增遍历数组元素,编译出错,错误如下:
error: value required as increment operand
因为数组名的指向是不可以改变的,使用自增运算符自增就会改变其指向,这是不对的,数组名只能指向数组的开头 。但是可以改为如下遍历方式:for ( i = 0; i < 5; i++ ){printf("a[%d] = %dn", i, *(a+i));}
这可以正确遍历数组元素 。因为*(a+i)与a[i]是等价的 。2、区别二
字符串指针指向的字符串中的字符是不能改变的,而字符数组中的字符是可以改变的 。
请看如下代码:
//字符串定义方式一char str[] = "hAppy";//字符串定义方式二char *str = "happy";
字符串定义方式一:字符串中的字符是可以改变的 。如可以使用类似str[3]='q'这样的语句来改变其中的字符 。原因就是:这种方式定义的字符串保存在全局数据区或栈区,是可读写的 。字符串定义方式二:字符串中的字符是不可以改变的 。原因就是:这种方式定义的字符串保存在常量区,是不可修改的 。
2、区别三
求数组长度时,借用数组名可求得数组长度,而借用指针却得不到数组长度 。
推荐阅读
- 移动应用开发的六大编程语言
- 哈佛大学图书馆的20句训言 哈佛大学经典语录
- 用C语言编写CPU使用率限制程序
- 四川经典茶技特色表演亮相德国
- 12个经典逻辑难题,你能想明白几个?
- 跨平台的C语言网络框架库acl
- 驿路茶马经典茶产品马当先热销中
- 经典短笑话(50个小笑话)
- 用最简单的语言让你懂得如何选择四驱车:五类四驱系统特点详解
- 16种编程语言是如何命名的?