字符串的复制、连接和比较及字符串的长度
字符串复制、连接、和比较以及计算字符串长度的函数,在系统头文件string.h中定义。所以在使用之前,需要先引入string.h头文件。
1、字符串复制函数 char *strcpy(char *s1, char *s2)
该函数把字符串s2复制到s1,直到遇到s2中 ‘\0’ 为止。s1要有足够的空间容纳s2,且s1中的内容被覆盖,函数返回s1。同样可以简化以上函数的表达形式为:strcpy(s1, s2);
参数s1必须是字符型数组基地址,参数2可以是字符数组名或字符串常量。 例如:
int i;
char str1[80], str2[80], from[80] = "happy"; /* 初始化数组from */
strcpy(str1, from);
strcpy(str2, "key");
上述代码中,第三条语句调用了函数strcpy()把from中的字符串复制给str1; 第四条语句把字符串常量“key”复制给str2后,数组str1中存放了“happy”,数组str2中存放了“key”。
2、字符串连接函数strcat(s1, s2)
参数s1必须是字符数组基地址,参数s2可以是字符数组名或字符串常量。 strcat()函数将字符串s2接到字符串s1的后面,此时,s1中原有的结束符 ‘\0’ 被放置在连接后的结束位置上。数组s1的长度要足够大,以便存放连接后的新字符串。例如:
char str1[80] = "hello ", str2[80], t[80] = "world";
strcat(str1, t);
strcpy(str2, str1);
strcat(str2, "!");
先调用函数strcat()连接str1和t,结果放在str1中。如下图:
在调用函数strcpy()将str1中的字符串赋给str2,最后调用函数strcat()连接str2和字符串常量 “!” 后,str2中存放了“Hello world!”。
C语言中不允许使用算术运算符加将字符串数组直接连接。即str1 = str1 + t是错误的。
3、字符串比较函数strcmp(s1, s2)
和函数strcpy()中对参数的要求不同,函数strcmp()中的参数s1和s2可以是字符数组名或字符串常量。函数strcmp()返回一个整数,给出字符串s1和s2的比较结果:
若s1和s2相等,返回0。
若s1大于s2,返回一个正数。
若s1小于s2,返回一个负数。
设str1和str2都是字符串,在C语言中,str1 == str2、str1 > str2 和 str1 <= str2比较的是两个字符串的起始地址,而strcmp(str1, str2) == 0、strcmp(str1, str2) > 0 和 strcmp(str1, str2) <= 0 比较两个字符串的内容。
字符串比较的规则是:从两个字符串的首字符开始,依次比较相对应的字符(比较字符的ASCII码),直接出现不同的字符或遇 ‘\0’ 为止。如果所有的字符都相同,返回0;否则,以第一个不相同字符的比较结果为准,返回这两个字符的差,即第一个字符串中的字符减去第二个字符串中的字符得到的差。例如:
strcmp("sea", "sea"); //值为0,说明“sea”, "sea"相等
strcmp("compute", "compare"); //值为('u' - 'a')是个正数,说明"compute"大于"compare"。
strcmp("happy", "z") //值为('h' - 'z')是个负数,说明"happy"小于"z"。
strcmp("sea", "seat") //值为('\0' - 't')是个负数,说明“sea”小于“seat”。
4、字符串长度函数strlen(s1)
参数s1可以是字符数组名或字符串常量。函数strlen()返回字符串s1的‘\0’之前的字符个数。即字符串有效字符的个数(不包括字符结束符’\0’)。
例如:strlen(“happy”)的值是5,strlen(“A”)的值是1。
字符串和字符指针
上面字符串都是以一维字符数组实现的。除了字符数组还可以使用字符型指针去接收字符串常量值。
如果定义一个字符指针接收字符串常量的值,该指针就指向字符串的首字符。这样,字符数组和字符指针都可以用来处理字符串。例如:
char sa[] = "array";
char *sp = "point";
printf("%s ", sa); /* 数组名sa作为输出参数 */
printf("%s ", sp); /* 字符指针sp作为输出的参数 */
printf("%s\n", "string"); /* 字符串常量作为输出的参数 */
运行结果如下:
调用printf()函数,以%s的格式输出字符串时,作为输出参数,数组名sa,指针sp和字符串“string”的值都是地址(起始地址),从该地址所指定的单元开始连续输出其中的内容,直到遇到 ‘\0’ 结束。因此,字符串中其他字符的地址也能作为输出参数。例如:
printf("%s ", sa+2); /* 数组元素sa[2]的地址作为输出参数 */
printf("%s ", sp+3); /* sp+3作为起始地址 */
printf("%s\n", "string" + 1);
运行结果如下:
字符数组与字符指针都可以处理字符串,但两者之间还是有区别的。例如:
char sa[] = "This is a string";
char *sp = "This is a string";
字符数组sa在内存中占用了一块连续的单元,有确定的地址,每个数组元素放字符串的一个字符,字符串就存放在数组中。字符指针sp只占用一个可以存放地址的内存单元,存储字符串首字符的地址,而不是将字符串放到字符指针变量中去。如图:
如果需要改变数组sa所代表的字符串,只能改变数组元素的内容。如果要改变指针sp所代表的字符串,通常直接改变指针的值,让它指向新的字符串。因为sp是指针变量,它的值可以改变,指向其他单元。例如:
strcpy(sa, "Hello");
sp = "Hello";
分别改变了sa和sp所表示的字符串。而sa = “Hello”; 是错误的,因为数组名是常量,不能对它赋值。
定义字符指针后,如果没有对它赋值,指针的值是不确定的,不能明确它指向的内存单元。因此,如果引用未赋值的指针,对指针指向的单元赋值会出现问题。例如:
char *s;
scanf("%s", s);
没有对指针s赋值,却对s指向的单元赋值。如果该单元已分配给其他变量,其值就改变了。
char *s, str[20];
s = str;
scanf("%s", s);
上述定义是正确的。数组str有确定的存储单元,s指向数组str的首元素,并对数组赋值。
为了尽量避免引用未赋值的指针所造成的错误,在定义指针时,可以先将它的初值置为空,如char *s = NULL。