C字符数组和C++字符串
1 所有字符串均以 '\0’ 结尾
在C语言当中,所以的以双引号括起来的字符串的末尾都默认加上了一个 \0.
如 "abcde” 实际上是 abcde\0 .
\0 表示了一个字符串的末尾,实际也占用了一个字节.
要注意的是,只有在字符串中才会默认加上 \0,如 'a' 像以单引号括起来的单个字符的后面是不会加 \0 的,而 "a" 这样用双引号括起来的不管是一个字符还是几个字符,都会加上 \0
2 ‘ 单引号 与 " 双引号表代表的值
char ch = ‘A’; 其中 用 ' 单引号括起来的,实质上其实是代表的一个范围为0~255的整型数据,这个整型值对应着其字符在ASCII码中所对应的整型数据.char 也是一个整型数据,和其它整型数据不同的是,char 数据默认是无符号的,占用1字节,数据大小范围是0~255.列如 char ch = 65; 在这里我们可以直接将一个整型数据赋值给 char 类型变量 ch.如果我们用printf(“%c\n”, ch); 那么不管是赋给ch的是 'A' 还是 65(65 在ASCII码中对应了字符 大写字母A),输出结果都是 A.当然我们也用%d以整型数据输出它.
#include <stdio.h> int main(void) { char a = 65; char b = 'A'; printf("%c, %d\n", a, a); printf("%c, %d\n", b, b); return 0; } /* 参考输出结果: A, 65 A, 65 */
char *string = “abcd”; 其中,我们可以将 "abcd" 赋值给一个字符指针的原因是: 以双引号括起来的字符串,整个表达式的值是一个指针.在这个语句中,字符串 abcd\0 是一个常量.在程序运行的时候会自动判断内存中是否已经存放了 abcd\0 这个数据,如果存放了双引号表达式就代表了字符串中第一个元素的地址,没有存放则创建.所以 "abcd" 这个双引号表达式代表的指针就指向了字符串中的第一个元素 a.因为字符串 abcd\0 是一个常量,所以我们不能通过 string 去修改它的值,但是我们可以去修改 string 指向的地址,如: string = “efg”; 这里的 "efg" 和 "abcd" 是同一个概念.
#include <stdio.h> int main(void) { char *str = "abcd"; printf("%s, %#x\n", str, str); return 0; } /* 参考输出结果: abcd, 0x40c000 */
3 char[] 字符数组
char string[5] = “abcd”; 这个语句表示的是将常量 abcd\0 复制到所分配的5字节内存空间中去,与char *string = “abcd”;不同之处就在于,前者是将一个内存区域中的数据复制到另外一个内存区域里去,后者是定义一个指针让它指向了这一个内存区域.
深入了解过数组的朋友应该也知道,不管是什么数组,定义的数组名其实都是一个指针.不过这个指针不同于普通指针的是,这一个指针指向的地址不能被改变,指针string是一个常量.这个指针指向了数组的第一个元素,程序以这一个指针来找到整个数组.在 char string[5] = “abcd”; 中,string 就指向了第一个元素的地址,也就是 abcd\0 中 a 的地址.
即使我们能够改变 string 的值也是不合理的,因为 string 指向的不是常量区的 abcd\0 ,而是程序自己分配了内存空间存入了的 abcd\0 指针,如果我们修改 string 的值,我们就无法找到这个字符串变量所在的内存地址了.而我们如果不调用外部函数要改变一个char [] 字符串的值的话,就只能通过下标来一个一个修改每一个字符的值从而修改整个字符串,如: string[0] = ‘e’; string[1] = ‘f’; …… 当然如果这样修改起来将会非常的繁琐,所以我们可以用到一个C语言中给我们提供的用于 char 字符串复制的函数: strcpy.
strcpy 函数原型:char *strcpy( char *strDestination, const char *strSource );
参数1:strDestination 指向目标字符串的首地址;
参数2:strSource 指向源字符串的首地址.
返回值:返回指向 strDestination 的指针.
对于数据类型 const char * 的讲解可见下一章.
这个函数的功能就是将 strSource 中的数据复制到 strDestination 中,其返回值我们一般用不到,可忽略.这个函数的功能等价于 char string[5] = “abcd”; 中的 = 号,而与这整个语句不同的是,strcpy 不会分配新的内存空间.
函数使用示例: 改变 string 的值为 efg:
strcpy(string, “efg");
更多的 char 字符字符串操作函数可以查阅 MSDN-String Manipulation Routines
char 数组的性质和其它数据类型的数组一样,也可以通过一个指向第一个元素的非常量指针进行递增从而修改元素的值:
char string[5] = “abcd”; char *pChar = string; *pChar = ‘e’; // 修改第一个元素 *(++pChar) = 'f'; // 修改第二个元素 这里的括号可有可无,只是为了观察方便
5 const char * 与 char *const
const char * a; 这个语句定义了一个常量指针 a,也就是指向常量的指针,意思是说不能通过 a 修改它指向内存地址中的值.要注意这里是不能通过 a 修改它指向地址中的值,并不代表 a 只能指向常量而不能指向变量.只是 a 指向了变量之后,不能通过 a 去修改这个变量的值.另外 char const *a; 语句,与其等价.
char *const b; 这个语句定义了一个指针常量 b,也就是一个指针的常量,意思是说 b 是一个常量,b 的值不能被改变,即 b 的指向的地址不能被改变,可以通过 b 去修改它指向内存中的值.这里同样要注意, b 可以指向常量也可以指向变量,只是说 b 指向谁是不能被改变的.而如果 b 指向了一个常量,那么当然通过 b 去修改这个常量的值还是错误的.因为这里定义的是一个常量的变量,所以必须在定义的时候就给赋值.
const char *a = "abcd"; // OK char str[5] = "abcd"; // OK char *const b = str; // OK const char *c = str; // OK a = "fff"; // OK *a = 'f'; // error 不能通过 常量指针 a 修改它指向内存地址中的值 b = "abcd"; // error 指针常量 b 是常量,不能被改变 *b = 'f'; // OK *++b = 'f'; // error ++ 自增会对指针常量 b 的值进行更改 b[1] = 'f'; //OK *c = 'f'; // error 不能通过常量指针 c 修改它指向内存地址中的值,尽管它指向的内存地址中的数据是变量
如果我们要使用 malloc 函数来为一个数组分配内存空间,并且让它和直接定义一个数组一样,指向第一个元素的指针的值不能被改变,那么我们就可以这样来定义:
char *const string = (char *)malloc(5);
6 字符数组和字符串
C字符串定义时可以利用"="号进行初始化,但是以后不能利用"="对C字符串进行赋值。对C字符串的操作需要通过"string"文件中定义的字符串处理函数。
例如:
//字符串的初始化 char a[11] = "huanying"; //字符串的赋值 strcpy(a,"nihao") //获取字符串的长度,不包括'\0'在内 strlen(a); printf("%s",a);
在C中也可以使用字符指针来访问一个字符串,通过字符指针指向存放字符串数组的首元素地址来进行访问.
char *a = "nihao";
printf("%s",a);
7 C++常用字符串函数
(1)串长度 int strlen(char *str)
cout<<strlen(s1)<<endl; 输出14
cout<<strlen(s2)<<endl; 输出7
(2)串拷贝 char *strcpy(char *str1,char *str2)
strcpy(s4,s2); //s4为"teacher"
(3)串连接 char *strcat(char *str1,char*str2)
strcat(s2,s3); //s2为"teacherstudent"
(4)串比较 int strcmp(char *str1,char *str) //比较的是对应字符的ASCII码值,如果str1>str2,返回1
result=strcmp(s2,s3); //result>0
result=strcmp(s2,s2); //result=0
result=strcmp(s3,s2); //result<0
(5)串定位 char *strchr(char *str,char ch)
p=strchr(s1,'s'); //找到返回字符在字串中的位置,否则返回-1
strcpy(p,s2); //s1为"I am a teacher"