字符‘/0’和‘0’的区别
字符’0’对应的ASCII码为十六进制30;而’/0’即为ASCII码中的0,其对应字符空字符NUL。
char c = ‘/0’;çèchar c = 0 // NUL
char c = ‘0’;çèchar c = 48;
最典型如memset函数:void *memset( void *buffer, int ch, size_t count );
将一段长为count字节的内存块初始化为ASCII码值0,字符为NUL:
memset(pBuffer, ‘/0’, sizeof(pBuffer) );çèmemset(pBuffer, 0, sizeof(pBuffer) );
字符串
字符串常量是双引号括起的任意字符序列。
例如:“Hello World”,”Fantasy”,”Please enter your full name:”,……
C语言没有专门定义字符串数据类型(如其他语言中的string) ,所谓的字符串,只是对字符数组的一种特殊应用而已,它用以‘/0’结尾的字符数组来表示一个逻辑意义上的字符串。
在字符串常量中,显然不能直接写双引号,因为这将被认为是字符串的结束。转义序列在字符串常量中要包含双引号,需要用“/””表示。如:”Hello /”Accp/””
与字符数组不同的是:在存完字符串常量的所有字符之后,还要另存一个空字符’/0’作为结束的标志,空字符是ASCII码值为0的字符,C语言中用’/0’标识字符串的结束,所以也称为结束符。如果在程序里写了字符串:char hello[]=“HELLO”或{ “HELLO”};虽然只有5个字符,在内存中却需要占用6个字节存储,其中’/0’表示空字符。存储情况如:
H | E | L | L | O | /0 |
5005 | 5006 | 5007 | 5008 | 5009 | 500A |
而字符数组char hello[]={ ‘H’,‘E’,‘L’,‘L’,‘O’};的长度和大小则为5.
根据字符串存储形式的规定,只要在数组里顺序存入所需字符,随后存一个空字符,这个字符数组里的数据就有了字符串的表现形式,这个数组也就可以当作字符串使用了。分析char str[]=“abc”;因为定义的是一个字符数组,所以就相当于定义了一些空间来存放”abc”,而又因为字符数组就是把字符一个一个地存放的,所以编译器把这个语句解析为char str[3] = { ‘a’,‘b’,‘c’};根据上面的总结,所以char str[]=“abc”;的最终结果是char str[4] = { ‘a’,‘b’,‘c’,‘/0’};即char str[] = { ‘a’,‘b’,‘c’,‘/0’}<==> char str[]=“abc”
值得注意的是只有在程序中对字符串进行处理时,才考虑字符串结束标志的问题。考虑字符数组char a[4]={ ‘B’,‘O’,‘Y’,‘/0’};a数组中存放的是字符串“BOY”。如果执行语句a[1]= ‘/0’;后,a数组的内容为‘B’,‘/0’,‘Y’,‘/0’。此时系统认为a数组中存放了一个字符串“B”,printf(“a=%s/n”,a);输出的结果是a=B; printf(“length a=%d/n”,strlen(a))输出的结果是length a=1, 而printf(“sizeof a=%d/n”,sizeof(a));输出结果为4.不要认为数组中只有‘B’和‘/0’了,只不过按系统对字符串的处理方式来看就是这样的。
char s3[10]=“HELLO”;//s3是编译期大小已经固定的数组
int a=strlen(s3); //a=5;//strlen()在运行起确定
int b=sizeof(s3); //b=10;//sizeof()在编译期确定
| sizeof(s) | strlen(s) |
char *s=“HELLO”; | 4 | 5 |
char s[]=“HELLO”; | 6 | 5 |
char s[10]=“HELLO”; | 10 | 5 |
注意printf(“hello is %s/n”,hello);和cout<<hello;以及头文件<string.h>中的库函数只能操作以‘/0’结尾的字符串,故对char hello[]={ ‘H’,‘E’,‘L’,‘L’,‘O’};操作无效。
以下为四种hello字符串的定义:
char hello1[]=“HELLO”;
char hello2[]={ “HELLO”}; //等同于hello1
char hello3[]={ ‘H’,‘E’,‘L’,‘L’,‘O’,‘/0’};//等价于hello1
char *hello4=“HELLO”;//区别:hello1是字符数组,hello4是字符指针。
用strlen函数测试hello1, hello2, hello3, hello4的结果均为5,因为不计末尾结束符’/0’。常用hello1或hello4来定义字符串。
字符串与指针
C语言中许多字符串的操作都由指向字符数组的指针及指针的运算来实现的。因为对字符串来说一般都是严格顺序存取,使用指针可以打破这种存取方式,使字符串的处理更加灵活。
以下代码利用指针简洁的实现了字符串拷贝函数:
void strcpy(s,t)//copy t to s
char *s,*t;
{
while(*s++=*t++);
}
解析:*s++=*t++,先赋值*s=*t,然后指针后移t++,s++,当遇到*t= ‘/0’时,则拷贝操作完成。
char *pChar;
char *text = “hello”;
pChar = new char[strlen(text) + 1]; // 注意这里考虑终止字符!
cout << strcpy(pChar, text) << endl; // 不能用pChar = text;
cout << (strcmp(pChar, text) == 0) << endl; // 不能用pChar == text;
字符串常量
当一个字符串常量出现于表达式中时,它的值是个指针常量。编译器把这些指定字符的一份拷贝存储在内存的某个位置,并存储一个指向第一个字符的指针。
“xyz”+1;//这个表达式计算“指针值加上”的值,返回一个指针,指向字符串中的第二个字符‘y’
*“xyz”;//返回第一个字符‘x’
“xyz”[2];//返回第三个字符‘z’
*(“xyz”+4);//偏移量超过了这个字符串的范围,返回一个不可预测的字符
那什么使用会用到上述表达式呢?我们考虑把二进制转换为字符并把它们打印出来。
remainder = value % 16;//value对求余保存到remainder中
if(remainder < 10)//0~9
putchar(remainder + ‘0’);
else10~15
putchar(remainder – 10 + ‘A’);
下面的代码用一种不同的方法解决这个问题:
putchar(“0123456789ABCDEF”[value % 16]);
参考:
《指针》
《数组与指针》