本篇介绍函数的声明,简单用法,模拟实现,(字符函数不模拟实现)
本篇模拟实现的代码均可用,测试用例请自行解决,或从本篇内链接找。
观前提示:(NULL是空指针,null是字符结尾标志' \0 '也叫NUL,)
/*个别不常用的/还未学习的暂且未模拟实现,后续会慢慢补齐,的喵~*/
目录
memcpy,memmove,strcpy,strncpy(copy类型)
memcmp,strcmp,strcoll,strncmp,strxfrm,(cmp类)
memchr,strchr,strcspn,strpbrk,strrchr,strspn,strstr,strtok(Search类)
memset, strerror,strlen(other):
字符函数:
字符函数的头文件: ctype.h (cplusplus.com网站链接)
字符分类函数:
int 函数名(int c);
字符转换函数 :
int tolower ( int c ); //将参数传进去的大写字母转小写
int toupper ( int c ); //将参数传进去的小写字母转大写
to lower; to upper ;(记忆方法)
字符串函数&&内存函数:
字符串函数的头文件: string.h(网站链接),
都在一个头文件了,一起搞吧,str开头的是字符串函数,mem开头是内存函数
我们就按照这个网站的分类来介绍,其实网站已经做的很详细了,我们主要是进行模拟实现,以便更好地了解它们;
memcpy,memmove,strcpy,strncpy(copy类型)
memcpy:
机翻。不过很合理,完全没毛病。
使用方法就那样,copy源内存块的值到目标的内存块,(官网已经给的很详细了,值得注意,重叠,不同编译器实现方法不一,复制的内存块和目标内存块重叠的情况请用memmove,ps听劝告,减少痛苦)
void * memcpy ( void * destination, const void * source, size_t num );
// 返回空指针, 目标 源内存,const修饰 复制的字节数
#define _CRT_SECURE_NO_WARNINGS 1
//模拟实现memcpy
#include<stdio.h>
void* my_memcpy(void* destination, const void* source, size_t num)
{
//这里有两种实现方式,一是从低地址到高地址,二是从高地址到低地址
//整体复制存到一块空的内存,不予考虑,当num过大时,占用内存过多。
//如果要支持重叠复制请看memmove函数
/*这里还可以使用assert断言来确保指针非空*/
void* dest = destination;
//assert(destination && source);
while (num--)
{
//这里采用从低地址开始复制
*(char*)destination = *(char*)source;
destination = (char*)destination + 1;
source = (char*)source + 1;
}
return dest;
}
int main()
{
int arr1[40] = { 0 };
int arr2[] = { 0,1,2,3,4,5,6,7,8,9 };
my_memcpy(arr1, arr2, 5 * sizeof(arr2[0]));
for (int i = 0; i < 10; i++) {
printf("%d ", arr1[i]);
}
printf("\n");
return 0;
}
memmove:
机翻,你值得拥有,基本没毛病,这个主要解决了memcpy的目标和源的重叠问题
void * memmove ( void * destination, const void * source, size_t num );
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void* my_memmove(void* destination, const void* source, size_t num)
{
void* dest = destination;
//assert(destination && source);
if (destination < source) {
while (num--)
{
//copy低到高
*(char*)destination = *(char*)source;
destination = (char*)destination + 1;
source = (char*)source + 1;
}
}
else {
int count = num;//这地方的这个可以省略,但我懒得再改了,如果你愿意,请尝试尝试
while (num--)
{
//高到低
*((char*)destination + count - 1 )= *((char*)source + count - 1);
destination = (char*)destination - 1;
source = (char*)source - 1;
}
}
return dest;
}
int main()
{
int arr1[40] = { 0 };
int arr2[] = { 0,1,2,3,4,5,6,7,8,9 };
my_memmove(&arr2[4], arr2, 5 * sizeof(arr2[0]));
for (int i = 0; i < 10; i++) {
printf("%d ", arr2[i]);
}
printf("\n");
return 0;
}
strcpy:
因为实现方式,所以不能重叠,重叠会修改自己(源)的null(' \0 ')导致死循环。
char * strcpy ( char * destination, const char * source );
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
for (int i = 0; *(dest+i) = *(src+i), *(src + i); i++) {
;//这里依然可以不用i这个整型变量,但懒得再写一份了,
}
return ret;
}
int main()
{
char arr1[40] = { 0 };
char arr2[] = "wa gai nai ,wo shi ben ben";
//strcpy(arr1, arr2);
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
strncpy:
char * strncpy ( char * destination, const char * source, size_t num );
#include<stdio.h>
char* my_strncpy(char* dest, const char* src, size_t num)
{
char* ret = dest;
while (num--)
{
*dest++ = *src++;
if (!*(src - 1)) {
while (num) {
num--;
*dest++ = '\0';
}
}
}
return ret;
}
int main()
{
char str1[5] = "abcde";
char str2[] = "ben";
my_strncpy(str1, str2, 5);
printf("%s", str1);
return 0;
}
strcat,strncat:
strcat:
可以看到strcat和strcpy十分的相似,都可以看作是copy,strcpy是直接copy,而strcat要先找到null。
char * strcat ( char * destination, const char * source );
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* str1, const char* str2)
{
assert(str1 && str2);
char* set = str1;
while (*str1) {
str1++;
}
while (*str1++ = *str2++)
{
;
}
return set;
}
int main()
{
char str1[1000] = "wo shi ge xiao bai cai";
char str2[] = " you cai you juan bu dong";
printf("%s", my_strcat(str1, str2));
return 0;
}
strncat:
char * strncat ( char * destination, const char * source, size_t num );
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
char* my_strncat(char* dest, const char* src, size_t num)
{
char* ret = dest;
while (*dest) {
dest++;
}
while (num-- && *src) {
*dest++ = *src++;
}
*dest = '\0';
return ret;
}
int main()
{
char str1[100] = "ccccffff\0ttttttttttttttt";
char str2[] = "aaa";
printf("%s \n", my_strncat(str1, str2, 5));
return 0;
}
strncpy和strncat :区别,
1.copy的复制字符串不额外加null(本身的null还是会加,属于能有就有看num是否包含了源的null),而cat额外加null('\0')(属于是看num加多少字符,加到\0前不加,没加到也停下来,最后一定会补个\0);
2.添加完源的num个字符后,还有字符未添加,copy是加' \0 ',cat是终止复制,
刚好三个但额外加\0以不打印tttt。说明strncat的额外添加\0,
两个,后补\0;
五个,说明strncat后的目标字符串(dest)必定有, \0,
下面是测验的小代码
#include<stdio.h>
#include<string.h>
int main()
{
char str1[100] = "ccccffff\0ttttttttttt";
char str2[] = "aaa";
printf("%s \n", strncat(str1, str2, 5));
return 0;
}
memcmp,strcmp,strcoll,strncmp,strxfrm,(cmp类)
这里有几个还未写完,以后找时间写,
memcmp:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
while (num--) {
if ((*(char*)ptr1 - *(char*)ptr2) > 0) {
return 1;
}
if ((*(char*)ptr1 - *(char*)ptr2) < 0) {
return -1;
}
ptr1 = (char*)ptr1 + 1;
ptr2 = (char*)ptr2 + 1;
}
return 0;
}
int main()
{
char str1[100] = "c\0ccffff\0ttttttttttttt";
char str2[] = "c\0d";
int tmp = my_memcmp(str1, str2, 3);
if (tmp > 0) {
printf("str1大\n");
}
else if (tmp < 0) {
printf("str2大\n");
}
else {
printf("一样大\n");
}
return 0;
}
strcmp:
int strcmp ( const char * str1, const char * str2 );
string compare ~, ~
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
//这是好久前写的代码。
int my_strcmp(const char* str1, const char* str2)
{
//想清楚我要干什么,
//遍历两个字符串,直到遇见'\0'
//然后每次判断即可
assert(str1 && str2);
int i = 0;
while ((*(str1 + i)) && (*(str2 + i))) {
if (*(str1 + i) != *(str2 + i)) {
break;
}
i++;
}
return *(str1 + i) - *(str2 + i);
//while (*str1 == *str2) { //这个更加简洁,还没用i
// if (*str1 == '\0') {
// return 0;
// }
// str1++;
// str2++;
//}
//return *str1 - *str2;
}
int main()
{
char arr1[] = "abcc";
char arr2[] = "abb";
int c = my_strcmp(arr1, arr2);
//int c = strcmp(arr1, arr2);
if (c > 0) {
printf("arr1大,\n");
}
else if (c == 0) {
printf("一样大\n");
}
else {
printf("arr2大\n");
}
return 0;
}
strcoll(未模拟实现):
(很遗憾,这个还没学,没有模拟实现)
int strcoll ( const char * str1, const char * str2 );
strncmp:
不用多说,只是小小的改动对于strcmp函数来说,
以先发生者的意思是,比较到null和num结束,这两种情况, 以先发生者为准。
int strncmp ( const char * str1, const char * str2, size_t num );
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int my_strncmp(const char* str1, const char* str2, size_t num)
{
while (num--)
{
if (*str1 != *str2) {
return *str1 - *str2;
}
if (*str1 == '\0') {
return 0;
}
str1++;
str2++;
}
return 0;
}
int main()
{
char arr1[] = "cbac\0ttttfffffffff";
char arr2[] = "cbac\0ttt";
int c = my_strncmp(arr1, arr2, 8);
if (c > 0) {
printf("arr1大,\n");
}
else if (c == 0) {
printf("一样大\n");
}
else {
printf("arr2大\n");
}
return 0;
}
strxfrm(未模拟实现):
size_t strxfrm ( char * destination, const char * source, size_t num );
memchr,strchr,strcspn,strpbrk,strrchr,strspn,strstr,strtok(Search类)
大部分作者目前还未过,啊就略过...目前仅有strstr,和strtok
strstr:
const char * strstr ( const char * str1, const char * str2 );
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
//返回指向 str1 中第一次出现的 str2 的指针,如果 str2 不是 str1 的一部分,则返回一个 null 指针。
char* my_strstr(const char* str1, const char* str2)
{
//遍历str1,找到和str2首元素一样的,
// 进行循环比较,直到str2结束,返回正确的下标,否,break,继续
// 直到str1结束,
assert(str1 && str2);
if (!*str2)
{
return (char*)str1;
}
while (*str1)
{
if (*str1 == *str2)
{
char* p1 = str1;
char* p2 = str2;
while (*p1 == *p2 )
{
if (*(p2+1) == '\0')
{
return (char*)str1;
}
p1++;
p2++;
}
}
str1++;
}
return NULL;
}
int main()
{
char str1[] = "ababcccc";
char str2[] = "cccc";
printf("%s",my_strstr(str1, str2));
return 0;
}
strtok(未模拟实现):
机翻,很欠揍,根本不能清楚理解,(英语好的,可以找官网自己看,)
strtok的函数解释大致为:
char * strtok ( char * str, const char * delimiters );
• delimiters参数指向⼀个字符串,定义了⽤作分隔符的字符集合
• 第⼀个参数指定⼀个字符串,它包含了0个或者多个由delimiters字符串中⼀个或者多个分隔符分割的标记。
• strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容 并且可修改。)
• strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串 中的位置。
• strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标 记。
• 如果字符串中不存在更多的标记,则返回 NULL 指针。
过于艰难,暂且搁置,使用方法都暂未掌握,
memset, strerror,strlen(other):
memset:
辣鸡翻译,是设置num个字节不是第一个字节
void * memset ( void * ptr, int value, size_t num );
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void my_memset(void* ptr, int value, size_t num)
{
while (num--) {
*(char*)ptr = (unsigned char)value;
ptr = (char*)ptr + 1;
}
}
int main()
{
char str1[] = "wo shi ben dan.";
my_memset(str1, 'f', 8);
printf("%s \n", str1);
return 0;
}
strerror(未模拟实现):
不好意思不会,偷懒,暂且不写。
strlen:
size_t strlen ( const char * str );
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
size_t My_strlen(const char* str) {
int count = 0;
while (*(str + count)) {
count++;
}
return count;
}
int main()
{
char str[1000] = { 0 };
gets(str);
int n = My_strlen(str);
printf("%d\n", n);
}
结束语:
这个<string.h>头文件,算是粗粗的啃了些,认识了部分的字符串函数和内存函数,
匆匆写完,如有错误,感谢在评论区指正,感谢谅解。
喜欢这篇文章的话,还请一键三连(doge)。