C库提供了多个处理字符串的函数,ANSI-C把这些函数的原型放在string.h头文件中。其中最常用的函数有strlen()、strcat()、strcmp()、strncmp()、strcpy()和strncpy()。另外,还有sprintf()函数,其原型在stdio.h头文件中。

1 strlen()函数

strlen()函数用于统计字符串的长度。下面的函数可以缩短字符串的长度,其中用到了strlen():

void fit(char *string, unsigned int size){    if (strlen(string) > size)        string[size] = '0';}

该函数要改变字符串,所以函数头在声明形式参数string时没有使用const限定符。程序test_fit.c中的程序测试了fit()函数。注意代码中使用了C字符串常量的串联特性。

/* test_fit.c -- try the string-shrinking function */#include #include  /* contains string function prototypes */void fit(char *, unsigned int);int main(void){    char mesg[] = "Things should be as simple as possible,"    " but not simpler.";    puts(mesg);    fit(mesg,38);    puts(mesg);    puts("Let's look at some more of the string.");    puts(mesg + 39);    return 0;}void fit(char *string, unsigned int size){    if (strlen(string) > size)        string[size] = '0';}

下面是该程序的输出:

Things should be as simple as possible, but not simpler.

Things should be as simple as possible

Let's look at some more of the string.

but not simpler.

fit()函数把第39个元素的逗号替换成'0'字符。puts()函数在空字符处停止输出,并忽略其余字符。然而,这些字符还在缓冲区中,下面的函数调用把这些字符打印了出来:

puts(mesg + 39);

表达式mesg + 39是mesg[39]的地址,该地址上存储的是空格字符。所以puts()显示该字符并继续输出直至遇到原来字符串中的空字符。下图演示了这一过程。

The puts() function and the null character.

注意

一些ANSI之前的系统使用strings.h头文件,而有些系统可能根本没有字符串头文件。

string.h头文件中包含了C字符串函数系列的原型,因此程序test_fit.c要包含该头文件。

2 strcat()函数

strcat()(用于拼接字符串)函数接受两个字符串作为参数。该函数把第2个字符串的备份附加在第1个字符串末尾,并把拼接后形成的新字符串作为第1个字符串,第2个字符串不变。strcat()函数的类型是char *(即,指向char的指针)。strcat()函数返回第1个参数,即拼接第2个字符串后的第1个字符串的地址。

程序str_cat.c演示了strcat()的用法。该程序还使用了程序清单11.10的s_gets()函数。回忆一下,该函数使用fgets()读取一整行,如果有换行符,将其替换成空字符。

/* str_cat.c -- joins two strings */#include #include   /* declares the strcat() function */#define SIZE 80char * s_gets(char * st, int n);int main(void){    char flower[SIZE];    char addon[] = "s smell like old shoes.";    puts("What is your favorite flower?");    if (s_gets(flower, SIZE))    {        strcat(flower, addon);        puts(flower);        puts(addon);    }    else        puts("End of file encountered!");    puts("bye");    return 0;}char * s_gets(char * st, int n){    char * ret_val;    int i = 0;    ret_val = fgets(st, n, stdin);    if (ret_val)    {        while (st[i] != 'n' && st[i] != '0')            i++;        if (st[i] == 'n')            st[i] = '0';        else // must have words[i] == '0'            while (getchar() != 'n')                continue;    }    return ret_val;}

该程序的输出示例如下:

What is your favorite flower?

wonderflower

wonderflowers smell like old shoes.

s smell like old shoes.

bye

从以上输出可以看出,flower改变了,而addon保持不变。

3 strncat()函数

strcat()函数无法检查第1个数组是否能容纳第2个字符串。如果分配给第1个数组的空间不够大,多出来的字符溢出到相邻存储单元时就会出问题。当然,可以用strlen()查看第1个数组的长度。注意,要给拼接后的字符串长度加1才够空间存放末尾的空字符。或者,用strncat(),该函数的第3个参数指定了最大添加字符数。例如,strncat(bugs, addon, 13)将把addon字符串的内容附加给bugs,在加到第13个字符或遇到空字符时停止。因此,算上空字符(无论哪种情况都要添加空字符),bugs数组应该足够大,以容纳原始字符串(不包含空字符)、添加原始字符串在后面的13个字符和末尾的空字符。程序join_chk.c 使用这种方法,计算avaiable变量的值,用于表示允许添加的最大字符数。

/* join_chk.c -- joins two strings, check size first */#include #include #define SIZE 30#define BUGSIZE 13char * s_gets(char * st, int n);int main(void){    char flower[SIZE];    char addon[] = "s smell like old shoes.";    char bug[BUGSIZE];    int available;    puts("What is your favorite flower?");    s_gets(flower, SIZE);    if ((strlen(addon) + strlen(flower) + 1) <= SIZE)        strcat(flower, addon);    puts(flower);    puts("What is your favorite bug?");    s_gets(bug, BUGSIZE);    available = BUGSIZE - strlen(bug) - 1;    strncat(bug, addon, available);    puts(bug);    return 0;}char * s_gets(char * st, int n){    char * ret_val;    int i = 0;    ret_val = fgets(st, n, stdin);    if (ret_val)    {        while (st[i] != 'n' && st[i] != '0')            i++;        if (st[i] == 'n')            st[i] = '0';        else // must have words[i] == '0'            while (getchar() != 'n')                continue;    }    return ret_val;}

下面是该程序的运行示例:

What is your favorite flower?RoseRoses smell like old shoes.What is your favorite bug?AphidAphids smell

读者可能已经注意到,strcat()和gets()类似,也会导致缓冲区溢出。为什么C11标准不废弃strcat(),只留下strncat()?为何对gets()那么残忍?这也许是因为gets()造成的安全隐患来自于使用该程序的人,而strcat()暴露的问题是那些粗心的程序员造成的。无法控制用户会进行什么操作,但是,可以控制你的程序做什么。C语言相信程序员,因此程序员有责任确保strcat()的使用安全。

4 strcmp()函数

假设要把用户的响应与已存储的字符串作比较,如程序nogo.c所示。

/* nogo.c -- will this work? */#include #define ANSWER "Grant"#define SIZE 40char * s_gets(char * st, int n);int main(void){    char try[SIZE];    puts("Who is buried in Grant's tomb?");    s_gets(try, SIZE);    while (try != ANSWER)    {        puts("No, that's wrong. Try again.");        s_gets(try, SIZE);    }    puts("That's right!");    return 0;}char * s_gets(char * st, int n){    char * ret_val;    int i = 0;    ret_val = fgets(st, n, stdin);    if (ret_val)    {        while (st[i] != 'n' && st[i] != '0')            i++;        if (st[i] == 'n')            st[i] = '0';        else // must have words[i] == '0'            while (getchar() != 'n')                continue;    }    return ret_val;}

这个程序看上去没问题,但是运行后却不对劲。ANSWER和try都是指针,所以try !=ANSWER检查的不是两个字符串是否相等,而是这两个字符串的地址是否相同。因为ANSWE和try存储在不同的位置,所以这两个地址不可能相同,因此,无论用户输入什么,程序都提示输入不正确。这真让人沮丧。

该函数要比较的是字符串的内容,不是字符串的地址。读者可以自己设计一个函数,也可以使用C标准库中的strcmp()函数(用于字符串比较)。该函数通过比较运算符来比较字符串,就像比较数字一样。如果两个字符串参数相同,该函数就返回0,否则返回非零值。修改后的版本如程序compare.c 所示。

/* compare.c -- this will work */#include #include    // declares strcmp()#define ANSWER "Grant"#define SIZE 40char * s_gets(char * st, int n);int main(void){    char try[SIZE];    puts("Who is buried in Grant's tomb?");    s_gets(try, SIZE);    while (strcmp(try,ANSWER) != 0)    {        puts("No, that's wrong. Try again.");        s_gets(try, SIZE);    }    puts("That's right!");    return 0;}char * s_gets(char * st, int n){    char * ret_val;    int i = 0;    ret_val = fgets(st, n, stdin);    if (ret_val)    {        while (st[i] != 'n' && st[i] != '0')            i++;        if (st[i] == 'n')            st[i] = '0';        else // must have words[i] == '0'            while (getchar() != 'n')                continue;    }    return ret_val;}

注意

由于非零值都为“真”,所以许多经验丰富的C程序员会把该例main()中的while循环头写成:while (strcmp(try, ANSWER))

strcmp()函数比较的是字符串,不是整个数组,这是非常好的功能。虽然数组try占用了40字节,而存储在其中的"Grant"只占用了6字节(还有一个用来放空字符),strcmp()函数只会比较try中第1个空字符前面的部分。所以,可以用strcmp()比较存储在不同大小数组中的字符串。

如果用户输入GRANT、grant或Ulysses S. Grant会怎样?程序会告知用户输入错误。希望程序更友好,必须把所有正确答案的可能性包含其中。这里可以使用一些小技巧。例如,可以使用#define定义类似GRANT这样的答案,并编写一个函数把输入的内容都转换成大写,就解决了大小写的问题。但是,还要考虑一些其他错误的形式,这些留给读者完成。

1.strcmp()的返回值

如果strcmp()比较的字符串不同,它会返回什么值?请看程序compback.c的程序示例。

/* compback.c -- strcmp returns */#include #include int main(void){    printf("strcmp("A", "A") is ");    printf("%dn", strcmp("A", "A"));    printf("strcmp("A", "B") is ");    printf("%dn", strcmp("A", "B"));    printf("strcmp("B", "A") is ");    printf("%dn", strcmp("B", "A"));    printf("strcmp("C", "A") is ");    printf("%dn", strcmp("C", "A"));    printf("strcmp("Z", "a") is ");    printf("%dn", strcmp("Z", "a"));    printf("strcmp("apples", "apple") is ");    printf("%dn", strcmp("apples", "apple"));    return 0;}

在我们的系统中运行该程序,输出如下:

strcmp("A", "A") is 0

strcmp("A", "B") is -1

strcmp("B", "A") is 1

strcmp("C", "A") is 1

strcmp("Z", "a") is -1

strcmp("apples", "apple") is 1

strcmp()比较"A"和本身,返回0;比较"A"和"B",返回-1;比较"B"和"A",返回1。这说明,如果在字母表中第1个字符串位于第2个字符串前面,strcmp()中就返回负数;反之,strcmp()则返回正数。所以,strcmp()比较"C"和"A",返回1。其他系统可能返回2,即两者的ASCII码之差。ASCII标准规定,在字母表中,如果第1个字符串在第2个字符串前面,strcmp()返回一个负数;如果两个字符串相同,strcmp()返回0;如果第1个字符串在第2个字符串后面,strcmp()返回正数。然而,返回的具体值取决于实现。例如,下面给出在不同实现中的输出,该实现返回两个字符的差值:

strcmp("A", "A") is 0

strcmp("A", "B") is -1

strcmp("B", "A") is 1

strcmp("C", "A") is 2

strcmp("Z", "a") is -7

strcmp("apples", "apple") is 115

如果两个字符串开始的几个字符都相同会怎样?一般而言,strcmp()会依次比较每个字符,直到发现第1对不同的字符为止。然后,返回相应的值。例如,在上面的最后一个例子中,"apples"和"apple"只有最后一对字符不同("apples"的s和"apple"的空字符)。由于空字符在ASCII中排第1。字符s一定在它后面,所以strcmp()返回一个正数。

最后一个例子表明,strcmp()比较所有的字符,不只是字母。所以,与其说该函数按字母顺序进行比较,不如说是按机器排序序列(machine collating sequence)进行比较,即根据字符的数值进行比较(通常都使用ASCII值)。在ASCII中,大写字母在小写字母前面,所以strcmp("Z", "a")返回的是负值。

大多数情况下,strcmp()返回的具体值并不重要,我们只在意该值是0还是非0(即,比较的两个字符串是否相等)。或者按字母排序字符串,在这种情况下,需要知道比较的结果是为正、为负还是为0。

--------------

注意

strcmp()函数比较的是字符串,不是字符,所以其参数应该是字符串(如"apples"和"A"),而不是字符(如'A')。但是,char类型实际上是整数类型,所以可以使用关系运算符来比较字符。假设word是存储在char类型数组中的字符串,ch是char类型的变量,下面的语句都有效:

if (strcmp(word, "quit") == 0)  // use strcmp() for strings    puts("Bye!");if (ch == 'q')                  // use == for chars    puts("Bye!");

尽管如此,不要使用ch或'q'作为strcmp()的参数。

--------------

程序quit_chk.c用strcmp()函数检查程序是否要停止读取输入。

/* quit_chk.c -- beginning of some program */#include #include #define SIZE 80#define LIM 10#define STOP "quit"char * s_gets(char * st, int n);int main(void){    char input[LIM][SIZE];    int ct = 0;    printf("Enter up to %d lines (type quit to quit):n", LIM);    while (ct < LIM && s_gets(input[ct], SIZE) != NULL &&           strcmp(input[ct],STOP) != 0)    {        ct++;    }    printf("%d strings enteredn", ct);    return 0;}char * s_gets(char * st, int n){    char * ret_val;    int i = 0;    ret_val = fgets(st, n, stdin);    if (ret_val)    {        while (st[i] != 'n' && st[i] != '0')            i++;        if (st[i] == 'n')            st[i] = '0';        else // must have words[i] == '0'            while (getchar() != 'n')                continue;    }    return ret_val;}

该程序在读到EOF字符(这种情况下s_gets()返回NULL)、用户输入quit或输入项达到LIM时退出。

顺带一提,有时输入空行(即,只按下Enter键或Return键)表示结束输入更方便。为实现这一功能,只需修改一下while循环的条件即可:

while (ct < LIM && s_gets(input[ct], SIZE) != NULL                && input[ct][0] != '0')

这里,input[ct]是刚输入的字符串,input[ct][0]是该字符串的第1个字符。如果用户输入空行,s_gets()便会把该行第1个字符(换行符)替换成空字符。所以,下面的表达式用于检测空行:

input[ct][0] != '0'

2.strncmp()函数

strcmp()函数比较字符串中的字符,直到发现不同的字符为止,这一过程可能会持续到字符串的末尾。而strncmp()函数在比较两个字符串时,可以比较到字符不同的地方,也可以只比较第3个参数指定的字符数。例如,要查找以"astro"开头的字符串,可以限定函数只查找这5个字符。程序starsrch.c演示了该函数的用法。

/* starsrch.c -- use strncmp() */#include #include #define LISTSIZE 6int main(){    const char * list[LISTSIZE] =    {        "astronomy", "astounding",        "astrophysics", "ostracize",        "asterism", "astrophobia"    };    int count = 0;    int i;    for (i = 0; i < LISTSIZE; i++)        if (strncmp(list[i],"astro", 5) == 0)        {            printf("Found: %sn", list[i]);            count++;        }    printf("The list contained %d words beginning"           " with astro.n", count);

下面是该程序的输出:

Found: astronomyFound: astrophysicsFound: astrophobiaThe list contained 3 words beginning with astro.

5 strcpy()和strncpy()函数

前面提到过,如果pts1和pts2都是指向字符串的指针,那么下面语句拷贝的是字符串的地址而不是字符串本身:

pts2 = pts1;

如果希望拷贝整个字符串,要使用strcpy()函数。程序copy1.c要求用户输入以q开头的单词。该程序把输入拷贝至一个临时数组中,如果第1个字母是q,程序调用strcpy()把整个字符串从临时数组拷贝至目标数组中。strcpy()函数相当于字符串赋值运算符。

/* copy1.c -- strcpy() demo */#include #include   // declares strcpy()#define SIZE 40#define LIM 5char * s_gets(char * st, int n);int main(void){    char qwords[LIM][SIZE];    char temp[SIZE];    int i = 0;    printf("Enter %d words beginning with q:n", LIM);    while (i < LIM && s_gets(temp, SIZE))    {        if (temp[0] != 'q')            printf("%s doesn't begin with q!n", temp);        else        {            strcpy(qwords[i], temp);            i++;        }    }    puts("Here are the words accepted:");    for (i = 0; i < LIM; i++)        puts(qwords[i]);    return 0;}char * s_gets(char * st, int n){    char * ret_val;    int i = 0;    ret_val = fgets(st, n, stdin);    if (ret_val)    {        while (st[i] != 'n' && st[i] != '0')            i++;        if (st[i] == 'n')            st[i] = '0';        else // must have words[i] == '0'            while (getchar() != 'n')                continue;    }    return ret_val;}

下面是该程序的运行示例:

Enter 5 words beginning with q:

quackery

quasar

quilt

quotient

no more

no more doesn't begin with q!

quiz

Here are the words accepted:

quackery

quasar

quilt

quotient

quiz

注意,只有在输入以q开头的单词后才会递增计数器i,而且该程序通过比较字符进行判断:

if (temp[0] != 'q')

这行代码的意思是:temp中的第1个字符是否是q?当然,也可以通过比较字符串进行判断:

 if (strncmp(temp, "q", 1) != 0)

这行代码的意思是:temp字符串和"q"的第1个元素是否相等?

请注意,strcpy()第2个参数(temp)指向的字符串被拷贝至第1个参数(qword[i])指向的数组中。拷贝出来的字符串被称为目标字符串,最初的字符串被称为源字符串。参考赋值表达式语句,很容易记住strcpy()参数的顺序,即第1个是目标字符串,第2个是源字符串。

char target[20];int x;x = 50;                    /* assignment for numbers */strcpy(target, "Hi ho!");  /* assignment for strings */target = "So long";        /* syntax error           */

程序员有责任确保目标数组有足够的空间容纳源字符串的副本。下面的代码有点问题:

char * str;strcpy(str, "The C of Tranquility"); // a problem

strcpy()把"The C of Tranquility"拷贝至str指向的地址上,但是str未被初始化,所以该字符串可能被拷贝到任意的地方!总之,strcpy()接受两个字符串指针作为参数,可以把指向源字符串的第2个指针声明为指针、数组名或字符串常量;而指向源字符串副本的第1个指针应指向一个数据对象(如,数组),且该对象有足够的空间存储源字符串的副本。记住,声明数组将分配存储数据的空间,而声明指针只分配存储一个地址的空间。

strcpy()的更多属性

strcpy()函数还有两个有用的属性。第一,strcpy()的返回类型是char *,该函数返回的是第1个参数的值,即一个字符的地址。第二,第1个参数不必指向数组的开始。这个属性可用于拷贝数组的一部分。程序清单11.26演示了该函数的这两个属性。

/* copy2.c -- strcpy() demo */#include #include     // declares strcpy()#define WORDS  "beast"#define SIZE 40int main(void){    const char * orig = WORDS;    char copy[SIZE] = "Be the best that you can be.";    char * ps;    puts(orig);    puts(copy);    ps = strcpy(copy + 7, orig);    puts(copy);    puts(ps);    return 0;}

下面是该程序的输出:

beastBe the best that you can be.Be the beastbeast

注意,strcpy()把源字符串中的空字符也拷贝在内。在该例中,空字符覆盖了copy数组中that的第1个t。注意,由于第1个参数是copy + 7,所以ps指向copy中的第8个元素(下标为7)。因此puts(ps)从该处开始打印字符串。

The strcpy() function uses pointers.

更谨慎的选择:strncpy()

strcpy()和strcat()都有同样的问题,它们都不能检查目标空间是否能容纳源字符串的副本。拷贝字符串用strncpy()更安全,该函数的第3个参数指明可拷贝的最大字符数。程序copy3.c用strncpy()代替程序copy1.c中的strcpy()。为了演示目标空间装不下源字符串的副本会发生什么情况,该程序使用了一个相当小的目标字符串(共7个元素,包含6个字符)。

/* copy3.c -- strncpy() demo */#include #include   /* declares strncpy() */#define SIZE 40#define TARGSIZE 7#define LIM 5char * s_gets(char * st, int n);int main(void){    char qwords[LIM][TARGSIZE];    char temp[SIZE];    int i = 0;    printf("Enter %d words beginning with q:n", LIM);    while (i < LIM && s_gets(temp, SIZE))    {        if (temp[0] != 'q')            printf("%s doesn't begin with q!n", temp);        else        {            strncpy(qwords[i], temp, TARGSIZE - 1);            qwords[i][TARGSIZE - 1] = '0';            i++;        }    }    puts("Here are the words accepted:");    for (i = 0; i < LIM; i++)        puts(qwords[i]);    return 0;}char * s_gets(char * st, int n){    char * ret_val;    int i = 0;    ret_val = fgets(st, n, stdin);    if (ret_val)    {        while (st[i] != 'n' && st[i] != '0')            i++;        if (st[i] == 'n')            st[i] = '0';        else // must have words[i] == '0'            while (getchar() != 'n')                continue;    }    return ret_val;}

下面是该程序的运行示例:

Enter 5 words beginning with q:

quack

quadratic

quisling

quota

quagga

Here are the words accepted:

quack

quadra

quisli

quota

quagga

strncpy(target, source, n)把source中的n个字符或空字符之前的字符(先满足哪个条件就拷贝到何处)拷贝至target中。因此,如果source中的字符数小于n,则拷贝整个字符串,包括空字符。但是,strncpy()拷贝字符串的长度不会超过n,如果拷贝到第n个字符时还未拷贝完整个源字符串,就不会拷贝空字符。所以,拷贝的副本中不一定有空字符。鉴于此,该程序把n设置为比目标数组大小少1(TARGSIZE-1),然后把数组最后一个元素设置为空字符:

/* compare.c -- this will work */#include #include    // declares strcmp()#define ANSWER "Grant"#define SIZE 40char * s_gets(char * st, int n);int main(void){    char try[SIZE];    puts("Who is buried in Grant's tomb?");    s_gets(try, SIZE);    while (strcmp(try,ANSWER) != 0)    {        puts("No, that's wrong. Try again.");        s_gets(try, SIZE);    }    puts("That's right!");    return 0;}char * s_gets(char * st, int n){    char * ret_val;    int i = 0;    ret_val = fgets(st, n, stdin);    if (ret_val)    {        while (st[i] != 'n' && st[i] != '0')            i++;        if (st[i] == 'n')            st[i] = '0';        else // must have words[i] == '0'            while (getchar() != 'n')                continue;    }    return ret_val;}

这样做确保存储的是一个字符串。如果目标空间能容纳源字符串的副本,那么从源字符串拷贝的空字符便是该副本的结尾;如果目标空间装不下副本,则把副本最后一个元素设置为空字符。

6 sprintf()函数

sprintf()函数声明在stdio.h中,而不是在string.h中。该函数和printf()类似,但是它是把数据写入字符串,而不是打印在显示器上。因此,该函数可以把多个元素组合成一个字符串。sprintf()的第1个参数是目标字符串的地址。其余参数和printf()相同,即格式字符串和待写入项的列表。

程序format.c中的程序用sprintf()把3个项(两个字符串和一个数字)组合成一个字符串。注意,sprintf()的用法和printf()相同,只不过sprintf()把组合后的字符串存储在数组formal中而不是显示在屏幕上。

/* format.c -- format a string */#include #define MAX 20char * s_gets(char * st, int n);int main(void){    char first[MAX];    char last[MAX];    char formal[2 * MAX + 10];    double prize;    puts("Enter your first name:");    s_gets(first, MAX);    puts("Enter your last name:");    s_gets(last, MAX);    puts("Enter your prize money:");    scanf("%lf", &prize);    sprintf(formal, "%s, %-19s: $%6.2fn", last, first, prize);    puts(formal);    return 0;}char * s_gets(char * st, int n){    char * ret_val;    int i = 0;    ret_val = fgets(st, n, stdin);    if (ret_val)    {        while (st[i] != 'n' && st[i] != '0')            i++;        if (st[i] == 'n')            st[i] = '0';        else // must have words[i] == '0'            while (getchar() != 'n')                continue;    }    return ret_val;}

下面是该程序的运行示例:

Enter your first name:

Annie

Enter your last name:

von Wurstkasse

Enter your prize money:

25000

von Wurstkasse, Annie : $25000.00

sprintf()函数获取输入,并将其格式化为标准形式,然后把格式化后的字符串存储在formal中。

7 其他字符串函数

ANSI C库有20多个用于处理字符串的函数,下面总结了一些常用的函数。

char *strcpy(char * restrict s1, const char * restrict s2);

该函数把s2指向的字符串(包括空字符)拷贝至s1指向的位置,返回值是s1。

char *strncpy(char * restrict s1, const char * restrict s2, size_t n);

该函数把s2指向的字符串拷贝至s1指向的位置,拷贝的字符数不超过n,其返回值是s1。该函数不会拷贝空字符后面的字符,如果源字符串的字符少于n个,目标字符串就以拷贝的空字符结尾;如果源字符串有n个或超过n个字符,就不拷贝空字符。

/* compback.c -- strcmp returns */#include #include int main(void){    printf("strcmp("A", "A") is ");    printf("%dn", strcmp("A", "A"));    printf("strcmp("A", "B") is ");    printf("%dn", strcmp("A", "B"));    printf("strcmp("B", "A") is ");    printf("%dn", strcmp("B", "A"));    printf("strcmp("C", "A") is ");    printf("%dn", strcmp("C", "A"));    printf("strcmp("Z", "a") is ");    printf("%dn", strcmp("Z", "a"));    printf("strcmp("apples", "apple") is ");    printf("%dn", strcmp("apples", "apple"));    return 0;}

该函数把s2指向的字符串拷贝至s1指向的字符串末尾。s2字符串的第1个字符将覆盖s1字符串末尾的空字符。该函数返回s1。

char *strncat(char * restrict s1, const char * restrict s2, size_t n);

该函数把s2字符串中的n个字符拷贝至s1字符串末尾。s2字符串的第1个字符将覆盖s1字符串末尾的空字符。不会拷贝s2字符串中空字符和其后的字符,并在拷贝字符的末尾添加一个空字符。该函数返回s1。

 int strcmp(const char * s1, const char * s2);

如果s1字符串在机器排序序列中位于s2字符串的后面,该函数返回一个正数;如果两个字符串相等,则返回0;如果s1字符串在机器排序序列中位于s2字符串的前面,则返回一个负数。

int strncmp(const char * s1, const char * s2, size_t n);

该函数的作用和strcmp()类似,不同的是,该函数在比较n个字符后或遇到第1个空字符时停止比较。

char *strchr(const char * s, int c);

如果s字符串中包含c字符,该函数返回指向s字符串首次出现的c字符的指针(末尾的空字符也是字符串的一部分,所以在查找范围内);如果在字符串s中未找到c字符,该函数则返回空指针。

char *strpbrk(const char * s1, const char * s2);

如果s1字符中包含s2字符串中的任意字符,该函数返回指向s1字符串首位置的指针;如果在s1字符串中未找到任何s2字符串中的字符,则返回空字符。

char *strrchr(const char * s, int c);

该函数返回s字符串中c字符的最后一次出现的位置(末尾的空字符也是字符串的一部分,所以在查找范围内)。如果未找到c字符,则返回空指针。

char *strstr(const char * s1, const char * s2);

该函数返回指向s1字符串中s2字符串出现的首位置。如果在s1中没有找到s2,则返回空指针。

 size_t strlen(const char * s);

该函数返回s字符串中的字符数,不包括末尾的空字符。请注意,那些使用const关键字的函数原型表明,函数不会更改字符串。例如,下面的函数原型:

char *strcpy(char * restrict s1, const char * restrict s2);

表明不能更改s2指向的字符串,至少不能在strcpy()函数中更改。但是可以更改s1指向的字符串。这样做很合理,因为s1是目标字符串,要改变,而s2是源字符串,不能更改。

关键字restrict 限制了函数参数的用法。例如,不能把字符串拷贝给本身。

size_t类型是sizeof运算符返回的类型。C规定sizeof运算符返回一个整数类型,但是并未指定是哪种整数类型,所以size_t在一个系统中可以是unsignedint,而在另一个系统中可以是unsigned long。string.h头文件针对特定系统定义了size_t,或者参考其他有size_t定义的头文件。

我们来看一下其中一个函数的简单用法。前面学过的fgets()读入一行输入时,在目标字符串的末尾添加换行符。我们自定义的s_gets()函数通过while循环检测换行符。其实,这里可以用strchr()代替s_gets()。首先,使用strchr()查找换行符(如果有的话)。如果该函数发现了换行符,将返回该换行符的地址,然后便可用空字符替换该位置上的换行符:

char line[80];char * find;fgets(line, 80, stdin);find = strchr(line, 'n');   // look for newlineif (find)                    // if the address is not NULL,    *find = '0';            // place a null character there

如果strchr()未找到换行符,fgets()在达到行末尾之前就达到了它能读取的最大字符数。可以像在s_gets()中那样,给if添加一个else来处理这种情况。

接下来,我们看一个处理字符串的完整程序。

C++接收字符串数组_C语言处理字符串的7个函数相关推荐

  1. c 字符串数组_C语言探索之旅 | 第二部分第四课:字符串

    内容简介 前言 字符类型 显示字符 字符串其实就是字符的数组 字符串的创建和初始化 从 scanf 函数取得一个字符串 操纵字符串的一些常用函数 总结 第二部分第五课预告 1. 前言 上一课 C语言探 ...

  2. c#解析json字符串数组_C#解析JSON字符串总结

    JSON文件读取到内存中就是字符串,.NET操作JSON就是生成与解析JSON字符串. 操作JSON通常有以下几种方式: 1. 原始方式:按照JSON字符串自己来解析. 2. 通用方式[★★★★★]: ...

  3. c#解析json字符串数组_c#解析json字符串处理(最清晰易懂的方法)

    (完整代码在文末,引用库文件后可直接运行~) 需求: 假设有如下json字符串: { "companyID": "15", "employees&qu ...

  4. java字符串数组转json_java中字符串String格式转化成json格式

    java字符串数组转json_java中字符串String格式转化成json格式 String s= Connection.deleteHost("10310");System.o ...

  5. 使用C#删除一个字符串数组中的空字符串

    C#中要如何才能删除一个字符串数组中的空字符串呢?随着微软对C#不断发展和更新,C#中对于数组操作的方式也变得越来越多样化.以往要实现过滤数组中的空字符串,都是需要实行循环的方式来排除和过滤.C#3. ...

  6. c+字符串数组_了解C ++字符串数组

    c+字符串数组 Hey, Folks! So, as programmers, we often deal with Arrays of all data types. We'll cover C++ ...

  7. c语言字 字符串转换成数组_C语言学习教程之详解C语言中的字符串数组

    在C语言当中,字符串数组可以使用: char a[] [10]; 或者 char *a[]; 表示 第一种表示方式固定了每个字符串的最大大小.第二种没有字符串的大小限制. #include 总结 以上 ...

  8. c int转char数组_C语言 指向数组和字符串的指针

    实例1 我们在pointer_test.c的文件中写一个test2()函数,我们定义一个有3个元素的字符数组初始化值分别为,'A', 'B', 'C',然后定义一个字符指针pc,把数组ca的首地址复制 ...

  9. c语言如何将8个字符串串联_C ++中的字符串串联:串联字符串的4种方法

    c语言如何将8个字符串串联 In this article, we will unveil the various ways of performing string concatenation in ...

最新文章

  1. fastq质量值_fastq格式文件处理大全(四)
  2. AFNetworking框架-详细解析
  3. [php]数据结构算法(PHP描述) 半折插入排序 straight binary sort
  4. 软件工程学习笔记《三》代码优化和性能测试
  5. mysql查询库中所有的表名,mysql查询指定表中的所有字段名及其相关信息
  6. 如何让char不要忽略开头的空格_如何使用C语言实现JSON解析库(二)
  7. document.documentElement和document.body的区别
  8. Scorm标准学习——Scorm RTE API与数据模型
  9. CISCO路由器的备份与还原(1)
  10. wordpress 增加备案号
  11. 中间表为什么可以不用实体类_法国蜗牛供不应求,为什么不用中国蜗牛代替?看完才知道真不可以...
  12. 魔百盒UNT403A UNT413A 卡刷精简固件-芯片S905L3
  13. Android 文本监听接口TextWatcher详解
  14. CI框架SESSION使用
  15. 要计算机桌面,科幻再次要成真:你的办公桌面很快也会变成计算机
  16. RdViewer(远程控制电脑屏幕软件)官方中文版V3.3.1 | rd远程工具下载
  17. 【锂知道】锂电池基本原理解析:充电及放电机制
  18. 在线学习PS设计精讲精练记录(5)
  19. 如何判断欠拟合、适度拟合、过拟合
  20. 前端vs图片 3 jpg、png、gif 图片老三样系统总结

热门文章

  1. Map 参数按Key重新排序,重组成String
  2. 用户登入验证码代码示例
  3. 常见移动机器人多角度对比分析(图片版)
  4. 问答| 为什么汽车会采用前轮转向,后轮驱动的方式?为什么反过来的搭配方式很少见?
  5. charles浏览器抓包https_十分钟学会Charles抓包(iOS的http/https请求)
  6. Iconfont的引用与在伪元素中的图标引用
  7. 如何修改WampServer服务器上传文件的大小?
  8. js过滤时间方法,几分钟前,1小时前
  9. svg写入/识别html元素和css样式
  10. python设置ini文件中的值_5分钟掌握Python中常见的配置文件