目录
一、strlen
1.参数指向的字符串必须要以 '\0' 结束。
2.注意strlen函数的返回值为size_t,是无符号的
3.模拟实现strlen
二、strcpy
1.源字符串中的 '\0' 拷贝到目标空间
2.源字符串必须以 '\0' 结束
3.目标空间必须足够大,以确保能存放源字符串
4.模拟实现strcpy
三、strcat
1.源字符串必须以 '\0' 结束
2.模拟实现strcat
四、strcmp
1.标准规定
2.模拟实现strcmp
五、小结
六、strncpy
七、strncat
八、 strncmp
九、strstr
9.1模拟实现strstr
十、strtok
十一、strerror
十二、字符分类函数:
十三、memcpy
1.memcpy:内存拷贝
2.模拟实现memcpy
十四、memmove
十五、memset
一、strlen
strlen:求字符串长度的,统计的是字符串中\0之前出现的字符个数(不包含 '\0' )
1.参数指向的字符串必须要以 '\0' 结束。
int main()
{//a b c \0 d e f \0char arr[] = "abc\0def";printf("%d\n", strlen(arr));return 0;
}
此结果输出为 3(\0结束)
2.注意strlen函数的返回值为size_t,是无符号的
#include <string.h>
int main()
{if (strlen("abc") - strlen("abcdef") > 0)printf(">\n");elseprintf("<\n");return 0;
}
对于此代码,大家第一眼看到的肯定是小于,则不然,输出结果为 >
size_t,是无符号的整形(无符号减无符号为无符号),不可能返回负数
3.模拟实现strlen
#include <assert.h>
size_t my_strlen(const char* str)//不会改arr,最好使用const
{assert(str);//保证str为空指针const char* start = str;//记录起始位置const char* end = str;//记录末尾位置while (*end != '\0'){end++;//从a往后走直到指向\0}return end - start;//得到指针个数
}int main()
{char arr[] = "abcdef";int len = my_strlen(arr);printf("%d\n", len);return 0;
}
运行结果:
二、strcpy
strcpy:字符串拷贝
1.源字符串中的 '\0' 拷贝到目标空间
#include <string.h>int main()
{char arr[10] = "xxxxxxxxxx";const char* p = "abcdef";strcpy(arr, p);printf("%s\n", arr);return 0;
}
2.源字符串必须以 '\0' 结束
2.1 没有‘ \0 ’
int main()
{char arr[10] = "xxxxxxxxx";char arr2[] = { 'b', 'i', 't'};strcpy(arr, arr2);printf("%s\n", arr);return 0;
}
1.2有‘ \0 ’
#include <stdio.h>
int main()
{char arr[10] = "xxxxxxxxx";char arr2[] = { 'b', 'i','\0', 't'};;strcpy(arr, arr2);printf("%s\n", arr);return 0;
}
3.目标空间必须足够大,以确保能存放源字符串
#include <string.h>
int main()
{char arr[3] = {0};char arr2[] = "abcdef";strcpy(arr, arr2);printf("%s\n", arr);return 0;
}
4.模拟实现strcpy
char* my_strcpy(char* dest, const char* src)
{assert(dest);//断言,保证有效性assert(src);char* ret = dest;while (*dest++ = *src++){;}return ret;
}int main()
{char arr1[20] = "abc";char arr2[] = "hello bit";printf("%s\n", my_strcpy(arr1, arr2));return 0;
}
三、strcat
strcat:字符追加函数
#include <string.h>
int main()
{char arr1[20] = "hello ";char arr2[] = "world";strcat(arr1, arr2);//字符追加函数printf("%s\n", arr1);return 0;
}
1.源字符串必须以 '\0' 结束
2.模拟实现strcat
#include <string.h>
#include <stdio.h>
char* my_strcat(char* dest, const char*src)
{//1.找目标空间中的\0char* cur = dest;while (*cur){cur++;}//2.拷贝源头数据到\0之后的空间while (*cur++ = *src++){;}return dest;
}int main()
{char arr1[20] = "hello \0xxxxxxxxxx";char arr2[] = "world";printf("%s\n", my_strcat(arr1, arr2));return 0;
}
四、strcmp
strcmp:字符串比较(比较的是对应位置上字符的大小,而非长度)必须以 '\0' 结束
1.标准规定
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
2.模拟实现strcmp
#include <stdio.h>
#include <string.h>
#include <assert.h>int my_strcmp(const char* s1, const char* s2)
{assert(s1 && s2);while (*s1 == *s2){if (*s1 == '\0'){return 0;}s1++;s2++;}return *s1 - *s2;
}int main()
{char arr1[] = "abc";char arr2[] = "abc";int ret = my_strcmp(arr1, arr2);if (ret < 0)printf("arr1<arr2\n");else if(ret>0)printf("arr1>arr2\n");elseprintf("arr1==arr2\n");printf("%d\n", ret);return 0;
}
五、小结
长度不受限制的字符串:
strcpy
strcat
strcmp
长度受限制的字符串:
strncpy
strncat
strncmp
六、strncpy
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "abcdefghi";char arr2[] = "xxxx";strncpy(arr1, arr2, 2);printf("%s\n", arr1);return 0;
}
假设:拷贝大于arr的空间
七、strncat
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "abcdef\0qqqqqq";char arr2[] = "xyz";strncat(arr1, arr2, 2);printf("%s\n", arr1);return 0;
}
八、 strncmp
#include <stdio.h>
#include <string.h>int main()
{int ret = strncmp("abcdef", "abc", 3);printf("%d\n", ret);return 0;
}
假设比较前四个就是d和\0比较:
九、strstr
strstr: 在一个字符串中找另一个字符串是否存在
存在:返回子串第一次出现的位置
不存在:返回NULL
int main()
{char arr1[] = "abcdefabcdef";char arr2[] = "cdq";char* p = strstr(arr1, arr2);if (p == NULL){printf("不存在\n");}else{printf("%s\n", p);}return 0;
}
9.1模拟实现strstr
char* my_strstr(const char* str1, const char* str2)
{const char* s1 = str1;const char* s2 = str2;const char* p = str1;if (*str2 == '\0'){return str1;}while (*p){s1 = p;s2 = str2;while (*s1 != '\0' && *s2 != '\0' && (*s1 == *s2)){s1++;s2++;}if (*s2 == '\0'){return (char*)p;//找到了}p++;}return NULL;//找不到子串
}int main()
{char arr1[] = "abcdefabcdef";char arr2[] = "cdq";char* p = strstr(arr1, arr2);if (p == NULL){printf("不存在\n");}else{printf("%s\n", p);}return 0;
}
十、strtok
sep参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
#include <stdio.h>
#include <stdio.h>int main()
{char arr[] = "zpengwei@bitedu.com";char buf[200] = { 0 };//"zpengwei@bitedu.com"strcpy(buf, arr);const char* p = "@.";char* str = strtok(buf, p);printf("%s\n", str);str = strtok(NULL, p);printf("%s\n", str);str = strtok(NULL, p);printf("%s\n", str);//"@."//strtok();//zpengwei//bitedu//comreturn 0;
}
优化:
#include <stdio.h>
#include <stdio.h>int main()
{char arr[] = "zpengwei@bitedu.com";char buf[200] = { 0 };//"zpengwei@bitedu.com"strcpy(buf, arr);const char* p = "@.";char* str = NULL;for (str=strtok(buf, p); str!=NULL; str=strtok(NULL, p)){printf("%s\n", str);}return 0;
}
十一、strerror
strerror:把错误码转换成错误信息
#include <stdio.h>
#include <stdio.h>int main()
{printf("%s\n", strerror(0));printf("%s\n", strerror(1));printf("%s\n", strerror(2));printf("%s\n", strerror(3));printf("%s\n", strerror(4));return 0;
}
//错误码记录到错误码的变量中//errno - C语言提供的全局的错误变量//#include <errno.h>FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("");//打印的依然是errno变量中错误码对应的错误信息//printf("%s\n", strerror(errno));return 1;}//读文件fclose(pf);pf = NULL;return 0;
}
十二、字符分类函数:
具体用法可以搜索:cplusplus
里边都有详细介绍
十三、memcpy
一组内存函数:
memcpy
memcmp
memmove
memset
1.memcpy:内存拷贝
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };memcpy(arr2, arr, 20);//float arr1[] = { 1.0f,2.0f,3.0f,4.0f };//float arr2[5] = { 0.0 };//memcpy(arr2, arr1, 8);return 0;
}
2.模拟实现memcpy
// memcpy模拟实现#include <assert.h>void* my_memcpy(void* dest, void* src, size_t num)//返回类型 viod*
{void* ret = dest;assert(dest);//断言,不能为NULLassert(src);while(num--)//一次搞定一个字节,一共num个字节{*(char*)dest = *(char*)src;//viod*的指针不能直接引用,强制类型转换成char*的指针dest = (char*)dest + 1;//同理,强制类型转换成char*的指针src = (char*)src + 1;//不能用 (char*)src++ :++在外边}return ret;//不能返回dest,已经不是起始位置,定义ret
}
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };memcpy(arr1+2, arr1, 20);memmove(arr1+2, arr1, 20);int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };my_memcpy(arr2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}float arr3[] = { 1.0f,2.0f,3.0f,4.0f };float arr4[5] = { 0.0 };my_memcpy(arr4, arr3, 8);return 0;
}
问题: 把1 2 3 4 5 放到 3 4 5 6 7上,如果使用memcpy时源空间会和目标空间有重合,拷贝的时候可能会把目标空间的一些数据覆盖掉
需要重新换思路
例如:
总结:
则需要memmove函数
十四、memmove
c语言中重叠内存的拷贝是交给:memmove
void* my_memmove(void* dest, void* src, size_t num)
{void* ret = dest;assert(dest);assert(src);if (dest < src)//1 前->后{while(num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else //2 3 后->前{while (num--){*((char*)dest + num) = *((char*)src + num);}}return ret;
}memcpy只需要实现不重叠的拷贝就可以了
memmove是需要实现重叠内存的拷贝的int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };memcpy(arr1+2, arr1, 20);return 0;
}
memcpy只需要实现不重叠的拷贝就可以了
memmove是需要实现重叠内存的拷贝的
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
int main()
{int arr1[] = { 1,2,3,0,5 };//01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00 ..int arr2[] = { 1,2,3,4,0 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ..int ret = memcmp(arr1, arr2, 13);printf("%d\n", ret);return 0;
}
十五、memset
memset:内存设置
测试:
int main()
{int arr[] = { 1,2,3,4,5 };memset(arr, 0, 8);return 0;
}