(九)字符串、字符和字节
C语言并没有显式的字符串数据类型,因为字符串以字符串常量的形式出现或者存储于字符数组中。字符串常量很适用于那些程序不会对它们进行修改的字符串。
NUL字节是字符串的终止符,但它本身并不是字符串的一部分,所以字符串的长度并不包括NUL字节。
char *strcpy(char *dst, char const *src);
这个函数把参数src字符串复制到dst参数。由于dst参数将进行修改,所以它必须是个字符数组或者是一个指向动态分配内存的数组的指针,不能使用字符串常量。
即使新的字符串比dst原先的内存更短,由于新字符串是以NUL字节结尾,所以老字符串最后剩余的几个字符也会被有效地删除。
如果字符串比数组长,多余地字符仍被复制,它们将覆盖原先存储于数组后面的内存空间的值。
char *strncpy(char *dst, char const *src, size_t len);
char *strncat(char *dst,char const *src, size_t len);
int strncmp(char const *s1, char const *s2, size_t len);
这些函数接受一个显式的长度参数,用于限定进行复制或比较的字符数。
如果strlen(src)的值大于或等于len,那么只有len个字符被复制到dst中。注意!它的结果将不会以NUL字节结尾。
所以要在代码中确保字符串是以NUL结尾的。
char buffer[BSIZE];
...
strncpy(buffer, name, BSIZE);
buffer[BSIZE - 1] = '\0';
strncat总是在结果字符串后面添加一个NUL字节,而且它不会像strncpy那样对目标数组用NUL字节进行填充。
字符串查找
查找一个字符:
char *strchr(char const *str, int ch);
char *strrchr(char const *str, int ch);
ch包含了一个字符值。
strchr在字符串str中查找字符ch第1次出现的位置,找到后函数返回一个指向该位置的指针。如果该字符并不存在于字符串中,函数就返回一个NULL指针。
strrchr的功能和strchr基本一致,只是它所返回的是一个指向字符串中该字符最后一次出现的位置。
char *strpbrk(char const *str, char const *group);
这个函数返回一个指向str中第1个匹配group中任何一个字符的字符位置。
char *strstr(char const *s1, char const *s2);
这个函数在s1中查找整个s2第1次出现的起始位置,并返回一个指向该位置的指针。
高级字符串查找
size_t strspn(char const *str, char const *group);
size_t strcspn(char const *str, char const *group);
group字符串指定一个或多个字符。strspn返回str起始部分匹配group中任意字符的字符数。
strcspn对str字符串起始部分中不与group中任何字符匹配的字符进行计数。
char *strtok(char *str, char const *sep);
sep参数是个字符串,定义了用作分隔符的字符集合。第1参数指定一个字符串,它包含零个或多个由sep字符串中一个或多个分隔符分隔的标记。strtok找到str的下一个标记,并将其用NUL结尾,然后返回一个指向这个标记的指针。
void print_tokens(char *line)
{
static char whitespace[] = " \t\f\r\v\n";
char *token;
for(token = strtok(line, whitespace)); token != NULL; token = strtok(NULL, whitespace))
printf("Next token is %s\n", token);
}
如果strtok函数的第1个参数不是NULL,函数将找到字符串的第1个标记。strtok同时将保存它在字符串中的位置。如果strtok函数的第1个参数是NULL,函数就在同一个字符串中从这个被保存的位置开始像前面一样查找下一个标记。如果字符串内不存在更多的标记,strtok函数就返回一个NULL指针。
内存操作
void *memcpy(void *dst, void const *src, size_t length);
void *memmove(void *dst, void const *src, size_t length);
void *memcmp(void const *a, void const *b, size_t length);
void *memchr(void const *a, int ch, size_t length);
void *memset(void *a, int ch, size_t length);
和strn带头的函数不同,它们在遇到NUL字节时并不会停止操作。
memcpy从src的起始位置复制length个字节到dst的内存起始位置。
memmove的行为和memcpy差不多,只是它的源和目标操作数可以重叠。
memcmp对两段内存length个字节的内容进行比较。
memchr从a的起始位置开始查找字符ch第1次出现的位置。
memset函数把从a开始的length个字节都设置为字符值ch。