c语言分层理解(c语言字符串+内存库函数)
文章目录
- 1. 求字符串长度
- 1.1 strlen库函数
- 1.1.1 注意要点
- 1.1.2 strlen模拟实现
- 2. 长度不受限制的字符串函数
- 2.1 strcpy库函数
- 2.1.1 主要要点
- 2.1.2 strcpy模拟实现
- 2.2 strcat库函数
- 2.2.2 strcat模拟实现
- 2.3 strcmp库函数
- 2.3.1 注意要点
- 2.3.2 strcmp模拟实现
- 3. 长度受限制的字符串函数
- 3.1 strncpy库函数
- 3.1.1 注意要点
- 3.1.2 strncpy模拟实现
- 3.2 strncat库函数
- 3.2.1 注意要点
- 3.2.2 strncat模拟实现
- 3.3 strncmp库函数
- 3.3.1 注意要点
- 3.3.2 strncmp模拟实现
- 4. 字符串查找函数
- 4.1 strstr库函数
- 4.1.1 注意要点
- 4.1.2 strstr模拟实现
- 4.2 strtok库函数
- 4.2.1 注意要点
- 4.2.2 strtok库函数的使用场景
- 5. 错误信息报告
- 5.1 strerror库函数
- 6. 字符操作函数
- 7.内存操作函数
- 7.1 memcpy库函数
- 7.1.1 注意要点
- 7.1.2 模拟实现
- 7.2 memmove库函数
- 7.2.1 注意要点
- 7.2.2 模拟实现
- 7.3 memset库函数
- 7.3.1 注意要点
- 7.3.2 使用场景
- 7.4 memcmp库函数
- 7.4.1 注意要点
1. 求字符串长度
1.1 strlen库函数
size_t strlen ( const char * str );
1.1.1 注意要点
- 字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包
含 ‘\0’ )- 参数指向的字符串必须要以 ‘\0’ 结束。
- 注意函数的返回值为size_t,是无符号的
1.1.2 strlen模拟实现
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
assert(str);
const char* start = str;
const char* end = str;
while (*end != '\0')
{
end++;
}
return end - start;
}
int main()
{
char arr[] = "abcdef";
int ret = my_strlen(arr);
printf("%d\n", ret);
return 0;
}
2. 长度不受限制的字符串函数
2.1 strcpy库函数
char* strcpy(char * destination, const char * source );
2.1.1 主要要点
- 源头字符串必须以’\0’结束
- 会把源头字符串中的’\0’拷贝到目标空间中
- 目标空间必须足够大,以确保存放源字符串
- 目标空间必须可变
2.1.2 strcpy模拟实现
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* destenation, const char* source)
{
assert(destenation && source);
char* ret = destenation;
while (*destenation++ = *source++)
{
;
}
return ret;
}
int main()
{
char arr1[] = "xxxxxxxxxxx";
char arr2[] = "hello";
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
2.2 strcat库函数
##3 2.2.1 注意要点
- 源头字符串必须以’\0’结束
- 目标空间必须足够大,能容纳源头字符串的内容
- 目标空间必须可修改
- strcat库函数自己给自己追加造成死循环
2.2.2 strcat模拟实现
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* destenation, const char* source)
{
char* record = destenation;
while (*record != '\0')
{
record++;
}
while (*record++ = *source++)
{
;
}
return destenation;
}
int main()
{
char arr1[20] = "math ";
char arr2[] = "easy";
printf("%s\n",my_strcat(arr1, arr2));
return 0;
}
2.3 strcmp库函数
int strcmp ( const char * str1, const char * str2 );
2.3.1 注意要点
- 第一个字符串大于第二个字符串返回大于0的数字;第一个字符串等于第二个字符串返回0;第一个字符串小于第二个字符串返回小于0的数字
- 从左到右一个一个字符依次比较,比较的是字符的ASCII值
2.3.2 strcmp模拟实现
#include <stdio.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[] = "abcdef";
char arr2[] = "abd";
int ret = my_strcmp(arr1, arr2);
if (ret > 0)
{
printf("arr1>arr2");
}
else if (ret < 0)
{
printf("arr1<arr2");
}
else
{
printf("arr1=arr2");
}
return 0;
}
3. 长度受限制的字符串函数
3.1 strncpy库函数
char * strncpy ( char * destination, const char * source, size_t num );
3.1.1 注意要点
- 拷贝num个字符从源头字符串到目标空间
- 如果源头字符串的长度小于num,则拷贝完源头字符串之后,在目标的后边追加’\0’,知道num个
3.1.2 strncpy模拟实现
#include <stdio.h>
char* my_strncpy(char* dest,const char* source,size_t count)
{
char* start = dest;
while (count && (*dest++ = *source++) != '\0')
{
count--;
}
if (count)
{
while (--count)
{
*dest++ = '\0';
}
}
return start;
}
int main()
{
char arr1[] = "xxxxxxxxxxx";
char arr2[] = "hello";
printf("%s\n", my_strncpy(arr1, arr2,3));
return 0;
}
3.2 strncat库函数
char * strncat ( char * destination, const char * source, size_t num );
3.2.1 注意要点
- 可以实现自己给自己追加的情况,通常追加后后面加上一个’\0’来结束
- 目标空间必须足够大
- 目标空间必须可修改
3.2.2 strncat模拟实现
#include <stdio.h>
char* my_strncat(char* front,const char* back,size_t count)
{
char* start = front;
while (*front++)
{
;
}
front--;
while (count--)
{
if ((*front++ = *back++) == 0)
{
return start;
}
}
*front = '\0';
return start;
}
int main()
{
char arr1[20] = "math ";
char arr2[] = "easy";
printf("%s\n",my_strncat(arr1, arr2,3));
return 0;
}
3.3 strncmp库函数
int strncmp ( const char * str1, const char * str2, size_t num );
3.3.1 注意要点
和strcmp需要注意的地方一样
3.3.2 strncmp模拟实现
#include <stdio.h>
#include <assert.h>
int my_strncmp(const char* str1, const char* str2, size_t num)
{
assert(str1 && str2);
if (!num)return 0;
while (--num && *str1 && (*str1 == *str2))
{
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char arr1[] = "adegcongdwg";
char arr2[] = "adegavd";
int ret = my_strncmp(arr1, arr2,5);
if (ret > 0)
{
printf("arr1>arr2");
}
else if (ret < 0)
{
printf("arr1<arr2");
}
else
{
printf("arr1=arr2");
}
return 0;
}
4. 字符串查找函数
4.1 strstr库函数
char * strstr ( const char *str1, const char * str2);
4.1.1 注意要点
在一个字符串中另外一个字符川是否存在。如果存在,则返回子串第一次出现的位置;如果不存在,则返回NULL
4.1.2 strstr模拟实现
#include <stdio.h>
char* my_strstr(const char* s1, const char* s2)
{
const char* str1 = s1;
const char* str2 = s2;
const char* p = s1;
while (*p)
{
str1 = p;
str2 = s2;
while (*str1 == *str2)
{
str1++;
str2++;
}
if (*str2 == '\0')
{
return (char*)p;
}
p++;
}
return NULL;
}
int main()
{
char arr1[] = "adefghadefgh";
char arr2[] = "efg";
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
4.2 strtok库函数
char * strtok ( char * str, const char * delimiters );
4.2.1 注意要点
1.delimiters参数上一个字符串,定义用作分隔符的字符集合
2.第一个参数指定一个字符串,它包含了0个或者多个由delimiters字符串中一个或者多个分隔符分割的标记。
3.strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
4.strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
6.如果字符串中不存在更多的标记,则返回 NULL 指针。
4.2.2 strtok库函数的使用场景
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "code-eye@qq.com";
char buff[200] = { 0 };
//strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改
strcpy(buff, arr);
const char* p = "-@.";
char* str = NULL;
for (str = strtok(buff, p); str != NULL; str = strtok(NULL, p))
{
printf("%s\n",str);
}
return 0;
}
5. 错误信息报告
5.1 strerror库函数
char* strerror(int errnum);
strerror库函数作用:返回错误码,所对应的错误信息。
6. 字符操作函数
- iscntrl库函数:判断是否为任何控制字符
- isspace库函数:判断是否为空白字符:‘空格’,换页‘\f’,换行‘\n’,回车‘\r’,制表符‘\t’
- isdigit库函数;判断是否为十进制数字
- isxdigit库函数:判断是否为十六进制数字包括十进制数字
- islower库函数:判断是否为小写字母
- isupper库函数:判断是否为大写字母
- isalpha库函数:判断是否为字母az或者AZ
- isalnum库函数:判断是否为字母或者数字
- ispunct库函数:判断是否为标点符号,任何不属于数字或者字母的图形字符
- isgraph库函数;判断是否为任何图形字符
- isprint库函数:判断是否为任何可打印字符
7.内存操作函数
7.1 memcpy库函数
void * memcpy ( void * destination, const void * source, size_t num );
7.1.1 注意要点
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置
- 这个函数在遇到 ‘\0’ 的时候并不会停下来。
- 如果source和destination有任何的重叠,复制的结果都是未定义的
7.1.2 模拟实现
#include <stdio.h>
#inlcude <assert.h>
void* my_memcpy(void* dest, void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
while(num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[10] = { 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 < (20 / sizeof(int)); i++)
{
printf("%d ",arr2[i]);
}
return 0;
}
7.2 memmove库函数
void * memmove ( void * destination, const void * source, size_t num );
7.2.1 注意要点
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理
7.2.2 模拟实现
#include <stdio.h>
void* my_memmove(void* dest, 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--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
print(int arr[],int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr+3,arr,16);
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr,sz);
return 0;
}
7.3 memset库函数
void * memset ( void * ptr, int value, size_t num );
7.3.1 注意要点
- memset是用来把ptr指针指向的内容后的num个字节全部改为value值
7.3.2 使用场景
7.4 memcmp库函数
int memcmp ( const void * ptr1,const void * ptr2,size_t num );
7.4.1 注意要点
这里和strncpy很相似,但是memcpy针对各种类型,strncpy只能比较char类型的。
这里的num单位是字节,所以比较的是从ptr1和ptr2指针开始的num个字节
ptr1的字符ASCII码值大于ptr2就返回大于0的值,等于返回0,小于则返回小于0的值