免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: Ager
打印 上一主题 下一主题

[C] 浅谈一下C语言中的指针与数组的关系 [复制链接]

论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
11 [报告]
发表于 2012-12-24 08:17 |显示全部楼层
本帖最后由 Ager 于 2012-12-24 08:17 编辑
pmerofc 发表于 2012-12-23 21:41
ager这次写得确实哲学味道浓了些。

gvim 发表于 2012-12-23 21:58
另外,窃以为简单的东西没必要复杂化,工程的东西没必要哲学化,越往复杂了说,越让人不解


呵呵,我来澄清一下吧。。。

在我看来,典型的“哲学/形而上学化”的阐释,一般是这种样子的:

xx是现象,yy是本质,我们要透过现象看本质。。

xx只是一个工具,yy才是本质。。。。。

xx只是理论,yy才是实践。。。。。。。

实践是检验真理的唯一标准。。。。。。。。。

数组是现象,指针是本质。。。

指针是现象,地址是本质。。。。。

数组的本质是。。。。。。

指针的本质是。。。。。。。。

深入贯彻落实xx语言编程思想,要求我们认真学习、深入了解,深刻领会、准确把握,坚决贯彻、切实落实。。。。。

。。首先,要认真学习、深入了解“指针”。学习贯彻xx语言编程思想,要准确把握“指针”,这是学习和贯彻的前提。。。。“指针”是xx语言的灵魂。。。。

。。。其次,要深刻领会准确把握xx语言编程思想。一是深刻领会xx语言的历史地位和科学内涵,二是深刻领会xx语言的鲜明特色和基本要求,三是深刻领会xx语言的宏伟目标,四是深刻领会xx语言的总布局,五是深刻领会“指针”是xx语言的核心。只有深刻领会才能准确把握xx语言编程思想,才能更好的贯彻落实xx语言编程思想。

。。。。最后,要坚决贯彻、切实落实xx语言编程思想。要大力发扬“理论联系实际”的开发风格,只有学以致用,坚持用xx语言编程思想指导实践,同时在实践中不断加深对xx语言编程思想的理解,才能真正把xx语言编程思想落到实处。

。。。。。xx语言编程思想确定了软件开发者对未来工作的指导思想,是软件开发者未来工作的方向塔,更是我们基层程序员的指明灯。我们要学认真习、深刻领会,在工作中切实贯彻落实,为IT事业发展事业而努力奋斗。


—— 喏,上面这种,就是“哲学”阐释的一种极致形式。

这种形式的特点是:对读者认知关于“xx语言编程思想”、“指针”的具体而直观的信息,没有任何帮助。

更有意思的是,你若把上文中的“xx语言编程思想”和“指针”替换成任何你想要强调的东西,其结果,都是“正确”的。

然而,我希望我所走的这条路,不是所谓“哲学之路”。

在我这里,更加关心的是:

(1)一个对于学习者本来是陌生的概念,是如何进入他们的视野中的,是以何种“样式”、“质感”甚至“成见”、“偏见”进入他们的意识中的 —— 比如说,许多用来对译的汉字(如“操作”)具有陷阱效应。

(2)学习者的畏难情绪,很可能来自于某种“魅”(宏大叙事的干扰,比如学习者总是习惯了闻听“指针是C的灵魂”从而产生某种自己也说不清的虚假敬畏)或某种“遮蔽”(由于学习者缺乏编程经验和学科素养,一些被业界内部非常熟稔、司空见惯、不言自明的知识、概念、思路和方法,这些关键信息在学习者那里却是阙失的;学习者被壁垒在话境之外,导致“看也看不懂、想也想不明白”)—— 比如说,有一些术语(如“打印/Print”、“回车/Carriage Return”)被遮蔽了历史源流。所以,优良的教材,应该为学习者“祛魅”、“祛蔽”。

