皮拉夫大王编程 2019-09-03 17:15:00 字符数组现在让我们把已经习惯的int型数组转换为char型。一般来讲,char型数组通常是用于'a', 'b', 'c', 'd'这类具有可读性的字符。在《类型与变量》一节中讲过,char类型的数据占用1个字节的存储空间,本质上它是一种小整型类型。这表明char型数组也可用来处理数据,如保存一张图像的像素值,保存接收到来自服务器的回复信息等。随着以后对指针的深入理解,我们会对此有更深的见解。此时,我们只用它来处理可阅读字符。 首先,让我们尝试输出"hello"这个字符串,不同的是,这次是使用数组输出。 为了明确的看到各种输出之间的不同,我以大写串END_STR来标识当前输出的结束。
分析后两项输出最后两个"hello",我们都是使用printf函数加%s格式符输出,为什么最后一个乱码了?最明显的不同之处在于数组的定义。str2的最后一个字符是'\0'值,而str1没有这个值。这说明这个'\0'有特殊意义。 我们知道数组传递给函数时,会转换为对应的指针类型,也就是说str2、str1传递给printf函数时,实际会形成类似printf( char *str )形式。回想一下计算数组平均值的函数,对于传递数组的函数,除了数组变量本身外,通常还需要一个int变量以指明数组元素的个数。而我们把str2,str1传递给printf函数时,并没有给定元素的个数! 但是由于str2具有特殊标记'\0',%s格式符对于该字符数组输出了正确值,但str1却没有这么幸运,它乱码了!这就说明了,'\0'指示了字符串的结束,如同给函数间接传递了元素个数一般。实际情况也确实如此,当printf+%s输出char*类型时,碰到'\0'就认为字符串结束了。 '\0'结束字符串可以看到,"world"没有被输出,这表明C的字符串是以'\0'表示 “我的话讲完了”。 那'\0'到底是什么呢?咳咳~~,又到了说说ASCII码表的时候了!'\0'是一个转义字符,它代表的是ASCII码值为0的值,也是ASCII码表中的第一个值,在C语言中用于表示字符串结尾标记。 注意数值0与字符'0'是不同的概念,字符'0'可以理解为是书写上用于交流0值的0。 动手试一下现在你可以尝试将第一个'\0'变为数值0,你会发现得到同样的输出。再尝试将0变为字符'0',再次观察输出并思考一下。假如你一直跟随我们的教程在学习,还是有点紧张你会用什么样的方式来完成这个试验呢?我们已经学习过数组的基础操作,希望你能使用下标运算符去修改数组中的某个值,而不是把代码拷贝多份...... 让生活再简单点假定你现在在编写一款RPG游戏,主人公有千言万语要向玩家诉说。基于现在所掌握的知识,把每个字符用单引号括起来并放到数组中,那简直就是噩梦!好在你的担心是多余的,你发现的问题,语言的设计者已经解决了,那就是使用char*指向常量字符串! 与单个字符赋值到数组相比,这种方式真的是轻松多了,而且也具有更好的可读性。这个程序会完整的输出"hello, world!",也不会出现乱码。这就表明,以这种赋值方式保存的字符串,语言自身会在结束加上结束标记。 这就是C风格的字符串,以0结束。 在这种形式下,你可能想要尝试修改一下某个字符,如hw[0]='a',程序可以编译过去,但执行会出错。这是因为"hello, world!"是字面常量,确切的说是常量字符串,是不可修改的。(在古老的编译环境下可能是正确的,如VC++6.0。另外,我们的声明还可以更加精确一些,使用const chr *hw代替会更好一些,由于目前没有学习const的意义,所以先不加;如果使用的是vs2017之类的编译器,这里的声明估计有问题。) 详细的说,可以这么理解:想像一下,不管是变量还是常量,总要有能存储这种东西的地方,这地方就是内存,是内存就有地址,对于常量存储区域,具有不可写标记(即只读)。hw仅是一个指针,指针的有效性就是指向一个地址,当为hw赋值后它就指向了这个常量地址,因此编译时是成功的。当使用下标修改时,系统发现你想要修改只读内存,然后被无情打脸。 你可能会抱怨,如果我真的想要修改字符串该怎么办?1:把常量字符串转换为数组。2:使用动态内存分配。作为练习,你可以基于现有的知识,尝试按自己的思路去实现方法1。当然,这些知识在后续的教程中也会一一道来。 |
|