分享
 
 
 

小议char *和C语言的字符串

王朝c/c++·作者佚名  2006-04-22
窄屏简体版  字體: |||超大  

作者:乾坤一笑

来源:http://blog.vckbase.com/smileonce/archive/2005/06/26/8330.html

摘要:介绍了C语言中的char *和字符串,比较深入

前几天和清风雨交谈strncpy()函数的时候,他认为“如果一个函数有一个char * str的参数,那么str一定是一个字符串”,而我对此不以为然。难得到了周末,抽得出功夫,谈谈我对char *含义的认识,与大家共同讨论一下。

C语言是开发操作系统的首选语言,在很多方面都能从C代码中看到机器的固有性质。比如,PASCAL语言的数组索引是从1开始计数,而C语言就是从0开始计数。从0开始计数不太符合一般人的正常思维模式,但是为什么C语言要采用这种设计方式呢?因为C语言最初主要是为操作系统开发人员和编译器设计人员设计的——对于经常需要考察内存地址的开发人员,偏移量的概念在他们脑子里面根深蒂固。要把100个int型的整数放在从地址0x0000开始的一段内存中,如果系统是按Byte编址的,那么第100个元素(其数组索引为99)的要放入的地址必然是:0x0000 + sizeof(int) * 99, 而不是乘以100,所以索引以0开始是很有好处的。(C语言的底层特性请参考P.V.D.L的《Expert C Programming——Deep C Secrets》,中文版《C专家编程》)

同样而言,C语言对所谓字符串的处理也和其他语言不同。(参见拙著《我用错了strcat() 》文后的评论) 它同样体现了便于系统设计的特点。例如unix系统总是把设备都映射为文件,对I/O流、光驱、硬盘、modem的访问最终都转换为了对文件的处理。而文件,也可以看作是一个长长的字符数组(文件以EOF结尾)。C语言没有专门定义字符串数据类型(如其他语言中的string),它用以'\0'结尾的字符数组来表示一个逻辑意义上的字符串。C语言用一些对于字符数组的处理函数(特别是对以'\0'结尾的字符数组的处理函数)来处理所谓的以'\0'结尾的字符串,并把他们放在string.*、stdio.*等一些标准库文件中。string这个字眼也就对人造成了某些误解,好像是C语言中定义了字符串这种类型一样。其实C语言只定义了char、int、float、void、poiner这几种基本类型,这正是C语言简洁之处。至于所谓的字符串,只是对字符数组的一种特殊应用而已。

由于没有了“字符串类型”,“传char *参数就是传一个字符串进来”之说自然也不攻自破。那么char *真正的含义是什么?我们不妨用大家最熟悉的int来对比一下。

#include <stdio.h>

int main(int argc, char *argv[])

{

int b[3] = { 17, 18, 19 };

int a = 5;

int d = 2103157716;

int * i; // pay attention to this variable

i = b;

printf("%d \n", *i); // i points to a array, *i gets the first number of the array,

// *i does not get the all elements of the array.

i = b + 1; // okey, i can get whichever element of the array.

printf("%d \n", *i);

printf("Int size: %d \n", sizeof(int));

printf("Address0: %#x \n", i); // if i++, the value of i add by sizeof(int)

i++;

printf("Address1: %#x \n", i);

i = &a; // i also can point to a int variable. as i is a pointer, we shoule

printf("%d \n", *i); // use & to get the address of a.

printf("%#x \n", d); // I use a big number to prove that int * is only a pointer,

i = &d; // which is not tightness to int type.

printf("%#x \n", *((unsigned char*)i));

return 0;

}

代码中的int * i就是我们关注的焦点。它是一个指向int指针。也就是说:i指向一个内存地址,从这个地址开始存储了一个数据。int * i中的int标明应该使用int类型(长度为sizeof(int)个字节)来从这个地址取数据,也就是说要一次取sizeof(int)个byte的数据来拼成最后的结果。最后一个例子也证明了这一点:如果我们强制用unsigned char的大小的数据类型来对这个地址操作,就只能取出数据的一部分。反过来说,如果用较大数据类型来取实际存储较小数据类型的数据,就有可能越界操作内存,取回一些杂乱的内容或导致系统崩溃。int b[]这个数组,标明有一组数,放在以&b开始地址的内存空间内,每个元素占用了sizeof(int)个byte的内存单元;如果有类似于i=&b;i++;的操作,i的值就每次递增sizeof(int)而不是1,这样确保了i每次都能恰好取回一个正确的int。

同理,char * c也是如此。如果我们定义了一个char *的变量c,那么c也只不过是一个指向内存中某个地址的指针而已。之所以标明它是char *的类型,就是说要以sizeof(char)为单位去内存中取数。所以,我们应该称呼char * c为指向char类型的指针——而不是说c就是字符串。为什么传一个char *指针给printf(),strlen()之类的函数,它就能把它当作一个字符串来处理呢?没错,我们不是定义了'\0'来表示一个"字符串"的终结么?我们只需从起始地址不断累加,遍历字符数组的每一个元素,直到找到一个'\0'为止,就算是处理一个字符串了——从起始地址到'\0'为止的字符数组元素构成一个“字符串”,这就是C语言设计字符串的原理。

所以,当一个函数要求传入一个char *的参数,并不一定这个参数就一定是字符串(以'\0'结尾的字符数组),char *只是一个字符指针而已,它仅仅提供了一个内存地址和每次遍历元素的偏移量而已。究竟函数对传入的参数有什么要求,还要视函数的具体实现而定。(我想ANSI C应该对参数有所要求和规定,可惜偶没有ANSI C文件,无法参考。 )C语言一般约定是用char * str来表示以'\0'结尾的字符数组,但是由于某些实现上的效率的考虑,往往没有严格遵守这个约定。C语言的设计理念中没有强调使用者一定要使用遵守这个约定,不遵守这个约定也不违背C语言的基本语法规则。这或许可以看作是C语言和创造和使用它的黑客群体崇尚自由的一种特色、一种精神文化吧。

小练习:

1)参照上面int *的例子来编写一个类似代码验证一下char *是否也有类似特性。

2)C语言这么设计字符串会在那些方面的处理上有为难之处。

3)考察C语言标准库函数中,有那些函数传入char*的参数是一定要求以'\0'结尾的,那些函数对char *参数不做这个检查。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有