(3)一个正确的编程语言要素(概念)的其正确性,应该在编程者对程序的具体编写过程(包括Thinking、Coding、Commenting和Reviewing)中体现出来,也就是说,概念之本身和对它们的使用,是彼此照映、彼此揭示的。

(4)编程语言的创造者、语言规范的制定者、算法与数据结构的发明者、设计模式的倡导者,他们原本的意图(或忌惮)是什么?他们希望自己的观念,怎么样地(分步骤、分层级地)呈现或被呈现在学习者的面前?

我希望,自己所做的,是“现象学(Phenomenology)”的 —— 其实它是反哲学的。

我的基本主张是这样的:

(1)除了现象,没有本质。

(2)应该尽力回到当事现场,发掘“质感性”、“偏见性”的东西 —— 这些东西通常被忽略或被刻意隐藏起来了。

(3)有一些东西应当被“悬搁”、“加上括号”。

就扯这麽多了,期盼大虾们指正,呵呵 —— :)


论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
12 [报告]
发表于 2012-12-24 08:53 |显示全部楼层
本帖最后由 Ager 于 2012-12-24 08:55 编辑

谢谢支持哦 {:3_193:}

timothyqiu 发表于 2012-12-24 08:34
星号没有特殊含义,比如 int *p; 指右侧的表达式 *p 的类型为左侧的 int,所以依照星号解除指针引用的原意,p 为指针。


这种理解法,的确容易帮助初学者尽快“过关”。但是,遇到这样附有初始化的声明行,就容易引发困惑:
  1. int x;
  2. int *p = &x;
复制代码
timothyqiu 发表于 2012-12-24 08:34
数组同理,比如 int x[10]; 指右侧表达式 x[10] 的类型为左侧的 int,所以依照方括号取下标的原意,x 为数组,元素个数为声明时的下标 10。


类似的道理,对于这样附有初始化的声明行:
  1. int *(*x)[3]= &a;
复制代码
一个可以令x合法的a,到底该是什么样子(啥类型)的?

在程序中,x该怎么用?

呵呵 ……

论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
13 [报告]
发表于 2012-12-24 09:05 |显示全部楼层
timothyqiu 发表于 2012-12-24 09:00
回复 55# Ager

声明和初始化虽然写在一起,但却是不相干的两步,是可以剥离看的。所以初始化并不包含在 ...


你说得没错:)

但是,按照那种理解法,初学者的困惑在于:

那个“int *p=&a;” 到底是在对“p”初始化,还是对“*p”初始化?

呵呵  {:3_193:}

论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
14 [报告]
发表于 2012-12-26 12:51 |显示全部楼层
蔡万钊 发表于 2012-12-25 20:06
a[1] != *(a + 1)

别被误导了。 在一般情况下,是相等的。也有不相等的时候。

int a[4][4];

这个时候  a[2][2] 的含义和   *(*(a +2) +2) 可不一样哦!


大虾。。你确定。。。。?

论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
15 [报告]
发表于 2012-12-26 20:21 |显示全部楼层
linux_c_py_php 发表于 2012-12-26 15:33
数组名是第一个元素的地址, 又没说过数组名是第一个元素的指针,


龙哥大虾,你说反了吧?笔误?

呵呵 。。。。

论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
16 [报告]
发表于 2012-12-26 20:27 |显示全部楼层
本帖最后由 Ager 于 2012-12-26 20:29 编辑
sqfasd 发表于 2012-12-26 20:12
疑问大了,您这句真有失水准
最起码的指针会分配内存,数组名只能是数组第一个元素地址的代号而已


。。。。

以下关键词,求关注:

内情向量  符号表 。。。。


干脆再呼召一下 键盘农夫 @KBTiller 大虾吧。。。



论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
17 [报告]
发表于 2012-12-26 20:53 |显示全部楼层
本帖最后由 Ager 于 2012-12-26 21:05 编辑

实在搞不清楚,我们做一个对比:

