目录
前言
本篇文章介绍字符函数与字符串函数,以及模拟实现其中的功能。
C语言当中本身是没有字符串类型的,字符串通常放在常量字符串或者字符数组中,字符串常量适用于对其不做修改的字符串函数。
一、函数介绍与模拟实现
1.1 strlen
size_t strlen ( const char * str );
参数指向的字符串以 '\0' 结束,strlen函数返回字符串中 '\0' 前的字符个数,其返回值类型是无符号的size_t
以下是对strlen函数的模拟实现
size_t my_strlen(const char* str)
{
size_t count = 0;
while (*str++ != '\0')
{
count++;
}
return count;
}
int main()
{
char arr[] = "hello strlen";
size_t sz= my_strlen(arr);
printf("%d", sz);
return 0;
}
1.2 strcpy
char* strcpy ( char * destination , const char * source );//目标字符串可变,源字符串不可变
源字符串source必须以 '\0' 结束,会将源字符串中的 '\0' 拷贝到目标空间,目标空间必须足够大来存放源字符串
通过arr2数组数据监视,strcpy函数将 '\0' 拷贝到目标字符串中。
以下是对strcpy的模拟实现
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
while (*dest++ = *src++)
{
}
return ret;
}
int main()
{
char arr1[] = "hello world";
char arr2[20] = "xxxxxxxxxxxxxxxxxxxx";
my_strcpy(arr2, arr1);
printf(arr2);
}
对arr2空间监视发现模拟实现了strcpy的功能
1.3 strcat
char * strcat ( char * destination , const char * source );
以下是模拟实现strcat函数
char* my_strcat(char* dest, char* src)
{
char* ret = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
}
return ret;
}
int main()
{
char arr1[] = "hello world";
char arr2[20] = "xxxxx";
my_strcat(arr2, arr1);
printf(arr2);
}
对arr2监视,发现成功实现追加
1.4 strcmp
int strcmp ( const char * str1 , const char * str2 );
下面是对strcmp的模拟实现
int my_strcmp(const char* str1, const char* str2)
{
int ret = 0;
while (!(ret = (*(unsigned char*)str1 - *(unsigned char*)str2)) && *str1)
{
str1++;
str2++;
}
if (ret < 0)
{
return -1;
}
else if (ret > 0)
{
return 1;
}
return 0;
}
int main()
{
char arr1[] = "hello world";
char arr2[] = "hello world";
int ret=my_strcmp(arr1, arr2);
printf("%d", ret);
return 0;
}
1.5 strncpy
char * strncpy ( char * destination , const char * source , size_t num );
char* my_strncpy(char* dest, char* sour, size_t num)
{
char ret = dest;
while (num)
{
if (*dest++ = *sour++)
{
num--;
}
else
{
*dest ++= '\0';
num--;
}
}
return ret;
}
int main()
{
char arr1[] = "helloggh";
char arr2[] = "world";
my_strncpy(arr1, arr2, 7);
return 0;
}
以下是对arr1的监控
1.6 strncat
char * strncat ( char * destination , const char * source , size_t num );
char* my_strncat(char* dest, char* src, size_t num)
{
char* ret = dest;
while (*dest)
{
dest++;
}
while (num--)
{
if (*dest = *src)
{
dest++;
src++;
}
else
{
break;
}
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
my_strncat(arr1, arr2,5);
printf(arr1);
return 0;
}
1.7 strncmp
int strncmp ( const char * str1 , const char * str2 , size_t num );
while (!(ret = (*(unsigned char*)str1 - *(unsigned char*)str2)) && *str1&&num)
{
str1++;
str2++;
num--;
}
1.8 strstr
char * strstr ( const char * str1 , const char * str2 );
返回一个指向str1中第一次出现的str2的指针,或者如果str2不是str1的一部分,则返回一个空指针。
1.9 strtok
char * strtok ( char * str , const char * sep );
sep 参数是个字符串,定义了用作分隔符的字符集合 。第一个参数指定一个字符串,它包含了 0 个或者多个由 sep 字符串中一个或者多个分隔符分割的标记。strtok 函数找到 str 中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok 函数会改变被操作的字符串,所以在使用 strtok 函数切分的字符串一般都是临时拷贝的内容并且可修改。)strtok 函数的第一个参数不为 NULL ,函数将找到 str 中第一个标记, strtok 函数将保存它在字符串中的位置。strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。如果字符串中不存在更多的标记,则返回 NULL 指针。
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "- This, a sample string.";
char* pch;
printf("拆分字符串 \"%s\":\n", str);
pch = strtok(str, " ,.-");
while (pch != NULL)
{
printf("%s\n", pch);
pch = strtok(NULL, " ,.-");
}
return 0;
}
运行结果为
1.10 strerror
char * strerror ( int errnum );
返回错误码,所对应的错误信息。
#include <errno.h> //必须包含的头文件
printf ( "Error opening file unexist.ent: %s\n" , strerror ( errno ));//errno: Last error number
二、 内存操作函数的介绍与模拟实现
2.1 memcpy
void * memcpy ( void * destination , const void * source , size_t num );=
#include<stdio.h>
void* my_memcpy(void* dest, void* src, size_t num)
{
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr, 32);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
通过对arr2内存的监控发现对应字节的数据以及被替换
2.2 memmove
void * memmove ( void * destination , const void * source , size_t num );
以下是对memmove的模拟实现
void* my_memmove(void* dest, void* src, size_t num)
{
void* ret = dest;
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;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr, arr + 2, 16);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
将从arr+2开始的16个字节的数据,也就是4个整形数据:3,4,5,6复制到从arr开始的位置
预计结果为 3,4,5,6,5,6,7,8,9,10
通过对arr地址内存监控得到成功复制了数据
2.3 memcmp
int memcmp ( const void * ptr1 , const void * ptr2 , size_t num );
比较从ptr1和ptr2指针开始的num个字节
返回值小于0表示两个内存块中不匹配得第一个字节ptr1的值比ptr2的值低
返回值等于0表示两个内存块内容相等
返回值大于0表示两个内存块中不匹配得第一个字节ptr1的值大于ptr2的值
2.4 memset
void * memset ( void *str, int c, size_t num );
复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。
用以下代码测试功能
int main()
{
int arr[10] = { 0 };
memset(arr, 1, 12);
return 0;
}
通过对arr内存监控得
替换了12个字节,也就是3个整形。