C指针和数组实例解析 Love The Way You Lie 2022-06-17 07:44 222阅读 0赞 积木网络 **修正了很多错误,以前理解的很多是错误的。2013.5-13** 数组是相同类型的元素集合,用一个名称引用。使用不同的索引值就可以引用数组中的不同的元素值。数组又分为一维数组和一维以上的多维数组。它们在组成形式上不同,但概念是相同的。所谓的多维数组就是数组里面包含数组。 例如: char Array\[3\] = \{'a','e','f'\}; 这是一个一维数组 char Array\[3\]\[3\] = \{ \{'a','b','c'\},\{'d','e','f'\},\{'e','g','f'\}\};这是一个二维数组,也是多维数组,它由三个一维数组组成。 即:\{'a','b','c'\},\{'d','e','f'\},\{'e','g','f'\},每个一维数组里,又包含了三个元素。 由于主要说指针和数组,所以关于更多的数组概念,我就不多做没用的解释了。 说起指针,指针到底是什么? 其实指针就是内存地址!它也用变量也存储,叫做指针变量,通常都叫它指针。它是变量,这个变量存储的只能是一个内存的地址。这个地址不管它是一个常量的地址,还是一个变量的地址,只要它是地址,那么它都可以用指针存储。既然指针是一个变量,那么它也会有自己的内存地址,这就是以后要说的指针的指针了。 那么指针和数组到底有什么关系呢? 首先我们来说一维数组 **对于一维数组:** char array\[3\] = \{'a','e','f'\}; 表示数组里的每个元素,用下标法我们可以这样写: array\[0\] 表示第0号元素:'a';对应的内存地址:&array\[0\]; array\[1\] 表示第1号元素:'e';对应的内存地址:&array\[1\]; array\[2\] 表示第2号元素:'f';对应的内存地址:&array\[2\]; C语言里规定数组名代表了数组的首地址,并且这个数组的第0号元素的地址也同是这个数组的首地址。也就是说,它们可以同时表示这个数组的首地址。 所以我们也可以这样表示: \*(array + 0) (或\*array)表示第0号元素:'a';对应的内存地址为:array + 0 或 array \*(array + 1) 表示第1号元素:'e';对应的内存地址为:array + 1 //第0号元素地址加1 就是第1号元素的地址 \*(array + 2) 表示第2号元素:'f';对应的内存地址为:array + 2 这里的"()"一定要有,否则是错误的。比如:\*array + 1,这样的结果是,先取得 array 的值 a 然后用 a 再加1,这相当于 a + 1的结果。 那么用指针如何表示?由于前面已经提到指针是什么了,所以,用指针就可以这样表示: char \*parray = array; //定义一个指针变量 parray 并用array数组的地址赋值 \*(parray + 0) (或:\*parray)表示第0号元素:'a'; 对应的内存地址就是指针 parray; \*(parray + 1) 表示第1号元素:'e'; 对应的内存地址就是:parray + 1; \*(parray + 2) 表示第2号元素:'f'; 对应的内存地址就是:parray + 2; 需要注意的是\*(parray + 1) 这里的"()"一定要有,如果不加"()",得到结果是不正确的。因为parray是一个地址,parray + 1是表示地址加1,这样首地址加1,得到才是第1号元素的地址,然后再对这个地址进行取值,就得到了第1号元素的值。如果不加"()",那么,首先通过取值运算符\*对parray进行取值,得到第0号元素的值,然用第0号元素值加1,那得到结果就不是第1号元素值了,而是 a+1了,一个字符型数值和一个整数型数值相加,就会报错了。 下面通过一段代码,把上面的概念来整合一下,为了表示清楚,便于理解这里没有用循环来做,此代码在VC6.0下编译运行通过。 /\*指针和一维数组\*/ \#include <stdio.h> int main(void) \{ char array\[3\] = \{'a','e','f'\}; //定义一个一维数组并赋初值 char \*Parray = array; //定义一个指针变量并赋初值 //下标表示 printf("下标法表示元素值和地址:\\n"); printf("数组array的首地址:%p\\n",array); printf("数组array的第0号元素地址:%p\\n",&array\[0\]); printf("数组array的第0号元素值:%c\\n\\n",array\[0\]); printf("数组array的第1号元素地址:%p\\n",&array\[1\]); printf("数组array的第1号元素值:%c\\n\\n",array\[1\]); printf("数组array的第2号元素地址:%p\\n",&array\[2\]); printf("数组array的第2号元素值:%c\\n\\n",array\[2\]); //取值符表示: printf("数组array的第0号元素地址:%p\\n",array + 0); printf("数组array的第0号元素值:%c\\n",\*(array + 0)); printf("数组array的第1号元素地址:%p\\n",array + 1); printf("数组array的第1号元素值:%c\\n",\*(array + 1)); printf("数组array的第2号元素地址:%p\\n",array + 2); printf("数组array的第2号元素值:%c\\n\\n",\*(array + 2)); //指针表示 printf("指针法表示元素值和地址:\\n"); printf("数组array的首地址:%p\\n",Parray); printf("数组array的第0号元素地址:%p\\n",Parray + 0); printf("数组array的第0号元素值:%c\\n\\n",\*(Parray + 0)); printf("数组array的第1号元素地址:%p\\n",Parray + 1); printf("数组array的第1号元素值:%c\\n\\n",\*(Parray + 1)); printf("数组array的第2号元素地址:%p\\n",Parray + 2); printf("数组array的第2号元素值:%c\\n\\n",\*(Parray + 2)); return 0; \} 上面的例子,我们看到,一开始,我就把数组的首地址赋给了指针变量Parray,其实我们也可以直接把数组任意元素的地址赋给Parray,然后通过指针随意读取元素值。 比如: char \*Parray = &array\[1\]; printf("array 的第1号元素值:%c", \*Parray); **对于二维数组:** char array\[3\]\[3\] = \{ \{'a','1','b'\}, \{'2','c','3'\}, \{'d','4','5'\} \}; 这个数组我们可以拆成这样看,它分别由三个一维数组组成: array\[0\] = \{'a','1','b'\}; array\[1\] = \{'2','c','3'\}; array\[2\] = \{'d','4','5'\}; 即:array\[3\]\[3\] = \{array\[0\],array\[1\],array\[2\]\}; **其中的值和地址用下标表示:** array\[0\]\[0\] 表示为 a; &array\[0\]\[0\] 表示为地址 array\[0\]\[1\] 表示为 a; &array\[0\]\[1\] 表示为地址 array\[0\]\[2\] 表示为 a; &array\[0\]\[2\] 表示为地址 array\[1\]\[0\] 表示为 2; &array\[1\]\[0\] 表示为地址 array\[1\]\[1\] 表示为 2; &array\[1\]\[1\] 表示为地址 array\[1\]\[2\] 表示为 2; &array\[1\]\[2\] 表示为地址 array\[2\]\[0\] 表示为 d; &array\[2\]\[0\] 表示为地址 array\[2\]\[1\] 表示为 d; &array\[2\]\[1\] 表示为地址 array\[2\]\[2\] 表示为 d; &array\[2\]\[2\] 表示为地址 在一维数组中,我们知道: printf("%c",array\[0\]); // 输出第0号元素的值, 或 printf("%c",\*array); //输出第0号元素的值, printf("%p",&array\[0\]); // 输出第0号元素的地址。 或 printf("%p",array) // 输出第0号元素的地址。 需要注意的是:在二维数组中, printf("%c",array\[0\]); // 错误,输出为地址 为什么是错误的?因为array\[0\]是一个一维数组。通过一维数组我们知道,一维数组的名字就是这个数组的首地址,也是这个数组中第0号元素的地址。那么,要想取得这个array\[0\]数组中元素的值,需要对这个数组取值,即: printf("%c",\*array\[0\]); 这样就会得到这个数组中第0号元素的值了。又因为数组的特点,元素的地址是连续的,那么取第1号元素的值就是: printf("%c",\*(array\[0\] + 1)); // 第0号元素地址+1 再取值,即为第1号元素的值。 第2号元素值: printf("%c",\*(array\[0\] + 2)); // 第8号元素值: printf("%c\\n",\*(array\[0\]+8)); 对应的地址为: printf("%p\\n",array\[0\] + 8); 或者: printf("%c\\n",\*array\[1\]); //取第3号元素的值 对应的地址为:printf("%p\\n",array\[1\]); printf("%c\\n",\*(array\[1\]+1));//取第4号元素的值 对应的地址为:printf("%p\\n",array\[1\]+1); printf("%c\\n",\*(array\[1\]+2));//取第5号元素的值 对应的地址为:printf("%p\\n",array\[1\]+2); 其实这个很绕,不太好理解。**总结一下就一句话:用上面这种方法表示多维数组的时候,我们把多维数组转化成一维数组,然后按一维数组的取值、取址方式进行操作即可。** 另外:我们还可以以下方试来表示二维数组的地址和值。 **直接用二维数组名来进行取值、取址操作** (同一维数组操作方式) \*(\*array) = 'a' //array本身就是一个地址,\*array 取得内容(第0号子数组的首地址,也是这个数组的第0号元素地址),然后对这个0号元素的地址再进行取值\*(\*array),即:元素值 'a' \*(\*array + 1) = 1 第1号元素值 对应的地址为:\*array + 1 \*(\*array + 2) = b 第2号元素值 对应的地址为:\*array + 2 \*(\*array + 3) = 2 第3号元素值 对应的地址为:\*array + 3 \*(\*array + 4) = c 第4号元素值 对应的地址为:\*array + 4 \*(\*array + 5) = 3 第5号元素值 对应的地址为:\*array + 5 \*(\*array + 6) = d 第6号元素值 对应的地址为:\*array + 6 \*(\*array + 7) = 4 第7号元素值 对应的地址为:\*array + 7 \*(\*array + 8) = 5 第8号元素值 对应的地址为:\*array + 8 下面,我们用一段代码,把上面的结果输出一下,为了节省代码量,我用了循环,此代码在VC6.0下编译运行通过。 \#include <stdio.h> int main(void) \{ char array\[3\]\[3\] = \{ \{'a','1','b'\}, \{'2','c','3'\}, \{'d','4','5'\} \}; for(int loop\_var = 0;loop\_var < 9;loop\_var ++) \{ printf("array数组的第%d个元素值是:%c\\n",loop\_var,\*(\*array + loop\_var)); printf("array数组的第%d个元素的地址是:%p\\n",loop\_var,\*array + loop\_var); \} return 0; \} **用指针操作数组:** 有了上面的基础,我们就可以使用指针来对二维数组进行描述了。而且如果你弄懂了上面所说的,那用指针来描述,你会发现是如此简单。 我们回头看上面的二维数组:它实际上一共有3\*3=9个元素。**对于指针来说,无论是一维数组还是二维数组,我们只需要把第0个元素的地址赋给指针变量(这个指针变量即为数组的指针变量)就可以了,因为数组的特点是连续存储的,即内存地址是连续的。所以用指针来表示的话,只要这个指针递加一个数值就可以表示不同的元素值或这个元素的地址了。** 首先定义一个指针变量(称为数组的指针变量): char \* parray; 然后赋值: parray = \*array; //注意这是 \*array 不是array 为什么是这样,一会解释 用指针表示数组元素值及地址: \*(parray + 0) 对应的值为:a 对应的地址为 :parray + 0 \*(parray + 1) 对应的值为:1 对应的地址为 :parray + 1 .... \*(parray + 8) 对应的值为:5 对应的地址为: parray + 8 注意取元素值的时候 \*(parray + 1) 这对"()"必须有,因为parray是第0个元素的地址,这个地址+1就是第二个元素的地址,所以要取其中的值,必须先用()括起来,再对这个地址取值。否则得到是:取得\*parray的值后,再用取得的值+1,即 :a + 1,而非下一 个元素的值。 那么为什么不能像一维数组一样,用 char \*parray = array 这样来给指针赋值呢?这是因为对于多维数组来说,\*parray不能引用一个间接地址,说白了就是说,array 包含另一个数组的地址,这个地址不是最终数组元素的地址,而这个地址包含最终的元素地址。对于\*parray 只能引用数组最终元素的地址。所以 char \*parray = array 这样写是不正确的。 下面就通过代码用指针把二维数组描述一下,为了节省代码量,我用了循环,此代码在VC6.0下编译运行通过。 \#include <stdio.h> int main(void) \{ //定义一个二维数组 char array\[3\]\[3\] = \{ \{'a','1','b'\}, \{'2','c','3'\}, \{'d','4','5'\} \}; char \*parray = \*array; //定义指针变量 //循环输出数组元素和元素地址 for(int loop\_var = 0;loop\_var < 9; loop\_var ++) \{ printf("数组array的第%d元素的地址为:%p\\n",loop\_var,parray + loop\_var); printf("数组array的第%d元素的值为:%c\\n",loop\_var,\*(parray + loop\_var)); \} return 0; \} 由于我是个初学者,肯定会有什么说的不对,或者理解错误的地方,请有经验的前辈给批评指出。
相关 Java中空指针异常实例解析 在Java编程中,"空指针异常"(NullPointerException)是一种常见的运行时错误。当程序试图访问一个null引用对象的属性或方法时,就会抛出这个异常。 以下 灰太狼/ 2024年09月10日 07:36/ 0 赞/ 20 阅读
相关 Java中空指针异常实例解析 在Java编程中,`NullPointerException`是一种常见的运行时异常,它表示你试图访问一个null对象的属性或方法。 下面是一个简单的`NullPointer 喜欢ヅ旅行/ 2024年09月05日 18:36/ 0 赞/ 15 阅读
相关 void和void指针解析 一)基本概念 void 类型:空类型,用于特殊目的的没有操作,也没有值的类型。不能被显式或隐式的转换为任意非空类型,可以通过强制类型转换为void类型。 ... 淡淡的烟草味﹌/ 2024年04月19日 14:11/ 0 赞/ 36 阅读
相关 【C进阶】指针和数组笔试题解析 做题之前我们先来回顾一下 > 对于数组名的理解:除了以下两种情况,数组名表示的都是数组首元素的地址 > > (1)sizeof(数组名):这里的数组名表示整个数组 > > 淡淡的烟草味﹌/ 2023年10月16日 00:52/ 0 赞/ 2 阅读
相关 c++数组指针和指针数组 如下: int \matrix\[10\]; // array of 10 pointers int (\matrix)\[10\]; // pointer to an 桃扇骨/ 2022年09月17日 07:29/ 0 赞/ 216 阅读
相关 C指针和数组实例解析 积木网络 修正了很多错误,以前理解的很多是错误的。2013.5-13 数组是相同类型的元素集合,用一个名称引用。使用不同的索引值就可以引用数组中的不同的 Love The Way You Lie/ 2022年06月17日 07:44/ 0 赞/ 223 阅读
相关 C 指针常量和常量指针实例解析 /\ 常量:是一个不可改变的量。 常量指针: 把指针做为一个常量,这时候指针(内存地址)做为一个常量,这个内存地址不能被改变,但是指针(内存地址)里存储的值 本是古典 何须时尚/ 2022年06月17日 00:40/ 0 赞/ 174 阅读
相关 C# 操作符重载实例解析 当你在编写一个大型的复杂的程序的时候可能会遇到“许多匪夷所思的情况”,其中一种就是:使用操作符对操作数进行运算的时候,其结果明显是错误的,而且排查之后发现导入的数据和算法都是正 叁歲伎倆/ 2021年09月28日 04:38/ 0 赞/ 331 阅读
还没有评论,来说两句吧...