我们先看一个例子:
A.int a[3][4];
B.int b[12];
C.int (*p)[12];
他们分别是一个二维数组,一个一维数组,一个指向一维数组的指针。我们知道整型,用int表示,字符用char表示,一些基本的类型都有字面上的一种表示,那么像int a[3][4]这种它的字面上的表示是什么呢?编译器可不知道什么“指向整型的二维数组”之类的东西,实际上他们有自己的类型,不过不像基本类型那样统一明确。很大程度上,他们在不同编译器中给出的类型表示是不同的,如vc下面的int [3][4],gcc下面的A3_A4_i,但是他们传递的意义是一样的。
我们知道数组可以跟指针转换。转换的本质就是“降维“,那么:
int [1][2][3]==> int (*)[2][3]
int [3][4] ==> int (*)[4]
int [12] ==> int *
还有一个事实就是,C语言在赋值时要求类型匹配(当然很多同学都无视这些警告 -_-!)。所以当B赋值给C时,就会报警告,因为B类型为int [12],而C为int (*)[12],所以正确的赋值时p = &b,因为&b的类型就是int (*)[12],一切就OK了。
这里不得不提一个问题就是a[3][4]降维之后为什么’3’没了,’4’还在?因为在内存布局上,一个二维数组(高维道理一样),是以行为布局单位,一行挨一行的放。在这个例子里,我们知道3为行数,4为列数,所以降维意味着我们能看得更细,我们就看到了它在内存里是一行一行的(当然有的人眼更厉害,他可以看到每个字节。。。这是另一种情况,我们后面会说)。
这里分几点来说:
1. 赋值与比较
C语言属于强类型语言,类型检查比较严格,类型不匹配的会报警告,但是有些情况除外,即转换形式(如数组转换成等价的指针形式)一致的两个类型,是兼容的。
例如:int (*p)[4]和int a[3][4],这时p=a的赋值时正常的,原因就是int [3][4]其等价的指针形式为int (*)[4],而这个跟p的类型是相符的。
2. 加减运算
在开始的那个例子中,int a[3][4]的类型是int [3][4],那么a + 1呢?
这里的a要转换为等价的指针形式来运算(数组加减。。。没听说过!),那个a的指针形式就是int (*)[4],运算时就要根据这个类型来算。另外一点,指针加减中的数字,是一个数量的意思,意思是加减n * sizeof(type),注意这里说的type是指针指向的类型,如本例,a是int (*)[4]类型,它指向的是int [4]
类型,那么加1,就以为这加1 * sizeof(int [4]),即16字节。
3. 取一个元素(就是前面所说的那种好眼力)
假设int a[3][3] = {{1,2,3}, {4,5,6},{7,8,9}},我们知道a[2][1]可以取到值8,那么*(*(a+2)+1)为什么也能取到这个值呢?有了上面所说的,理解应该比较简单了。我们最终要取得一个int,而现在摆在眼前的是int [3][3]类型,那么我们就可以通过一步步转换和降维来做到。a[2][1],位于第3行中的第2个数(位于二维层面上的三行二列的位置),所以我们先定位第3行,再在这一行中定位第2个数就行了。
a的指针等价形式为int (*)[3],所以a+2,就是从开始位置,找到2*sizeof(int [3]),即第三行(记住在内存布局上,是一行一行挨在一起放的),此时a+2的类型还是int (*)[3],因为指针上加减数字并不改变类型。此时*(a+2)就是为int (*)[3]的指针类型取内容,很明显得到的类型就是int [3]了。因为*(a+1)的类型为int [3],其等价的指针形式就是char *,自然*(a+1)+1,就是指向int [3]数组中的第二个元素,此时的类型还是char
*,那么拿到最终的元素,用*来取内容就行了,也就是*(*(a+2)+1)。
编译器就是按照这些规则来处理千变万化的表达式,而只要按照规则,处理起来就是一样的道理,类似递归那样一层层处理下去。大家在碰到类似的情况时,按照这些方法去理解,去处理,问题就好解决了。
分享到:
相关推荐
C语言中数组与指针的探讨
C语言中数组与指针学习探讨.pdf
C语言中数组与指针关系的探讨.pdf
本文将深入探讨C语言指针的相关概念,帮助你更好地理解和运用它们。 C语言指针是程序设计中最重要的概念之一。它可以帮助你更好地管理内存,提高程序的效率,让你更加高效地编写代码。在这个问答集中,你将会学习到...
本书为你详尽探讨指针的使用,什么是常量指针,什么是指针常量,数组同指针有什么区别,什么叫地址传递和指针传递,函数指针式怎么一回事。本书通俗易明,图文并茂,语言精简易懂,有理论也有实践部分,适合有c语言...
本文档在某知名网站下载,要么浏览量最多,要么最新,保证精品,至少为你节约3RMB。格式为caj或者kdh需要专业阅读器打开。
接着,我们将深入探讨指针和数组,包括指针的基本概念、指针的算术运算、指针和数组的关系等等。然后,我们将介绍C语言中的结构体和联合体,以及这些数据类型在实际编程中的应用。此外,我们还将讲解C语言中的函数和...
进阶知识笔记:深入探讨了指针、数组、函数、结构体等进阶知识点,帮助学习者进一步提升编程能力。 实践案例笔记:结合实际案例,让学习者通过实践掌握C语言的实际应用,培养解决问题的思维。 常见错误与调试笔记:...
指针是 C 语言的精华部分,也是 C 语言学习的重点和难点,正确而灵活地应用指针是学习 C 语言中最重要的环节,本文从指针的概念、运算、初始化以及与数组和函数的关系五个方面对 C 语言指针进行了分析和探讨。
本书提供与C语言编程相关的全面资源和深入讨论。本书通过对指针的基础知识和高级特性的探讨,帮助程序员把指针的强大功能融入到自己的程序中去。 全书共18章,覆盖了数据、语句、操作符和表达式、指针、函数、数组...
接着,它深入探讨了控制结构、函数、数组、指针、结构体等核心概念,然后继续扩展到文件操作、库函数使用、数据结构、算法,以及与操作系统和网络编程相结合的高级主题。 此外,学习路线还包含实际项目实战,旨在...
指针、引用和取值 什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量。在这份教程里“引用”表示计算机内存地址。从指针指向的内存读取数据称作指针的取值。指针可以指向某些...
1、探讨字符串指针变量与字符串数组的区别; 2、探讨指针变量的偏移与距离;
1、讲解通过指针变量实现字符串拷贝函数的代码编写方法; 2、探讨字符串数组和字符串常量在字符串复制过程中的各种情况;
循环是所有编程语言中最为重要的机制之一,几乎任何拥有实际意义的计算机程序(排序、查询等)都里不开循环。 而循环也正是程序优化中非常让人... javascript 的for语法继承自c语言,for循环的基本语法有两种使用方法。
本套课程主要探讨如何读懂 C/C++ 语言程序的反汇编代码。所谓反汇编,简单的讲就是把可执行文件的二进制编码翻译成汇编语言代码,从汇编代码中读懂原高级语言的含义。这是一套基础课程,着重讲解反汇编代码与 C/C++ ...
C语言中最大的特色就是指针。指针的使用具有很强的技巧性和灵活性,但同时也带来了很大的危险性。在XXX的代码中有如下一端对指针的灵活使用: ... ... _UC *puc_card_config_tab; ... ... Get_Config_Table( ...