字符函数和字符串函数
函数部分的解析来源于( C++资源网络)
- 求字符串长度
strlen - 长度不受限制的字符串函数
strcpy
strcat
strcmp - 长度受限制的字符串函数介绍
strncpy
strncat
strncmp - 字符串查找
strstr
strtok - 错误信息报告
strerror - 字符操作
- 内存函数操作
memcpy
memmove
memset
memcmp
C语言中的字符串问题
写代码时对字符和字符串的处理很频繁,但是C语言中本身没有字符串类型,字符串通常存储在常量字符串中或者字符数组中。常量字符串适用于那些对它不做修改的字符串函数。
函数介绍
1. strlen
1.1 功能:
Get string length获取字符串长度
返回C语言中字符串的长度。
1.2 库函数形式
size_t strlen ( const char * str );
1.3 注意事项:
字符串的长度由终止字符确定。字符串的长度与字符串开头和终止空字符之间的字符数一样长(不包括终止空字符本身)。
1.4 实例
int main ()
{
char szInput[256];
printf ("Enter a sentence: ");
gets (szInput);
printf ("The sentence entered is %u characters long.\n",(unsigned)strlen(szInput));
return 0;
}
2. strcpy
2.1 功能:
Copy block of memory复制字符串
将源所指向的 C 字符串复制到**目标**所指向的数组中,包括终止空字符(并在该点停止)。
2.2 库函数形式
char * strcpy ( char * destination, const char * source );
2.3 注意事项:
为避免溢出,目标所指向的数组的大小应足够长,以包含与源相同的 C 字符串(包括终止空字符),并且不应在内存中与 source 重叠。
2.4 实例
int main ()
{
char str1[]="Sample string";
char str2[40];
char str3[40];
strcpy (str2,str1);
strcpy (str3,"copy successful");
printf ("str1: %s\nstr2: %s\nstr3: %s\n",str1,str2,str3);
return 0;
}
3. strcat
3.1 功能:
Concatenate strings连接字符串
将源字符串的副本追加到目标字符串。目标中的终止空字符被源的第一个字符覆盖,并且在目标中由两者串联形成的新字符串的末尾包含一个空字符。
3.2 库函数形式
char * strcat ( char * destination, const char * source );
3.3 注意事项:
目的地和来源不得重叠。
3.4 实例
int main ()
{
char str[80];
strcpy (str,"these ");
strcat (str,"strings ");
strcat (str,"are ");
strcat (str,"concatenated.");
puts (str);
return 0;
}
4. strcmp
4.1 功能:
Compare two strings比较两个字符串
将 C 字符串str1与 C 字符串str2进行比较。
返回值 | 表明 |
---|---|
<0 | 第一个不匹配的字符在ptr1中的值低于ptr2中的值 |
0 | 两个字符中的内容相等 |
>0 | 第一个不匹配的字符在ptr1中的值低于ptr2中的值 |
4.2 库函数形式
int strcmp ( const char * str1, const char * str2 );
4.3 注意事项:
此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续使用以下对,直到字符不同或达到终止空字符。
4.4 实例
int main ()
{
char key[] = "apple";
char buffer[80];
do {
printf ("Guess my favorite fruit? ");
fflush (stdout);
scanf ("%79s",buffer);
} while (strcmp (key,buffer) != 0);
puts ("Correct answer!");
return 0;
}
5. strncpy
5.1 功能:
Copy characters from string从字符串中复制字符
将源的前num字符复制到目标。如果在复制num个字符之前找到源C 字符串(由空字符指示)的末尾,则目标将填充零,直到向其写入总共num个字符。
5.2 库函数形式
char * strncpy ( char * destination, const char * source, size_t num );
5.3 注意事项:
如果源的长度超过 num,则不会在目标末尾隐式追加空字符。
因此,在这种情况下,目标不应被视为以空值结尾的 C 字符串(这样读取它会溢出)。
目的地和来源不得重叠(重叠时,请参阅 memmove 以了解更安全的替代方案)。
5.4 实例
int main ()
{
char str1[]= "To be or not to be";
char str2[40];
char str3[40];
/* copy to sized buffer (overflow safe): */
strncpy ( str2, str1, sizeof(str2) );
/* partial copy (only 5 chars): */
strncpy ( str3, str2, 5 );
str3[5] = '\0'; /* null character manually added */
puts (str1);
puts (str2);
puts (str3);
return 0;
}
6. strncat
6.1 功能:
Append characters from string
将源的前num个字符追加到目标,加上一个终止空字符。
6.2 库函数形式
char * strncat ( char * destination, const char * source, size_t num );
6.3 注意事项:
如果源中 C 字符串的长度小于num,则仅复制直到终止空字符的内容。
6.4 实例
int main ()
{
char str1[20];
char str2[20];
strcpy (str1,"To be ");
strcpy (str2,"or not to be");
strncat (str1, str2, 6);
puts (str1);
return 0;
}
7. strncmp
7.1 功能:
Compare characters of two strings 比较两个字符串的字符
将 C 字符串str1的最多 num个字符与 C 字符串str2的字符数进行比较。
7.2 库函数形式
int strncmp ( const char * str1, const char * str2, size_t num );
7.3 注意事项:
此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续向后比较,直到字符不同,直到达到终止空字符,或者直到两个字符串中的num字符匹配,以先发生的情况为准。
7.4 实例
int main ()
{
char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
int n;
puts ("Looking for R2 astromech droids...");
for (n=0 ; n<3 ; n++)
if (strncmp (str[n],"R2xx",2) == 0)
{
printf ("found %s\n",str[n]);
}
return 0;
}
8. strstr
8.1 功能:
**Locate substring ** 定位子字符串
返回一个指向str1中第一次出现的str2的指针,如果str2 不是 str1的一部分,则返回空指针。
8.2 库函数形式
const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
8.3 注意事项:
匹配过程不包括终止空字符,但碰到它就此停止。
8.4 实例
int main ()
{
char str[] ="This is a simple string";
char * pch;
pch = strstr (str,"simple");
if (pch != NULL)
strncpy (pch,"sample",6);
puts (str);
return 0;
}
9. strtok
9.1 功能:
Split string into tokens 将字符串拆分为标记
对该函数的一系列调用将str拆分为标记,这些标记是由分隔符中的任何字符分隔的连续字符序列。
9.1 库函数形式
char * strtok ( char * str, const char * delimiters );
9.3 注意事项:
在第一次调用时,函数需要一个C字符串作为str的参数,str的第一个字符用作扫描标记的起始位置。在随后的调用中,函数需要一个空指针,并使用最后一个标记结束后的位置作为扫描的新起始位置。
要确定标记的开头和结尾,函数首先从起始位置扫描分隔符中未包含的第一个字符(即标记的开头)。然后从标记的这个开头开始扫描分隔符中包含的第一个字符,它将成为标记的结尾。如果找到终止的空字符,扫描也会停止。
令牌的这一端将自动替换为空字符,函数将返回令牌的开头。
在对strtok的调用中找到str的终止null字符后,所有后续对该函数的调用(以null指针作为第一个参数)都会返回null指针。
找到最后一个令牌的点由函数在内部保留,以便在下次调用时使用(不需要特定的库实现来避免数据争用)。
9.4 实例
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
10. strerror
10.1 功能:
Get pointer to error message string获取指向错误消息字符串的指针
解释errnum的值,生成一个字符串,其中包含一条描述错误条件的消息,就好像被库的函数设置为errno一样。
10.2 库函数形式
char * strerror ( int errnum );
10.3 注意事项:
字符串。对此函数的进一步调用可能会覆盖其内容(不需要特定的库实现来避免数据争用)。strerror 生成的错误字符串可能特定于每个系统和库实现。
10.4 实例
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
FILE * pFile;
pFile = fopen ("unexist.ent","r");
if (pFile == NULL)
printf ("Error opening file unexist.ent: %s\n",strerror(errno));
return 0;
}
11. memcpy
10.1 功能:
Copy block of memory 复制内存块
将num字节的值从源指向的位置直接复制到目标所指向的内存块。源指针和目标指针所指向的对象的基础类型与此函数无关。
10.2 库函数形式
void * memcpy ( void * destination, const void * source, size_t num );
10.3 注意事项:
结果是数据的二进制副本。该函数不检查源中是否有任何终止空字符 - 它始终精确地复制数字字节。
为避免溢出,目标参数和源参数所指向的数组的大小应至少为 num 字节,并且不应重叠(对于重叠的内存块,memmove 是一种更安全的方法)。
11.4 实例
struct {
char name[40];
int age;
} person, person_copy;
int main ()
{
char myname[] = "Pierre de Fermat";
/* using memcpy to copy string: */
memcpy ( person.name, myname, strlen(myname)+1 );
person.age = 46;
/* using memcpy to copy structure: */
memcpy ( &person_copy, &person, sizeof(person) );
printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age );
return 0;
}
12. memmove
10.1 功能:
Move block of memory 移动内存块
将num字节的值从源所指向的位置复制到目标所指向的内存块。
10.2 库函数形式
void * memmove ( void * destination, const void * source, size_t num );
10.3 注意事项:
复制就像使用中间缓冲区一样进行,允许目标和源重叠。
源指针和目标指针所指向的对象的基础类型与此函数无关;结果是数据的二进制副本。该函数不检查源中是否有任何终止空字符 - 它始终精确地复制数字字节。
为避免溢出,目标参数和源参数所指向的数组的大小应至少为 num 字节。
12.4 实例
int main ()
{
char str[] = "memmove can be very useful......";
memmove (str+20,str+15,11);
puts (str);
return 0;
}
13. memcmp
13.1 功能:
比较两个字符串
将ptr1指向的内存块的第一个字节数与ptr2指向的第一个数字字节进行比较
返回值 | 表明 |
---|---|
<0 | 在两个内存块中不匹配的第一个字节在ptr1中的值低于ptr2中的值(如果计算为无符号字符值) |
0 | 两个内存块的内容相等 |
>0 | 两个内存块中不匹配的第一个字节在ptr1中的值大于ptr2中的值(如果计算为无符号 char值) |
13.2 库函数形式
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
13.3 注意事项:
将ptr1指向的内存块的第一个字节数与ptr2指向的第一个数字字节进行比较,如果它们都匹配,则返回零,或者一个值不同于零,表示如果它们不匹配,则表示哪个值更大。请注意,与strcmp不同,该函数在找到空字符后不会停止比较。
13.4 实例
int main ()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n=memcmp ( buffer1, buffer2, sizeof(buffer1) );
if (n>0) printf ("'%s' is greater than '%s'.\n",buffer1,buffer2);
else if (n<0) printf ("'%s' is less than '%s'.\n",buffer1,buffer2);
else printf ("'%s' is the same as '%s'.\n",buffer1,buffer2);
return 0;
}
函数的模拟实现
strlen的模拟实现
//计数器方式
int my_strlen(const char *str) {
int count = 0;
while (*str) {
count++;
str++;
}
return count;
}
//不能创建临时变量计数器 --递归方式实现
int my_strlen(const char *str) {
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str + 1);
}
//指针的方式实现
int my_strlen(char *s) {
char *p = s;
while (*p != '\0')
p++;
return p - s;
}
strcpy的模拟实现
//1.参数顺序
//2.函数的功能,停止条件
//3.assert
//4.const修饰指针
//5.函数返回值
char *my_strcpy(char *dest, const char *src) {
char *ret = dest;
assert(dest != NULL);
assert(src != NULL);
while ((*dest++ = *src++)) { ;
}
return ret;
}
strcat的模拟实现
char *my_strcat(char *dest, const char *src) {
char *ret = dest;
assert(dest != NULL);
assert(src != NULL);
while (*dest) {
dest++;
}
while ((*dest++ = *src++)) { ;
}
return ret;
}
strstr的模拟实现
char *strstr(const char *str1, const char *str2) {
char *cp = (char *) str1;
char *s1, *s2;
if (!*str2)
return ((char *) str1);
while (*cp) {
s1 = cp;
s2 = (char *) str2;
while (*s1 && *s2 && !(*s1 - *s2))
s1++, s2++;
if (!*s2)
return (cp);
cp++;
}
return (NULL);
}
strcmp的模拟实现
int my_strcmp(const char *src, const char *dst) {
int ret = 0;
assert(src != NULL);
assert(dest != NULL);
while (!(ret = *(unsigned char *) src - *(unsigned char *) dst) && *dst)
++src, ++dst;
if (ret < 0)
ret = -1;
else if (ret > 0)
ret = 1;
return (ret);
}
memcpy的模拟实现
void *memcpy(void *dst, const void *src, size_t count) {
void *ret = dst;
assert(dst);
assert(src);
/*
* copy from lower addresses to higher addresses
*/
while (count--) {
*(char *) dst = *(char *) src;
dst = (char *) dst + 1;
src = (char *) src + 1;
}
return (ret);
}
memmove的模拟实现
void *memmove(void *dst, const void *src, size_t count) {
void *ret = dst;
if (dst <= src || (char *) dst >= ((char *) src + count)) {
/*
* Non-Overlapping Buffers
* copy from lower addresses to higher addresses
*/
while (count--) {
*(char *) dst = *(char *) src;
dst = (char *) dst + 1;
src = (char *) src + 1;
}
} else {
/*
* Overlapping Buffers
* copy from higher addresses to lower addresses
*/
dst = (char *) dst + count - 1;
src = (char *) src + count - 1;
while (count--) {
*(char *) dst = *(char *) src;
dst = (char *) dst - 1;
src = (char *) src - 1;
}
}
return (ret);
}