免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 5296 | 回复: 21
打印 上一主题 下一主题

[C] 大家新年快乐啊,请教一个关于字符数组声明的问题(新手请教) [复制链接]

论坛徽章:
1
白羊座
日期:2014-03-22 18:23:03
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-01-04 22:49 |只看该作者 |倒序浏览
今天看书,看到一段代码,下面是其中的一个申明部分,是记录每月天数的表。
  1. static char daytab[2][13] = {
  2.     {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  3.     {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
  4. };
复制代码
一开始并没在意数组的类型以及数组中的元素类型,后来看到书上特意提了一下。
“这里之所以将daytab的元素声明为char类型,是为了说明在char类型的变量中存放较小的非字符整数也是合法的。”


恩,就是有点小疑问= =。。关于这个存放较小的非字符整数的合法性问题。= =。。各位怎么看。。= =

论坛徽章:
0
2 [报告]
发表于 2013-01-05 01:07 |只看该作者
简单来说,字符常量与整形等价。比如 'a' 就只是对某个 int 值的映射而已(通常是 97,也就是它的 ASCII 码)。

而且 char 的规定是要能表示「基本运行字符集」里的所有字符,只要那个「较小的非字符整数」在这个范围内就可以啊……

论坛徽章:
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
3 [报告]
发表于 2013-01-05 02:15 |只看该作者
本帖最后由 Ager 于 2013-01-05 21:55 编辑

楼主小弟新年快乐!

首先,这个问题跟声明无关。

在C语言中,char类型,是整数类型的一种。

假定在你的系统的某个C实现上面,一个char类型数据占用了1个字节的长度,即8 bits。

我们知道,在一个bit中的,要么是一个0,要么是一个1。

所以,8个bits组成的序列,可以表示2的8次方个不同位向量,即

0000 0000
0000 0001
0000 0010
……
1111 1110
1111 1111

一共256个。

那么,它们可以和256个整数一一对应。

即所有的char类型的数据所构成的集合中的元素,总可以和256个整数一一对应。

这256个整数,可以是[0,255],也可以是[-128,127],也可以是其他的整数集合。

在我的系统上,文件 /usr/include/limits.h 给出了本系统上某个C实现(GCC)的约定:
  1. /* Number of bits in a `char'.  */
  2. #  define CHAR_BIT      8

  3. /* Minimum and maximum values a `signed char' can hold.  */
  4. #  define SCHAR_MIN     (-128)
  5. #  define SCHAR_MAX     127

  6. /* Maximum value an `unsigned char' can hold.  (Minimum is 0.)  */
  7. #  define UCHAR_MAX     255

  8. /* Minimum and maximum values a `char' can hold.  */
  9. #  ifdef __CHAR_UNSIGNED__
  10. #   define CHAR_MIN     0
  11. #   define CHAR_MAX     UCHAR_MAX
  12. #  else
  13. #   define CHAR_MIN     SCHAR_MIN
  14. #   define CHAR_MAX     SCHAR_MAX
  15. #  endif
复制代码
注意上面最后一小节。其中的“__CHAR_UNSIGNED__”宏是否被定义,是由GCC根据我的机器(严格地说,是目标机器)的背景情况决定的(用户不可干预),当且仅当我的机器满足“char类型是一种符号的整数类型”这个背景条件时,这个宏将被定义。

在我这里,现场的实际情况是:这个宏没有被定义,即:作为GCC的目标机器,具有“char类型是一种符号的整数类型”的属性。

此时,我们回到上面那一个小节:因为“__CHAR_UNSIGNED__”宏没有被定义,则GCC将

“CHAR_MIN”宏定义为“SCHAR_MIN”宏,即整数-128。
“CHAR_MAX”宏定义为“SCHAR_MAX”宏,即整数127。

所以,在这个实现场合中,所有char类型的数据之集合中的元素,可以与[-128,127]这个整数集合中的元素一一对应。

或者,干脆直接说:char类型的数据之集合中的元素,是从-128到127这256个整数。

而当我们利用“字符常量”这种机制(特别注意:字符常量不是所谓的“char类型常量”,后者在C语言中是不存在的!)来为char类型的数据对象赋值的时候,一种“字符-整数”的对应关系,就是一个基本前提。


这种对应关系的法则,由不得你来决定,一般情况下,它会遵照绝大多数计算机基础教材的附录(通常是附录1或附录A,可见其基要性)中的《ASCII字符集》所揭示的字符与整数的对应关系。

比如:
字符'\0'对应且仅对应着整数0(十进制);
字符'\1'对应且仅对应着整数1(十进制);
字符'\2'对应且仅对应着整数2(十进制);
……
字符'\10'对应且仅对应着整数8(十进制) —— 可见,斜杠后面跟着的是一个八进制整数;
字符'\11'对应且仅对应着整数9(十进制);
……
字符'\r'对应且仅对应着整数13(十进制) —— 转义序列“\r”指代一个CR(Carriage Return)字符,即回车。回车字符的ASCII编码是13(十进制);
……
字符'\x10'对应且仅对应着整数16(十进制);—— 可见,斜杠与x后面跟着的是一个八进制整数;
……
字符'A'对应且仅对应着整数65(十进制)—— 字符A的ASCII编码是65(十进制);
字符'B'对应且仅对应着整数66(十进制);
……
字符'a'对应且仅对应着整数97(十进制);
字符'b'对应且仅对应着整数98(十进制);
……

这样的对应关系,实际上,就是将char类型的数据之集合中的[0,127]这个真子集中的元素,与[0,127]这个整数集合中的元素一一对应。

同样要特别注意的是:作为表达式的
  1. 'A'
复制代码
—— 其类型是int,而非char!


即“'A'”这样的字符常量,其数据占用的宽度与一个int类型数据所占用的宽度是一致的,通常是32bits,而不是8bits。
  1. char x;
  2. x = 'A';
复制代码
这样的赋值运算,蕴含了将一个通常为32bits的数据“截短”为8bits的数据的转换过程(这种情况是合法的)。

回到楼主的题目。。。

人类社会目前所最普遍使用的历法 —— 格列高利历(俗称公历),将一年分为12个月,并按照大体均等的原则规定了每个月的日子数,这个日子数不会超过31。

因为[0,31](本题额外多设了一个0)这个整数集合,是[-128,127]或[0,255]的一个真子集;或者,换一种看法:[0,31]这个集合中的任何元素,相对于它的超集中的最大整数即127或255来说,都是“较小的”,所以,[0,31]这个整数集合中的任何元素,都可以与char类型数据集合中的元素单射地对应。

简言之,0、28、29、30、31这五整数,完全可以用char类型来存储、读取和表达。

注意:在代码(数组元素的初始化部分)中出现的这些样式的整数(除了0之外),将被视为关于十进制常量的表达式,它们的类型是int,当然关于常量“0”的那个表达式,其类型也是int,所以,它们均占用了通常是32bits的长度。(这个“整数常量的代码被编译器解释/认可为int类型”的基本原则,请参见@KBTiller大虾的帖子:http://bbs.chinaunix.net/forum.p ... 55&pid=23746205

同前述之理,用这样的表达式为char[][]类型的数组之元素初始化,就会蕴含一个将数据“截短”为8bits的数据的转换过程(这种情况是合法的)。


综上所述,由这五整数构成的一个二维数组(2x13个元素),可以是static char [2][13]类型的。

以上,仅供参考,呵呵 ——:)

论坛徽章:
1
白羊座
日期:2014-03-22 18:23:03
4 [报告]
发表于 2013-01-05 09:42 |只看该作者
回复 2# timothyqiu

手机党飘过,谢谢一楼的哥们。清早过来看到这两个回复,感觉清楚明了多了。
   

论坛徽章:
1
白羊座
日期:2014-03-22 18:23:03
5 [报告]
发表于 2013-01-05 10:22 |只看该作者
回复 3# Ager

Ager哥新年快乐,嘿嘿。发现数据类型的确最麻烦,==。不过这到是第一次你的帖子我一次性看懂了,噗==。哈哈,谢咯。

论坛徽章:
0
6 [报告]
发表于 2013-01-05 15:12 |只看该作者
"非字符整数"的说法莫名其妙

论坛徽章:
0
7 [报告]
发表于 2013-01-05 15:16 |只看该作者
KBTiller 发表于 2013-01-05 15:12
"非字符整数"的说法莫名其妙


参见「非负整数」……

论坛徽章:
3
寅虎
日期:2013-11-27 07:53:29申猴
日期:2014-09-12 09:24:152015年迎新春徽章
日期:2015-03-04 09:48:31
8 [报告]
发表于 2013-01-05 16:00 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
9 [报告]
发表于 2013-01-05 17:12 |只看该作者
很简单撒,如果你把31改成3100,就会报一个warning了,一个溢出的警告。
因为char本身占用1个字节,即2的8次方,取值为0~256,如果你用3100就超过了他的范围了。
所以才有这个说法“较小的整数”也是合法的,而整数必然就称呼为“非字符”了

论坛徽章:
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
10 [报告]
发表于 2013-01-05 19:10 |只看该作者
本帖最后由 Ager 于 2013-01-06 01:02 编辑
KBTiller 发表于 2013-01-05 15:12
"非字符整数"的说法莫名其妙


考虑到提设的巧妙 —— [0,31]这个整数集合(含32个整数),以ASCII编码看来,恰巧是“控制字符(Control Character)”区间。

控制字符,也叫“非打印字符(Non-Printing Character)”,它们不仅是“不可见的”,而且是可以用来操控终端设备的(最早是操控TTY即电传打字机的)。

经常接触终端的用户,大多都有这种经验:在由“可见字符”组成的序列中,搀杂控制字符,很可能导致打印(显示)的混乱。

所以,一些用户对控制字符,是敬而远之的。

或许,他们有“将控制字符保存进char类型的对象中会导致数组元素序列混乱”的顾虑。

而作者在这里所说的“在char类型的变量中存放较小的非字符整数也是合法的”,应该就是为了破除这种顾虑。


这里的“非字符”,应该就是指控制字符(作者在这个语境中,将不可见字符当作“非字符”看待)。

而这里的“较小的”一词,应该是对于“非字符整数”本身的描述(即“非字符整数”在整个ASCII字符集当中,是“较小的”),而不是一个限制性定语(指整个“非字符整数”集合中“较小”的那个部分)。

讲到这里 —— 一个颇为微妙的事情,似乎呼之欲出 ……

我们注意到:在ASCII字符集中,控制字符(除了DEL字符)全部位于前32个(即从0到31)。

32这个数字,是2的一个正整数次幂,即2的5次方。

而大多数历法中的一个月的日子,都在30附近 —— 这是因为月相的变化周期(即朔望月)是大约30天左右,所以叫“月(Month/Moon)”。

也就是说:

朔望月的长度,是“一天”长度的约30倍。

“一天”传统上都是基于“视太阳”的“太阳日”,即地球相对于“视太阳”自转一周的时间(不同于地球“自己”相对于遥远恒星的自转一周的时间),也就是观测地的一个正午到下一个正午(可以藉由日晷测量)的时间。

而我们今天普遍使用的格列高利历(俗称公历),遵守“以太阳回归年为一年”的原则。(太阳回归年:在地球看来,太阳从黄道上的一点再回到该点的周期。)

可以藉由观测得知,一个太阳回归年大约是365.24个“太阳日”,这就使得:我们公历的一年有365日或置闰的366日。

公历将它的“年”与传统的朔望月相调和,就使得:公历需要有12个月,且每个月的日子数在30或31附近。

30或31这个数,和2的5次方即32,非常接近,我并不想武断地下一个“这不是巧合”的结论,但是,这是否能揭示一些群族将二进制/八进制/十六进制/三十二进制作为历法基础的可能性?

不过,这还得和中国传统巫术文化如《易》中所体现的所谓“二进制思想”、“八进制思想”或“六十四进制思想”区别开来。

我的意思是:朔望月相对于太阳日的倍数(大约是30)—— 即太阳-地球-月球三天体的运动关系,是否可以用“2正整数次幂之进制”的计数法来*解释*?

我觉得,这种希望非常渺茫。上述天体的运动关系,倒是揭启了人类对于“12进制”、“60进制”和“360进制”的自觉运用,但却不是二进制/八进制/十六进制/三十二进制。

那我们调转方向,查考一些“非主流”民族的计数制/进位制。

比如,把全人类“折腾”了一番的玛雅民族(和他们的历法)。

玛雅民族(玛雅文明)的计数制/进位制和他们的历法(即对天体运行规律的揭示)是分不开的。

玛雅文明普遍采用18进制和20进制(已经可以注意到:18与20的乘积是360)。

20进制,基于玛雅文明的每个月份的日子数,即他们的一个月有20天。

为什么他们的一个有20天,而不是30天?

因为玛雅人采用双手双脚的指/趾端数总和,即20,来作为他们计数的基本基数。

而他们倚靠对金星的观测,来确定太阳年。这个单位太阳年的长度是365天多一点。

在晚上欧巴桑没有电视可看、屌丝没有网可上、美白富没有夜店可泡、仰望星空时也没有大气污染和光污染干扰的古代玛雅人看来,金星是夜晚天空中亮度仅次于月亮的天体。(有人藉此来佐证“古代玛雅时期,月球尚不存在”,这真是匪夷所思、令人难以置信!)

玛雅文明利用太阳-地球-金星三天体的运动关系,确定了他们的历法。在一个月有20天的情况下,为了调和约365天多一点的太阳年,就要把一年分为18个月或置闰的19个月(第19个月很短,只有5天多一点)。

这样,我们就不难理解,玛雅文明采用了18进制和20进制的计数法。

那么 …… 采用基于二进制/八进制/十六进制/三十二进制的历法的“民族”,恐怕仅仅存在于计算机世界里了,呵呵 …… {:3_185:}

以上,仅供参考,呵呵 —— :)

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP