C Program Ⅳ 字符串和字符串函数

五.字符串函数

1.strlen()函数

strlen()函数用于统计字符串的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* test_fit.c -- try the string-shrinking function */
#include <stdio.h>
#include <string.h> /* 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';
}

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

1
puts(mesg + 8);

表达式mesg + 39mesg[39]的地址,该地址上储存的是空格字符。所以put()显示该字符并继续输出直至遇到原来字符串中的空字符.

演示过程如下图所示:

2.strcat()和strncat()函数

strcat()(用于拼接字符串)函数接受两个字符串作为参数。该函数把第2个字符串的备份附加在第1个字符串末尾,并把拼接后形成的新字符串作为第1个字符串,第2个字符串不变。

strcat()函数的类型是char *(即,指向char的指针)。strcat()函数返回第1个参数,即拼接第2个字符串后的第1个字符串的地址。

strcat()的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/* str_cat.c -- joins two strings */
#include <stdio.h>
#include <string.h> /* declares the strcat() function */
#define SIZE 80
char * 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;
}

strcat()函数问题:

`strcat()`函数无法检查第1个数组是否能容纳第2个字符串。如果分配给第1个数组的空间不够大,多出来的字符溢出到相邻存储单元时就会出问题。

解决方法:

  • strlen()查看第1个数组的长度。注意,要给拼接后的字符串长度加1才够空间存放末尾的空字符。
  • strncat(),该函数的第3 个参数指定了最大添加字符数。

strncat()例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/* join_chk.c -- joins two strings, check size first */
#include <stdio.h>
#include <string.h>
#define SIZE 30
#define BUGSIZE 13
char * 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;
}

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

三.strcmp()函数

0%