目录
求字符串长度:
size_t strlen ( const char * str );
无长度限制的字符串函数
字符串拷贝:
char * strcpy ( char * destination, const char * source );
字符串追加:
char * strcat ( char * destination, const char * source );
字符串比较:
int strcmp ( const char * str1, const char * str2 );
有长度限制的字符串函数
字符串拷贝:
char * strncpy ( char * destination, const char * source, size_t num );
字符串追加:
char * strncat ( char * destination, const char * source, size_t num );
字符串比较:
int strncmp ( const char * str1, const char * str2, size_t num );
字符串查找函数
在字符串中查找字符:
char * strchr ( const char * str, int character );
在一个字符串中查找另个一个字符串:
char * strstr ( const char * str1, const char * str2 );
字符串分割:
char * strtok ( char * str, const char * sep );
获取错误信息:
char * strerror ( int errnum );
字符操作函数
字符分类函数:
字符转换函数:
int tolower ( int ch );
int toupper ( int ch );
内存操作函数
内存拷贝:
void * memcpy ( void * destination, const void * source, size_t num );
内存移动:
void * memmove ( void * destination, const void * source, size_t num );
内存比较:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
内存填充:
void * memset ( void * ptr, int value, size_t num )
-
求字符串长度:
size_t strlen ( const char * str );
- 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' );
- str 指向的字符串必须要以 '\0' 结束;
- 注意函数的返回值为size_t,是无符号的;
- 若str 指向的字符串中有多个 ' \0 ',则strlen返回的是第一个' \0 '前的字符的个数。
有如下代码:
#include<stdio.h>
int main()
{
char arr1[] = "asdfghjkl";
int len1 = strlen(arr1);
char arr2[] = "asdf\0ghjkl";
int len2 = strlen(arr2);
printf("len1=%d\n", len1);
printf("len2=%d\n", len2);
return 0;
}
arr2数组比arr1数组中间多了一个' \0 ',因此使用strlen函数时,len1应为9,len2应为4。
代码运行结果:
用自定义函数实现:
int mystrlen(char* str)
{
int count = 0;
while (*str!='\0')
{
count++;
str++;
}
return count;
}
实例:
-
无长度限制的字符串函数
字符串拷贝:
char * strcpy ( char * destination, const char * source );
- 将source指向的字符串复制到destination指向的空间中,包括终止空字符(并在该点停止)。
- source指向的字符串不能为空,且必须以 '\0' 结束;
- 会将source指向的字符串中的 '\0' 拷贝到destination指向的空间中。
- destination指向的空间必须足够大,以确保能存放source指向的字符串。
- destination指向的空间必须可变。
- destination指向的空间与source指向的空间不应有重叠。
- 与strlen类似,strcpy遇到第一个‘ \0 ’时就会终止。
有如下代码:
int main()
{
char str[] = "asdfg\0hgfd";
char str1[] = "Sample string";
char str2[40] = { 0 };
char str3[40] = { 0 };
char str4[40] = { 0 };
strcpy(str2, str1);
strcpy(str3, "copy successful");
strcpy(str4, str);
printf("str1: %s\n", str1);
printf("str2: %s\n", str2);
printf("str3: %s\n", str3);
printf("str4: %s\n", str4);
return 0;
}
运行结果:
用自定义函数实现:
char* mystrcpy(char* des, const char* sour)
{
char* cur = des;
assert(des);
assert(sour);
while (*cur++ = *sour++)
{
;
}
return des;
}
实例:
字符串追加:
char * strcat ( char * destination, const char * source );
- 将source指向的字符串追加到destination后边,若destination后边有‘ \0 ’,会覆盖掉‘ \0
- destination指向的空间必须可修改且足够大。
- source指向的字符串不能为空,且必须以 '\0' 结束。
- destination指向的空间和source指向的空间不可重叠。
- 与strlen、strcpy类似,strcat遇到第一个‘ \0 ’时就会终止。
有如下代码:
int main()
{
char str[80] = { 0 };
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concat\0enated.");
puts(str);
return 0;
}
运行结果:
自定义函数实现:
char* mystrcat(char* des,const char* sour)
{
assert(des);
assert(sour);
char* cur = des;
while (*cur)//找到尾
{
cur++;
}
while (*cur++ = *sour++)
{
;
}
return des;
}
运行实例:
字符串比较:
int strcmp ( const char * str1, const char * str2 );
- 比较两个字符串str1和str2
- 从第一个字符开始依次比较,直至字符不同或到达终止字符
- 比较两个字符时,比较的是ASCII码
返回值 表明 <0
两个内存块中不匹配的第一个字节在 ptr1 中的值低于 ptr2 中的值 0
两个内存块的内容相等 >0
两个内存块中不匹配的第一个字节在 ptr1 中的值大于在 ptr2 中的值
有如下代码:
int main()
{
char str1[] = "abcdefg";
char str2[] = "abcdegh";
if (strcmp(str1, str2) > 0)
{
printf("str1>str2\n");
}
else if(strcmp(str1, str2) == 0)
{
printf("str1=str2\n");
}
else
{
printf("str1<str2\n");
}
return 0;
}
运行结果:
自定义函数实现:
int mystrcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return (*str1 - *str2);
}
实例:
-
有长度限制的字符串函数
字符串拷贝:
char * strncpy ( char * destination, const char * source, size_t num );
- 从source指向的字符串中拷贝num个字符到destination在指向的空间中
- destination指向空间要大于num个字节,否则无法在结尾追加终止字符
- destination指向的空间和source指向的空间不能有重叠
- 若source指向的字符串长度小于num,则拷贝完source指向的字符串后,继续在后边追加0,直至num个
- 若source指向的字符串长度大于等于num,则拷贝num个字符后停止,不会自动加‘ \0 ’
有如下代码:
int main()
{
char str1[] = "To be or not to be";
char str2[40] = "asdfghjklopiuytrewqbnchux";
char str3[40];
char str4[40];
char str5[40];
char str6[18];
char str7[10];
//拷贝长度等于str1长度
strncpy(str2, str1, strlen(str1));
//拷贝长度小于str1长度
strncpy(str3, str2, 5);
//拷贝长度等于str1长度
strncpy(str4, str1, strlen(str1));
//拷贝长度大于str1长度
strncpy(str5, str1, strlen(str1) + 5);
//目的地空间等于拷贝长度
strncpy(str6, str1, strlen(str1));
//目的地空间小于拷贝长度
strncpy(str7, str1, strlen(str1));
puts(str1);
puts(str2);
puts(str3);
puts(str4);
puts(str5);
puts(str6);
puts(str7);
return 0;
}
运行结果:
自定义函数实现:
char* mystrncpy(char* des, const char* sour, int num)
{
assert(des);
assert(sour);
assert(num >= 0);
char* cur = des;
while (num)
{
if (*sour == '\0')
{
break;
}
*cur++ = *sour++;
num--;
}
if (num != 0)
{
while (num--)
{
*cur++ = '\0';
}
}
return des;
}
实例:
字符串追加:
char * strncat ( char * destination, const char * source, size_t num );
- 在destination指向字符串末尾追加source指向字符串的前num个字符,并额外追加一个终止字符。
- 若num大于source指向字符串长度,则仅复制终止字符之前的内容。
有如下代码:
int main()
{
char str[] = "asdfg\0hjk";
char str1[6] = "e";
char str2[10] = "q";
char str3[10] = "w";
strncat(str1, str, 9);
strncat(str2, str, 9);
strncat(str3, str, 3);
puts(str1);
puts(str2);
puts(str3);
return 0;
}
运行结果:
观察可以发现即使str1指向空间不够额外追加终止字符,strncat也会在str1指向空间后边强制追加一个终止字符。 自定函数实现:
char* mystrncat(char* des, const char* sour, int num)
{
assert(des);
assert(sour);
assert(num >= 0);
char* cur = des;
while (*cur)
{
cur++;
}
while (num)
{
if (*sour == '\0')
{
break;
}
*cur++ = *sour++;
num--;
}
*cur = '\0';
return des;
}
实例;
字符串比较:
int strncmp ( const char * str1, const char * str2, size_t num );
- 比较两个字符串str1和str2前num个字符
- 从第一个字符开始依次比较,直至字符不同或到达终止字符或到达第num个字符
- 比较两个字符时,比较的是ASCII码
返回值 表明 <0
两个内存块中不匹配的第一个字节在 ptr1 中的值低于 ptr2 中的值 0
两个内存块的内容相等 >0
两个内存块中不匹配的第一个字节在 ptr1 中的值大于在 ptr2 中的值
有如下代码:
int main()
{
char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
int n;
for (n = 0; n < 3; n++)
{
//找前两个字符为“R2”的字符串
if (strncmp(str[n], "R2xx", 2) == 0)
{
printf("found %s\n", str[n]);
}
}
return 0;
}
运行结果:
自定义函数实现:
int mystrncmp(const char* str1, const char* str2, int num)
{
assert(str1 && str2);
assert(num > 0);
while ((*str1 == *str2) && num--)
{
if (*str1 == '\0'||num == 0)
{
return 0;
}
str1++;
str2++;
}
return (*str1 - *str2);
}
实例:
-
字符串查找函数
在字符串中查找字符:
char * strchr ( const char * str, int character );
- 在字符串str中找字符character,并返回指向该字符的指针,若找不到返回NULL。
- 终止字符‘ \0 ’也被视为字符串str的一部分,因此也可以查找。
- 字符character以int类型传递,但在内部会转换为char类型进行查找。
有如下代码:
int main()
{
char str[] = "This is a sample string";
char* pch = NULL;
printf("Looking for the 's' character in \"%s\"\n", str);
pch = strchr(str, 's');
while (pch != NULL)
{
printf("found at %d\n", pch - str + 1);
pch = strchr(pch + 1, 's');
}
int len = strlen(str);
printf("len = %d\n", len);
pch = strchr(str, '\0');
printf("pch - str = %d\n", pch - str);
return 0;
}
运行结果:
自定义函数实现:
char* mystrchr(const char* str, int ch)
{
assert(str);
if (ch == '\0')
{
while (*str)
{
str++;
}
return str;
}
while (*str)
{
if (*str == ch)
{
return str;
}
str++;
}
return NULL;
}
实例:
在一个字符串中查找另个一个字符串:
char * strstr ( const char * str1, const char * str2 );
- 在str1中找str2第一次出现的位置并返回该位置的指针,否则返回NULL
- 匹配过程不包括‘ \0 ’
有如下代码:
int main()
{
char str[] = "This is a simple string";
char* pch;
pch = strstr(str, "simple");
puts(pch);
if (pch != NULL)
{
strncpy(pch, "SAMPLE", 6);
}
puts(pch);
return 0;
}
运行结果:
自定义函数实现:
char* mystrstr(const char *str1, const char* str2)
{
char* cp = str1;
char* s1 = cp;
char* s2 = str2;
if (*str2 == '\0')
{
return str1;
}
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
cp++;
}
return NULL;
}
实例:
字符串分割:
char * strtok ( char * str, const char * sep );
- sep参数是个字符串,定义了用作分隔符的字符集合
- 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
- strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
- strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
- 如果字符串中不存在更多的标记,则返回 NULL 指针。
有如下代码:
int main()
{
char arr[] = "asdfgh@yeah.net@666#777";
char copy[30];
strcpy(copy, arr);
char sep[] = "@#.";
char* ret = NULL;
for (ret = strtok(copy, sep); ret != NULL; ret=strtok(NULL, sep))
{
printf("%s\n", ret);
}
return 0;
}
运行结果:
-
获取错误信息:
char * strerror ( int errnum );
- 返回错误码errnum所对应的错误信息
有如下代码:打印错误码0~9所对应的错误信息
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d: %s\n", i, strerror(i));
}
return 0;
}
运行结果:
-
字符操作函数
使用字符操作函数徐要包含头文件<ctype.h>
字符分类函数:
函数 | 如果他的参数符合下列条件就返回真 |
iscntrl | 任何控制字符 |
isspace | 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v' |
isdigit | 十进制数字 0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 字母a~z或A~Z |
isalnum | 字母或者数字,a~z,A~Z,0~9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
字符转换函数:
int tolower ( int ch );
- 若ch是大写字母,则转换为小写字母
int toupper ( int ch );
- 若ch是小写字母,则转换为大写字母
有如下代码:
#include <ctype.h>
int main()
{
int i = 0;
char str[] = "Test String.";
puts(str);
char c;
while (str[i])
{
c = str[i];
if (isupper(c))
{
c = tolower(c);
}
putchar(c);
i++;
}
printf("\n");
i = 0;
while (str[i])
{
c = str[i];
if (islower(c))
{
c = toupper(c);
}
putchar(c);
i++;
}
return 0;
}
运行结果:
-
内存操作函数
内存函数的操作对象不再局限于字符串
内存拷贝:
void * memcpy ( void * destination, const void * source, size_t num );
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
- 这个函数在遇到 '\0' 的时候并不会停下来。
- source和destination不能有重叠,如果source和destination有任何的重叠,复制的结果都是未定义的。
有如下代码:
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00
int arr2[20] = { 0 };
memcpy(arr2, arr1, 21);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
运行结果:
自定义函数实现:
void* mymemcpy(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(src && dest);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
实例:
内存移动:
void * memmove ( void * destination, const void * source, size_t num );
- 和memcpy的差别就是memmove函数处理的destination和source是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
有如下代码:
int main()
{
char str[] = "memmove can be very useful....?!";
puts(str);
memmove(str + 20, str + 15, 11);
puts(str);
return 0;
}
运行结果:
自定义函数实现:
void* mymemmove(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
if (dest < src)
{
//前->后
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//后->前
while (num--)//20
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
实例:
内存比较:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
- 比较从ptr1和ptr2指向位置开始的前num个字节的内容,如果它们都相等,则返回零,如果不匹配,则返回一个不同于零的值,表示哪个值更大。(注意:与 strcmp 不同,该函数在找到空字符后不会停止比较。)
返回值 表明 <0
两个内存块中不匹配的第一个字节在 ptr1 中的值低于 ptr2 中的值 0
两个内存块的内容相等 >0
两个内存块中不匹配的第一个字节在 ptr1 中的值大于在 ptr2 中的值
有如下代码:
int main()
{
int arr1[] = { 1,2,3,4,5 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
int arr2[] = { 1,2,257 }; //01 00 00 00 02 00 00 00 01 01 00 00
int ret = memcmp(arr1, arr2, 10);
printf("%d\n", ret);
return 0;
}
运行结果:
自定义函数实现:
int mymemcmp(const void* str1, const void* str2, int len)
{
assert(str1);
assert(str2);
while ((*(char*)str1 == *(char*)str2) && len--)
{
if (len == 0)
{
return 0;
}
str1 = (char*)str1 + 1;
str2 = (char*)str2 + 1;
}
if (*(char*)str1 > *(char*)str2)
{
return 1;
}
if (*(char*)str1 < *(char*)str2)
{
return -1;
}
}
实例:
内存填充:
void * memset ( void * ptr, int value, size_t num );
- 从ptr指向位置开始向后num个字节填充为value,且不会因遇到终止字符而停止
有如下代码:
int main()
{
char arr[] = "hellohehe";
memset(arr+1,'x',5);
printf("%s\n", arr);
return 0;
}
运行结果:
自定义函数实现:
void* mymemset(void* ptr, int val, size_t num)
{
assert(ptr);
void* cur = ptr;
while (num--)
{
*(char*)cur = val;
cur = (char*)cur + 1;
}
return ptr;
}
实例: