第十一章 字符串和字符串函数
11.1 字符串表示和字符串I/O
字符串是以空字符(\0)结尾的char数组。
11.1.1 初始化
一、字符串常量
字符串常量又称字符串文字,是指位于一对双引号中的任何字符。双引号里的字符会加上编译器自动提供的结束标志\0字符,作为一个字符串被存储在内存里。
如果字符串文字中间没有间隔或者间隔的是空格符,ANSI C会将其串联起来。
例如 char get[50]="How are" "you";和 char get[50]="How are you";等同
如果想在字符串中使用双引号,可以在双引号前加一个反斜线符号。
字符串常量属于静态存储类,即在一个函数中多次调用这函数,该字符串在程序的整个运行过程中只存储一份。
二、字符串数组及初始化
指定数组大小时,一定要确保数组元素数比字符串长度至少多1。未被使用的元素均被自动初始化为0。(是\0而不是数字0)
字符数组名也是数组首元素的地址。
数组初始化是从静态存储区把一个字符串复制给数组,而指针初始化只是复制字符串的地址。
三、数组和指针的差别
char heart[]=" I love Tillie!";
char *head="I love MIllie!";
主要差别在于数组名heart是个常量,而指针head是个变量。
1、两者都可以使用数组符号。
2、两者都可以使用指针加法。
3、只有指针可以使用增量运算符。
数组的元素是变量,但是数组名不是变量。
可以在声明指针的时候加上const防止更改字符串内容。
const char *mytal1[5] char mytal2[5][81]
前者是一个指向char的指针的数组,而后者是一个char数组的数组。
前者存放5个地址,而后者存放5个完整的字符数组。
11.2 字符串输入
首先声明数组大小:例如char name[81];
gets()读取换行符之前的所有字符,在这些字符后添加一个空字符。
gets()使用一个地址将字符串赋予它,而且它返回一个指向char的指针值,如果出错或者遇到文件结尾,它就返回一个空地址。(NULL)
while(gets(name)!=NULL) while((ch=getchar())!=EOF)
gets()的一个不足是它不检查预留存储区是否能够容纳实际输入的数据,多出来的字符简单的溢出到相邻的内存去。
fgets()函数改进了这个问题,它让您指定最大读入字符数。
1、它需要第二个参数来书名最大读入字符数。如果这个参数值为n,则它就会读取最多n-1个字符或者读完一个换行符为止,由最先满足的条件决定。
2、如果它读取到换行符,会把她存储到字符串中,而不是像gets()那样丢弃它。
3、它还需要第三个参数来说明读哪一个文件。从键盘读取数据时,可以用stdin作为该参数。
也可以使用带有%s格式的scanf()函数来读入一个字符串。scanf()更基于获取单词而不是获取字符串。
11.3 字符串输出
puts()函数使用很简单,只需要给出字符串参数的地址。puts()现实字符串时自动在其后添加一个换行符。
fputs()函数是gets()的面向文件版本
1、fputs()需要第二个参数来说明要写的文件,可以使用stdout作为参数来进行输出显示。
2、fputs()并不为输出自动添加换行符。
也可以使用printf()函数来进行字符串的输出。
11.4 自定义字符串输入\输出函数
#include<stdio.h>
void put1(const char *string)
{
while(*string!='\0')
putchar(*string++);
}
如果熟悉的话可以将while(*string!='\0')改为while(*string)
11.5 字符串函数
一、strlen()函数
用strlen()函数可以得到字符串的长度。
二、strcat()函数
strcat()函数接受两个字符串参数,它将第二个字符串的一份拷贝添加到第一个字符串的结尾,从而使第一个字符串成为一个新的组合字符串,第二个字符串并没有改变。
strcat()函数是char *类型,这个函数返回它的第一个参数的值。
三、strncat()函数
strcat()函数并不检查第一个数组是否能够容纳第二个字符串。strncat()函数需要另一个参数来指明最多允许添加的字符的数目,例如strncat(bugs,addon,13);直到加到13个字符或遇到空字符位置。
四、strcmp()函数
strcmp()函数用来比较字符串内容,它比较的是第一个空字符之前的部分,因此可以用来比较存放在不同大小数组里的字符串。
如果第一个字符串在字母表中的顺序先于第二个字符串,strcmp()返回一个负数,如果相同,它返回0,如果顺序后于则返回一个正数。
strcmp()是按机器编码顺序来进行比较的。
五、strncmp()函数
strncmp()比较字符串时,一直比较到找到不同的相应字符,也可以比较完由第三个参数指定的字符数。
六、strcpy()和strncpy()函数
strcpy()接受两个字符串指针参数。将第二个字符串内容复制到第一个指针指定的地址。
- #include<stdio.h>
- #include<string.h>
- #define SIZE 40
- #define LIM 5
- int main(void)
- {
- char qwords[LIM][SIZE];
- char temp[SIZE];
- int i=0;
- while(i<LIM&&gets(temp))
- {
- if(temp[0]!='q')
- {
- printf("error!\n");
- }
- else
- strcpy(qwords[i++],temp);
- }
- for(i=0;i<LIM;i++)
- puts(qwords[i]);
- return 0;
- }
strcpy()函数还有另外两个有用的属性。首先,它是char *类型,它返回的是第一个参数的值,即一个字符的地址。其次,第一个参数不需要指向数组的开始,这样就可以只复制数组的一部分。
strncpy()需要第三个参数来指明最大可复制的字符数。
七、sprintf()函数
sprintf()函数的第一个参数是目标字符串的地址,其余的参数和printf()一样。例如:sprintf(formal,"%s,%-19s:$%6.2f\n",last,first,prize);
将输入格式化为标准形式后存放在字符串formal中。
11.6 命令行参数
- #include<stdio.h>
- int main(int argc,char *argv[])
- {
- int count;
- printf("The command line has %d arguments: \n",argc-1);
- for(count=1;count<argc;count++)
- printf("%d:%s\n",count,argv[count]);
- printf("\n");
- return 0;
- }
把这个程序编译为可执行文件repeat。 命令行 C>repeat Resistance is futile输出如下
The command has 3 arguments
1: Resistance
2: is
3: futile
main()中的两个参数,第一个参数是命令行中的字符串数,包括命令在内。第二个参数是一个指向字符串的指针数组。(argc:argument count;argv:argument value)
如果使用 repeat "I am hungry" now 则argc=3;
11.7 把字符串转换为数字
strol()、stroul()、strtod()其中strol()函数把一个字符串转换为long型值。其原型如下
long strol(const char *nptr,char **endptr,int base);
- #include<stdio.h>
- #include<stdlib.h>
- int main(int argc,char *argv[])
- {
- char number[30];
- char *end;
- long value;
- puts("Enter a number:");
- while(gets(number)&&number[0]!='\0')
- {
- value=strtol(number,&end,10);
- printf("value:%ld,stopped at %s(%d)\n",value,end,*end);
- value=strtol(number,&end,16);
- printf("value:%ld,stopped at %s(%d)\n",value,end,*end);
- }
- return 0;
- }
如果基数是10,字符串“10”就被转换为10;如果基数是16,则转为16。第一次转换在遇到空字符时结束,这样end就指向空字符。
对于输入的第二个字符串,end是‘a’字符的地址,因此,输出end显示的是字符串“atom”,输出*end显示的则是‘a’字符的ASCII码。但是,如果基值变为16,'a'字符就会被识别为一个有效的十六进制数字,函数会把十六进制数10a转换为十进制的266。