C字符串
2016-09-08
字符串字面量
所谓的字符串字面变量就是用一对双引号括起来的字符序列。例如 “abc” ,就是一个字符串字面变量。
字符串字面量的存储
C语言把字符串字面变量当做字符数组来处理,所以是利用数组来存储的。结尾元素都是’\0’.
字符串字面量的操作
通常情况下可以再任何C语言允许使用 char* 指针的地方使用字符串字面量。例如:
char *p;
p = "abc";
这个赋值操作不是复制”abc“中的字符,而仅仅是使p指向字符串的第一个字符。
C语言允许对指针添加下标,因此可以给字符串字面量添加下标:
char ch*;
ch = "abc"[2]; // 输出结果c
注意: 允许改变字符串字面量中的字符,但是不推荐这么做:
char *p = "abc";
*p = 'b'; /* string literal is now "bbc" */
对于一些编译器而言,改变字符串字面量可能会导致程序异常。
字符串变量
初始化字符串变量
可以利用一下几种形式:
char str1[] = "huhuhaha";
char str2[8] = {'h','u','h','u','h','a','h','a','\0'};
字符数组与字符指针
一下两种方法创建的字符串:
char date[] = “June 14”; char *date = “June 14”;
不能错误的认为上面两种date可以互换,两者之家有显著的差异:
- 在声明数组时,就像任意数组元素一样,可以修改存储在date中的字符。 在声明为指针时,date指向字符串字面量,是不可以修改字符串字面量的。
- 声明为数组时,date是数组名。声明为指针时,date是变量,这个变量可以再程序执行期间指向其它字符串。
如果需要可以修改的字符串,那么就要建立字符数组用来存储字符串。这时声明指针变量是不够的,下面的声明使编译器为指针变量分配了足够的存储空间:
char *p;
此时,它不为字符串分配空间。在使用p作为字符串之前,必须把p指向字符数组。如果不初始化,那么我们就不知道它指向了哪里,可能会对程序产生无法预期的影响。
字符串读写
写字符串-printf,puts
printf函数会逐个写字符串中的字符,直到遇到空字符才停止,如果空字符丢失,pringf函数会越过字符串的末尾继续写,知道最终在内存的某个地方找到空字符为止。如果只显示字符串的一部分,可以使用转换说明 %.ps, 这里的p是要显示的字符数量.
char str[] = "Are we having fun yet?";
printf("%.6s\n",str); // 结果: Are we
puts函数只有一个参数,此参数就是要显示的字符串。 puts(str); 在写完字符串后,puts函数总会添加一个额外的换行符。
读字符串-scanf,gets
scanf函数读入字符串永远不会包含空白字符。因此scanf通常不会读入一整行输入。换行符会使scanf函数停止读入,空格符和制表符也会产生同样的效果。
读入一整行数据使用gets函数。gets函数和scanf函数有以下区别:
- gets函数不会再开始读字符串之前跳过空白字符,而scanf会跳过。
- gets函数会持续读入直到找到换行符才停止,而scanf会在任意空白字符处停止。
字符串库
声明在
strcopy函数
函数原型如下:
char *strcpy(char *s1, const char *s2);
strcpy函数把字符串s2复制给字符串s1 。 也就是说,strcpy函数把s2中的字符复制到s1中直到遇到s2中的一个空字符为止。strcpy函数返回s1。因为不会改变s2指向的字符串,因此声明为const 。
大多数情况下会忽略掉strcpy函数的返回值。但是,有些时候,返回值会比较有用。比如,strcpy函数的调用作为较大表达式的一部分时,使用函数的返回值就非常有用。
strcat函数
函数原型如下:
char *strcat(char *s1,const char *s2);
strcat函数把字符串s2的内容追加到字符串s1的末尾,并返回字符串s1.
strcmp函数
函数原型如下:
int strcmp(const char *s1,const char *s2);
strcmp函数比较字符串s1和字符串s2,然后根据s1是否小于、等于、或大于s2,函数会返回小于、等于、或大于0的值。
类似于字典中单词的编排方式,strcmp函数利用字典顺序进行字符串比较。当比较两个字符串中的字符时,strcmp函数会查看表示字符的数字码。一些底层字符集的只是可以帮助预测strcmp函数的结果。下面是strcmp函数会遵循的一些规则:
- 所有大写字母都小于所有小写字母。(在ASCII码中,65~90的编码表示大写字母;97~122的编码表示小写字母)。
- 数字小于字母(48~57的编码表示数字)。
- 空格符小于所有打印字符(ASCII码中空格符的值是32)。
strlen函数
函数原型如下:
size_t strlen(const char *s);
strlen函数的作用是求字符串长度。size_t是无符号整数类型。strlen函数返回s中第一个空字符前的字符个数,但不包括第一个空字符。
字符串惯用法
处理字符串的函数是特别丰富的惯用法资源。
搜索字符串的结尾
许多字符串操作需要搜索字符串的结尾。strlen就是一个重要例子。下面我重写一下strlen函数:
size_t strlen(const char *s)
{
size_t n = 0;
for(; *s != '\0';s++)
n++
return n;
}
以上能正确的返回字符串s的长度。但是条件 *s != ‘\0’ 与 *s != 0 是一样的,因为空字符的ASCII码值就是0. 但是测试 *s!=0 与测试 *s 是一样的,两者都是在 *s不为0时结果为真。所以以上程序可以改写成如此:
size_t strlen(const char *s)
{
size_t n = 0;
for(; *s ;s++)
n++;
return n;
}
用while语句替换for语句,可以得到如下版本的 strlen函数:
size_t strlen(const char *s)
{
size_t n = 0;
while(*s++)
n++;
return n;
}
虽然已经对strlen函数进行了相当大的精简,但是可能仍没有提高它的运行速度,至少对于一些编译器来说下面版本确实会运行更快一些:
size_t strlen(const char *s)
{
const char *p = s;
while(*s)
s++;
return s - p ;
}
此版本的strlen函数通过定位空字符位置的方式来计算字符串长度,然后用空字符地址减去字符串中第一个字符的地址。
字符串追加
下面直接重写字符串追加的方法 strcat:
char *strcat(char *s1,const char *s2)
{
char *p;
p = s1;
while( *p != '\0')
p++;
while(*s2 != '\0'){
*p = *s2;
p++;
s2++;
}
*p = '\0';
return s1;
}
strcat函数的这种写法采用了两步算法:(1) 查找字符串s1末尾空字符的位置,并且使指针p指向它; (2)把字符串s2中的字符逐个复制到p所指向的位置。
通过对比strlen函数所采用的方法,可以简化strcat函数的定义,得到如下写法:
char *strcat(char *s1,const char *s2)
{
char *p = s1;
while(*p)
p++;
while(*p++ = *s2++);
return s1;
}
int main(int argc,char *argv[])
{
char str1[] = "China";
char str2[] = "Zhejiang";
strcat(str1, str2);
printf("%s",str1);
return 0;
}