对于数组x的第i个元素(从0起头序),i显然是一个整数

x[ i ]

—— 当数组标识符x出现在(除了sizeof或&的之外的)表达式语境中,它被转换为指向数组首个元素的指针

所以,与x[ i ]等效的表达式

*(x + i)    ..........(式子 1 )

当中的 指 针 加 法,才能成立

而另一个方面,若用地址(偏移量)来解释的话,则是:

x[ i ]的偏移地址是:

BASE(Array x) + SIZEOF(Each Element of Array x) * i              ..........(式子 2 )

在式子2中的SIZEOF(Each Element of Array x)成分,是式子1的代码成分里面所没有的

所以,式子1,就叫做:指针加法!

指。针。加。法。

呵呵:)







论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
18 [报告]
发表于 2012-12-26 21:33 |显示全部楼层
本帖最后由 Ager 于 2012-12-26 21:34 编辑
sqfasd 发表于 2012-12-26 21:04
回复 98# Ager

还是太表面了,没有触及到本质,这些语法层面的东西,编译器想怎么解释想怎么处理都可以,问题是到了执行环境下,是什么一种状况?
int *p;
这就会分配内存了
&p
这只能作为rvalue,编译器直接计算,不会因为一个“取址”操作而为它分配空间,这是本质的区别吧


呵呵。。觉得你所讲的,有些含混。

撇开它们,我再澄明两点:

(1)许多人所谈到的“取址”操作,往往得到的是指针。

(2)指针不是地址!指针与生俱来地携带着数据类型信息(这个信息对于指针加减法来说,至关重要),地址则完全没有。

另外
int a[5];
assert(a == &a);
怎么解释
(&a) + 1
又怎么解释


在这样的例子中,“取址”表达式(姑且还这麽叫)
  1. &a
复制代码
帮助程序得到一个指向数组a的指针,而非指向其元素a[0]的指针。

一个指向数组a的指针 —— 即 int(*)[5] 类型(而不是int*类型),这意味着,该指针天然地携带着由声明
  1. int a[5];
复制代码
所呈明的 数组元素数据类型信息(int) 和 数组规模信息(5)。

继而,表达式
  1. (&a) + 1
复制代码
如果从地址偏移来说,是得到了一个“于数组a的基地址之上偏移5个int单位尺寸”的地址。

按你们那种表面理解,根本解释不了


不是“表面理解”啦,这就是语言特性或语言规范的简单事实而已。

呵呵,仅供参考 —— :)




论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
19 [报告]
发表于 2012-12-26 21:43 |显示全部楼层
sqfasd 发表于 2012-12-26 21:25
回复 101# lin5161678

您还没解释,a == &a呢
参照91楼和98楼的观点,能解释吗
  1. a == &a
复制代码
The Warning says it all.....

编译器会先抱怨你一下,然后,它还是默默流泪地满足你的欲望。。。。。。

呵呵。。。。


论坛徽章:
11
摩羯座
日期:2013-09-16 11:10:272015亚冠之阿尔萨德
日期:2015-06-12 22:53:29午马
日期:2014-04-15 11:08:53亥猪
日期:2014-03-02 23:46:35申猴
日期:2013-12-06 22:07:00亥猪
日期:2013-11-28 12:03:13双鱼座
日期:2013-11-21 14:43:56亥猪
日期:2013-10-23 10:55:49处女座
日期:2013-10-17 18:15:43午马
日期:2013-09-27 17:40:4215-16赛季CBA联赛之青岛
日期:2016-06-22 00:45:55
20 [报告]
发表于 2012-12-28 12:12 |显示全部楼层
lin5161678 发表于 2012-12-26 21:13
int a[5];
&a+1
这个a的数据类型是int[5]
&a是 int(*)[5]
&a+1就是 +sizeof(int[5])
为什么解释不了
不止能解释 还能解释得很清楚


好! 顶一下:)
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP