1.strlen函数
-
size_t strlen ( const char * str );
函数功能:
- 获取字符串的长度,即返回一个字符串到中到\0'字符之前的的字符个数
//int main()
//{
// char* arr = "abcdef";
// size_t len = strlen(arr);
// printf("%d\n", len);//6
//
// return 0;
//}int main()
{char* arr = "abc\0def";size_t len = strlen(arr);printf("%d\n", len);//3return 0;
}
注意:strlen的返回值是size_t类型,是无符号的
int main()
{char str1[] = "abcdef";char str2[] = "bbb";if (strlen(str2) - strlen(str1) > 0){printf("str2>str1\n");}else{printf("srt1>str2\n");}return 0;
}
代码解读:
- 因为strlen的返回值是size_t类型的,两个size_t类型的值相减,结果仍然是size_t类型
3-6结果是-3,因为是size_t类型,会被编译器当成一个很大的正数,因此打印str2>str1
1.1strlen的模拟实现
方法1:计数器
size_t my_strlen(const char* str)
{assert(str);char* p = str;int count = 0;while (*p != '\0'){count++;p++;}return count;
}
方法2:递归
size_t my_strlen(const char* str)
{assert(str);char* p = str;if (*p == '\0')return 0;return 1 + my_strlen(p + 1);
}
方法三:指针-指针
size_t my_strlen(const char* str)
{assert(str);char* p = str;while (*p != '\0'){p++;}return (p - str);
}
2.strcpy函数
-
char * strcpy ( char * destination, const char * source );
函数功能:
- 将source处的内容拷贝到destination指向的空间,包括'\0'
注意事项:
- source中的内容要有'\0'
- 会将'\0'一起拷贝
- destination指向的空间要足够大
2.1strcpy的模拟实现
char* my_strcpy(char* destination, const char* source)
{assert(destination && source);char* ret = destination;while (*destination++ = *source++){;}return ret;
}
3.strcat函数
-
char * strcat ( char * destination, const char * source );
函数功能:
- 在destination末尾追加字符串source
注意事项:
- 先找到destination字符串中的'\0',在'\0'处开始拷贝
- 会将source字符串中的'\0'一起拷贝
- destination字符串必须要有'\0';source字符串也必须要有'\0'
- destination的空间必须足够大
3.1strcat的模拟实现
char* my_strcat(char* destination, const char* source)
{assert(destination && source);char* ret = destination;//找到'\0'while (*destination++){;}//拷贝while (*destination++ = *source++){;}return ret;
}
问:能不能自己给自己追加?
答:我们自己写的模拟实现代码是不能追加给自己追加的,程序会陷入死循环;库函数中的strcat更加完善,能够完成自己追加自己,但还是不建议这样做
4.strcmp函数
-
int strcmp ( const char * str1, const char * str2 );
函数功能:
- 比较两个字符串
注意事项:
- str1>str2,返回正数
- str1==str2,返回0
- str1<str2,返回负数
int main()
{char arr1[] = "abcdef";char arr2[] = "abcdeg";int ret = strcmp(arr1, arr2);if (ret > 0)printf("str1 > str2\n");else if (ret == 0)printf("str1 == str2\n");elseprintf("str1 < str2\n");return 0;
}//输出:str1 < str2
4.1strcmp的模拟实现
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;
}
上面的strcpy,strcat都是长度不受限制的字符串函数,与它们相对应的是长度受限制的字符串函数
5.strncpy函数
-
char * strncpy ( char * destination, const char * source, size_t num );
函数功能:
- 相较于strcpy,strncpy函数多了一个num参数,该参数表示要拷贝的字节个数
也就是我们可以指定拷贝的字符个数
注意事项:
- destination指向的空间必须足够大
- 如果source中的字符串个数小于num,则拷贝完source的字符串后自动补'\0'
- 如果source中的字符串个数大于num,则仅拷贝num个字符,不会加上'\0'
int main()
{char arr1[20] = "xxxxxxxxx";char arr2[] = "abcde";strncpy(arr1, arr2, 3);printf("%s\n", arr1);return 0;
}//输出:abcxxxxxx
5.1strncpy的模拟实现
char* my_strncpy(char* destination, const char* source, int num)
{assert(destination && source);char* ret = destination;while (num--){if (*source == '\0')*destination++ = '\0';else*destination++ = *source++;}return ret;
}
6.strncat函数
-
char * strncat ( char * destination, const char * source, size_t num );
函数功能:
- 从source中追加num个字符到destination中
注意事项:
- destination的空间必须足够大
- 如果source字符串个数小于num,则相当于追加source字符串
- 如果source字符串个数大于num,则追加完num个字符后,自动补上'\0'
6.1strncat的模拟实现
char* my_strncat(char* destination, const char* source, int num)
{assert(destination && source);char* ret = destination;//找'\0'while (*destination != '\0'){destination++;}while (num--){if (num < 0 || *source == '\0')break;*destination++ = *source++;}*destination = '\0';return ret;
}
7.strncmp函数
-
int strncmp ( const char * str1, const char * str2, size_t num );
函数功能:
- 比较str1和str2中前num个字符构成的字符串的大小
int main()
{char arr1[] = "abcdef";char arr2[] = "abcdef";int ret = strncmp(arr1, arr2, 3);if (ret > 0)printf("str1>str2\n");else if (ret == 0)printf("str1==str2\n");elseprintf("str1<str2\n");return 0;
}
//输出:str1 == str2
8.strstr函数
-
const char * strstr ( const char * str1, const char * str2 );
函数功能:
- 在字符串str1中查找字符串str2
- 如果找到了,返回str2第一个字符在str1中的地址;如果找不到,返回NULL
int main()
{char arr1[] = "abcdef";char arr2[] = "cde";char* ret = strstr(arr1, arr2);if (ret)printf("%s\n", ret);elseprintf("找不到\n");return 0;
}
//输出:cdef
8.1strstr的模拟实现
char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);if (*str2 == '\0')return str1;int i = 0;//str1的下标int j = 0;//str2的下标while (str1[i]){while (str1 && str2 && str1[i] == str2[j]){i++;j++;}if (str2[j] == '\0')return str1 + i - j;i = i - j + 1;j = 0;}return NULL;
}
9.strtok
-
char * strtok ( char * str, const char * delimiters );
函数功能:
- 根据delimiters中的字符分割str字符串中的内容
int main()
{char arr1[] = "baiyahua@qq.com";char arr2[] = "@.";char* ret = strtok(arr1, arr2);printf("%s\n", ret);return 0;
}
//输出:baiyahua
注意事项:
- delimiters中是自己定义的分隔符的集合
- str中包含delimiters中的分隔符
- 如果strtok的第一个参数不为空,会将str中的第一个分隔符替换成'\0',并记录该位置,返回起始位置的地址
- 如果strtok的第一个参数为空,从上次记录的位置开始寻找分隔符
- 如果没有找到分隔符,返回NULL
由于strtok会改变字符串的内容,所以我们一般先拷贝一份原来的字符串,对拷贝的字符串进行操作
int main()
{char arr1[] = "baiyahua@qq.com";char* p = "@.";char copyArr1[50] = { 0 };strcpy(copyArr1, arr1);char* s = strtok(copyArr1, p);while (s != NULL){printf("%s\n", s);s = strtok(NULL, p);}return 0;
}
//输出:
//baiyahua
//qq
//com
10.strerror
-
char * strerror ( int errnum );
函数功能:
- 翻译错误码对应的错误信息,并返回错误信息的起始地址
在C语言中,使用库函数发生错误时,会将错误码存放在一个叫errno的全局变量中;strerror的作用就是返回errnum中的值所对应的错误信息,然后返回错误信息的起始地址
int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){printf("打开文件失败,原因是:%s\n", strerror(errno));return 0;}else{printf("打开文件成功\n");}fclose(pf);pf = NULL;return 0;
}
//输出:打开文件失败,原因是: No such file or directory
10.1perror
-
void perror ( const char * str );
函数功能:
- 直接将错误码翻译成错误信息,并打印出来
perror相当于strerror+printf;在使用库函数出错时,它首先会打印str字符串,再将错误码对应的错误信息打印
int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("打开文件失败,原因是");return 0;}else{printf("打开文件成功\n");}fclose(pf);pf = NULL;return 0;
}
//输出:打开文件失败,原因是: No such file or directory
strerror和perror
- 如果只想要错误码对应的错误信息,用strerror
- 如果还想打印出错误信息,用perror更方便
11.字符函数
11.1字符分类函数
常见的字符分类函数:
函数 | 符合下面的条件返回真 |
iscntrl | 任何控制字符 |
isspace | 空白字符,空格' ',换页'\f',换行'\n',回车'\r',制表符'\t',垂直制表符'\v' |
isdigit | 数字0~9 |
isxdigit | 十六进制数字,0~9,a~f或A~F |
islower | 小写字母,a~z |
isupper | 大写字母,A~Z |
isalpha | 字母,a~z,A~Z |
isalnum | 字母或数字,0~9,a~z,A~Z |
ispunct | 标点符号,任何不属于数字或字母的可打印字符 |
isgraph | 任何图形字符 |
isprint | 任何可打印字符 |
我们就拿其中一个函数举例,其他函数同理
isdigit函数
- int isdigit ( int c );
函数功能:
- 判断c是否是一个数字字符,如果是数字返回非0;如果不是,返回0
int main()
{int ch = '1';if (isdigit(ch))printf("是数字字符\n");elseprintf("不是数字字符\n");return 0;
}
//输出:是数字字符
11.2字符转换函数
-
int toupper ( int c );
-
int tolower ( int c );
函数功能:
- toupper:如果c是小写字母,则返回c的大写字母;否则就直接返回c
- tolower:如果c是大写字母,则返回c的小写字母;否则就直接返回c
int main()
{char arr[] = "Test String.\n";char* p = arr;while (*p){if (isupper(*p))*p = tolower(*p);p++;}printf("%s\n", arr);return 0;
}
//输出:test string.
12.内存函数
12.1memcpy函数
-
void * memcpy ( void * destination, const void * source, size_t num );
函数功能:
- 从source指向的内存拷贝num个字节到destination中,返回destination首元素的地址
前面的strcpy是只能对字符串进行拷贝的函数,而memcpy能对任意类型的数据进行拷贝
int main()
{int arr1[20] = { 0 };int arr2[] = { 1,2,3,4,5,6,7 };memcpy(arr1, arr2, 20);for (int i = 0; i < 5; i++){printf("%d ", arr1[i]);}printf("\n");return 0;
}
//输出1 2 3 4 5
12.1.1memcpy的模拟实现
void* my_memcpy(void* destination, const void* source, size_t num)
{assert(destination && source);void* ret = destination;while (num--){*(char*)destination = *(char*)source;destination = (char*)destination + 1;source = (char*)source + 1;}return destination;
}
如果我们想要对重叠的内存进行拷贝,my_memcpy是完成不了的;库函数中的memcpy虽然可以进行重叠内存的拷贝,但我们规定好:
- 两段不重叠的内存拷贝用memcpy
- 两段有重叠的内存拷贝用memmove
12.2memmove函数
-
void * memmove ( void * destination, const void * source, size_t num );
函数功能:
- 从source指向的内存拷贝num个字节到destination中,返回destination首元素的地址
同样是拷贝内存,用法也与memcpy一样,只不过对于重叠内存的拷贝我们一般选择memmove
12.2.1memmove的模拟实现
void* my_memmove(void* destination, const void* source, size_t num)
{assert(destination && source);void* ret = destination;if (source < destination){//从后往前拷贝while (num--){*((char*)destination + num) = *((char*)source + num);}}else{//从前往后拷贝while (num--){*(char*)destination = *(char*)source;destination = (char*)destination + 1;source = (char*)source + 1;}}return ret;
}
12.3memset函数
-
void * memset ( void * ptr, int value, size_t num );
函数功能:
- 设置ptr指向内存的内容改为value;以字节为单位,一共该num个字节
int main()
{char arr[] = "Welcome to my world.\n";memset(arr + 14, 'x', 3);printf("%s", arr);return 0;
}
//输出:Welcome to my xxxld.
注意事项:
- 该函数是以字节为单位进行修改的,每次只会修改一个字节
12.4memcmp函数
-
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
函数功能:
- 以字节为单位比较两块内存
- ptr1>ptr2,返回正数;
- ptr1==ptr2,返回0
- ptr1<ptr2,返回负数
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8 };int arr2[] = { 1,2,3,4,0x11111105 };int ret = memcmp(arr1, arr2, 17);printf("%d\n", ret);return 0;
}
//输出0,前16字节都是相等
//arr1和arr2的第十七字节数据都是05,所以相等
字符函数和字符串函数的内容就到这!