常用函数的介绍
求字符串长度
strlen(计算字符串长度)
调用函数要包含头文件<string.h>
size_t strlen ( const char* str );
- 字符串已经’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数{不包含’\0’)。
- 参数指向的字符串必须要以’\0’结束。
例:
#include <stdio.h>
#include <string.h>
int main()
{
const char* str1 = "abcdef";
const char* str2 = "abc";
if (strlen(str2) - strlen(str1) > 0)
{
printf("str2 > str1\n");
}
else
{
printf("str1 > str2\n");
}
return 0;
}
//输出的结果是:str2 > str1
这里我们发现输出的结果是错误的,正确的结果是str1 > str2。
原因:因为strlen的返回类型是size_t,而size_t与unsigned int等价,所以两个无符号数相减得到的还是无符号数3-6的结果是无符号数3所以最后输出的结果是错误的。
长度不受限制的字符串函数
strcpy(拷贝字符串)
调用函数要包含头文件<string.h>
char* strcpy ( char* destination, const char* source );
- 源字符串必须以’\0’结束。
- 会将源字符串中的’\0’拷贝到目标空间里。
- 目标空间必须足够大,以确保能存放源字符串,不然会出错。
- 目标空间必须可变,不能是常量字符串(char* p = “abcd”)。
例:
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdefghi";
char arr2[] = "love";
//错误的示范
//char arr2[] = { 'l','o','v','e' };
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
//输出的结果是:love
模拟实现:
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
//拷贝str指向的字符串到dest指向的空间,包含'\0'
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[] = "abcdefghi";
char arr2[] = "love";
//错误的示范
//char arr2[] = { 'l','o','v','e' };
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
//输出的结果是:love
strcat(追加字符串)
调用函数要包含头文件<string.h>
char* strcat ( char* destination, const char* source );
- 源字符串必须以’\0’结束。
- 目标字符串必须足够大,能容纳下源字符串的内容。(目标空间要有’\0’,因为要先寻找到目标空间的’\0’才能追加)
- 目标空间必须可修改。
- 字符串自己不能给自己追加。(会导致死循环,因为在追加第一个字符时,源字符串的’\0’就没了)
例:
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "I love";
char arr2[] = " you";
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
//输出的结果是:I love you
模拟实现:
#include <stdio.h>
#include <assert.h>
my_strcat(char* dest, const char* src)
{
assert(dest != NULL);
assert(src);
char* ret = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "I love";
char arr2[] = " you";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
//输出的结果是:I love you
strcmp(比较两个字符串)
调用函数要包含头文件<string.h>
int strcmp ( const char* str1, const char* str2 );
标准规定:
- 第一个字符串大于第二个字符串,则返回大于0的数字。
- 第一个字符串等于第二个字符串,则返回0。
- 第一个字符串小于第二个字符串,则返回小于于0的数字。
注:在VS中返回的是1, 0 ,-1。
例:
#include <stdio.h>
#include <string.h>
int main()
{
char* p1 = "qbc";
char* p2 = "abc";
if (strcmp(p1, p2) > 0)
{
printf("p1>p2\n");
}
else if (strcmp(p1, p2) < 0)
{
printf("p1<p2");
}
else
{
printf("p1==p2");
}
return 0;
}
//输出的结果是:p1 > p2
模拟实现:
#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* str1,const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return (*str1 - *str2);
}
int main()
{
char* p1 = "abc";
char* p2 = "abcd";
int ret = my_strcmp(p1, p2);
printf("%d\n", ret);
return 0;
}
//输出的结果是:-100
上面的三个函数都要到’\0’才停止,很不安全。
长度受限制的字符串函数
strncpy(拷贝字符串,可以控制拷贝的字符的个数)
调用函数要包含头文件<string.h>
char* strncpy ( char* destination, const char* source, size_t num );
- 拷贝num个字符从源字符串到目标空间。
- 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标空间后边追加0,直到num个。
例:
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[10] = "abcdefghi";
char arr2[] = "I love";
strncpy(arr1, arr2, 6);
printf("%s\n", arr1);
return 0;
}
//输出的结果是:I loveghi
strncat(追加,可以控制追加的字符的个数)
调用函数要包含头文件<string.h>
char* strncat ( char* destination, const char* source, size_t num );
例:
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[30] = "I";
char arr2[] = " love you";
strncat(arr1, arr2, 5);
printf("%s\n", arr1);
return 0;
}
//输出的结果是:I love
strncmp(比较两个字符串,可以控制比较的字符的个数)
调用函数要包含头文件<string.h>
int strncmp ( const char* str1, const char* str2, size_t num );
- 比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
例:
#include <stdio.h>
#include <string.h>
int main()
{
const char* p1 = "abcdef";
char* p2 = "abcqwer";
int ret = strncmp(p1, p2, 4);
printf("%d\n", ret);
return 0;
}
//输出的结果是:-1
字符串查找
strstr(查找一个字符串内是否含有另一个字符串)
调用函数要包含头文件<string.h>
char* strstr ( const char* str1, const char* str2 );
- 是在str1中查找是否含有str2,若不含有则返回NULL(空指针),若含有则返回str1中第一次出现str2时的地址。
例:
#include <stdio.h>
#include <string.h>
int main()
{
char* p1 = "abbbcdef";
char* p2 = "bbc";
char* ret = strstr(p1, p2);
if (ret == NULL)
{
printf("子串不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
//输出的结果是:bbcdef
模拟实现:
#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* p1, const char* p2)
{
assert(p1 && p2);
char* s1 = NULL;
char* s2 = NULL;
char* cur = (char*)p1;
if (*p2 == '\0')
{
return (char*)p1;
}
while (*cur)
{
s1 = cur;
s2 = (char*)p2;
while (*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cur;
}
if (*s1 == '\0')
{
return NULL;
}
cur++;
}
return NULL;
}
int main()
{
char* p1 = "abbbcdef";
char* p2 = "bbc";
char* ret = my_strstr(p1, p2);
if (ret == NULL)
{
printf("子串不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
//输出的结果是:bbcdef
strtok(切割字符串)
调用函数要包含头文件<string.h>
char* strtok ( char* str, const char* sep );
- sep参数是一个字符串,定义了用作分割符的字符集合。
- str参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分割符分割的标记。
- strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可以修改)
- strtok函数的str参数不能为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置。
- strtok函数的str参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
- 如果字符串中不存在更多的标记,则返回NULL指针。
例:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "I@.love.you";
char* p = "@.";
char buf[1024] = { 0 };
strcpy(buf, arr);
char* ret = NULL;
for (ret = strtok(buf, p); ret != NULL; ret = strtok(NULL, p))
{
printf("%s\n", ret);
}
return 0;
}
//输出的结果是:I
// love
// you
错误信息报告
strerror
调用函数要包含头文件<string.h>
char* strerroe ( int errnum );
- 返回错误码,所对应的错误信息。
例:
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
//错误码 错误信息
//0 - No error
//1 - Operation not permitted
//2 - No such file or directory
//...
//errno是一个全局的错误码的变量
//当c语言的库函数在执行过程中,发生了错误,就会把对应的错误码,赋值到errno中
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
}
else
{
printf("open file success\n");
}
return 0;
}
//输出的结果是:No such file or directory(没有这样的文件或目录)
strerror函数要和errno函数一起使用,在使用errno时需要引用头文件#include <errno.h>
字符分类函数
调用函数要包含头文件<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 | 任何可打印字符,包括图形字符和空白字符 |
例:
#include <ctype.h>
int main()
{
char ch = '2';
int ret = islower(ch);
printf("%d\n", ret);
ret = isdigit(ch);
printf("%d\n", ret);
return 0;
}
//输出的结果是:0
// 不为0的随机数
字符转换函数:
int tolower ( int c );//大写字母转换成小写
int toupper ( int c );//小写字母转换成大写
例:
#include <ctype.h>
int main()
{
char arr[] = "I love you";
int i = 0;
while (arr[i])
{
if (isupper(arr[i]))
{
arr[i] = tolower(arr[i]);
}
i++;
}
printf("%s\n", arr);
i = 0;
while (arr[i])
{
if (islower(arr[i]))
{
arr[i] = toupper(arr[i]);
}
i++;
}
printf("%s\n", arr);
return 0;
}
//输出的结果是:i love you
// I LOVE YOU
内存操作函数
内存操作函数是可以作用于所有类型的函数
memcpy
调用函数要包含头文件<string.h>
void* memcpy ( void* destination, const void* source, size_t num );
- memcpy函数中参数和返回值的类型都是void*(无类型),因为函数不知道我们使用什么类型,所以留给程序员自己操作。
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
- 这个函数在遇到’\0’的时候并不会停下来。
- 如果source和destination有任何的重叠,复制的结果都是未定义的。
例:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[5] = { 0 };
memcpy(arr2, arr1, sizeof(arr1));
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", arr2[i]);
}
printf("\n");
struct S arr3[] = { {"张三",20},{"李四",30} };
struct S arr4[3] = { 0 };
memcpy(arr4, arr3, sizeof(arr3));
for (i = 0; i < 3; i++)
{
printf("%s %d ", arr4[i].name,arr4[i].age);
}
return 0;
}
//输出的结果是:1 2 3 4 5
// 张三 20 李四 30 0
模拟实现:
#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
while (num--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[5] = { 0 };
my_memcpy(arr2, arr1, sizeof(arr1));
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", arr2[i]);
}
printf("\n");
struct S arr3[] = { {"张三",20},{"李四",30} };
struct S arr4[3] = { 0 };
my_memcpy(arr4, arr3, sizeof(arr3));
for (i = 0; i < 3; i++)
{
printf("%s %d ", arr4[i].name,arr4[i].age);
}
return 0;
}
//输出的结果是:1 2 3 4 5
// 张三 20 李四 30 0
memmove
调用函数要包含头文件<string.h>
void* memmove ( void* destination, const void* source, size_t num );
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
例:
#include <stdio.h>
#include <string.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
memmove(arr+2, arr, 20);
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
//输出的结果是:1 2 1 2 3 4 5 8 9 10
模拟实现:
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t count)
{
void* ret = dest;
assert(dest && src);
if (dest < src)
{
while (count--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
}
else
{
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
my_memmove(arr, arr + 2, 20);
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
//输出的结果是:3 4 5 6 7 6 7 8 9 10
memset
调用函数要包含头文件<string.h>
void* memset ( void* dest, int c, size_t count );
- memset函数是设置缓冲区为一个特定的字符。
例:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[10] = "";
memset(arr, '#', 10);
//是将arr数组里面的内容替换成字符#替换了10个字节
int arr1[10] = { 0 };
memset(arr1, 1, 10);
//是将arr1数组里面的内容替换成1替换了10个字节因为arr1是整形有40个字节,最终改变的只有前三个元素
return 0;
}
memcmp
调用函数要包含头文件<string.h>
int memcmp ( const void* ptr1, const void* ptr2, size_t num );
- 比较ptr1和ptr2指针开始的num个字节
- 返回值
情况 | 返回值 |
---|---|
ptr1<ptr2 | 返回一个小于0的随机数 |
ptr1=ptr2 | 返回0 |
ptr1>ptr2 | 返回一个大于0的随机数 |
例:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,5,4,3 };
//01 00 00 00 02 00 00 00 03 00 00 00 ...
//01 00 00 00 02 00 00 00 05 00 00 00 ...
int ret = memcmp(arr1, arr2, 9);
//比较九个字节那就是从第一个字节开始比较直到第九个字节我们才发现不一样最终得知会输出一个小于0的随机数但在VS编译器中所以返回值是-1
printf("%d\n", ret);
return 0;
}
//输出的结果是:-1
- 本篇文章当中有些函数进行了模拟实现,希望大家看完可以自己去实现一下来增加记忆。
- 本篇文章只是找了一些常见的函数,如果想知道更多更详细的介绍可以去cplusplus网站去进行搜索。