C语言中的部分字符函数,内存函数,和部分字符串函数的模拟实现
C语言中对字符串的处理是很频繁的,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量适用于哪些对它不做修改的字符串函数、
1.求字符串长度
strlen
strlen
size_t strlen (const char *str);
- 1.字符串已经’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现 的字符个数(不包含’\0’)。
- 2.参数指向的字符的字符串必须要以’\0’结束。
- 3.注意函数的返回值为sizeof_t,是无符号的!!!!!!!
模拟实现strlen
#include<stdio.h>
//方法1.计数器方式
int my_strlen(const char * str)
{
int count = 0;
while(*str)
{
count++;
str++;
}
return count;
}
//方法2.不能创建临时的变量计数器(递归)
int my_strlen(const char* str)
{
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str + 1);
}
//方法3.指针的方式
int my_strlen(char* s)
{
char* p = s;
while (*p != '\0')
p++;
return p - s;
}
2.长度不受限制的字符串函数
strcpy
char* strcpy(char* destination,const char* source);
strcpy
Copies the C string pointed by source into the array pointed by destination,including the terminating null character(and stopping at the point)
- 1.源字符串必须以’\0’结束。
- 2.会将源字符串中的’\0’拷贝到目标空间。
- 3.目标空间必须足够大,以确保能存放源字符串。
- 4.目标空间必须可变。
模拟实现strcpy
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* str1,const char* str2)//str2不会改变所以拿const修饰
{
assert(str1 != NULL);
assert(str2 != NULL);//断言 指针是否为空
char* ret = str1;
while (*str1++ = *str2++)//当找到'\0'时 停止循环拷贝
{
;
}
return ret;
}
int main()
{
char arr1[10] = "asdfghjkl";
char arr2[10] = "bit";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
strcat
char* strcat(char* destination,const char* source);
-
Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source,and a null -character is include at the end of the new string formed by concatenation of both in destination.
-
1.源字符串必须以’\0’结束。
-
2.目标空间必须足够大,能容纳下源字符串的内容。
-
3.目标空间必须可修改
模拟实现 strcat
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest,const char* src)//const修饰src防止其发生变化
{
char* ret = dest;
assert(dest != NULL);//断言防止指针为空
assert(src != NULL);
//1.找到'\0'
while (*dest != '\0')
{
dest++;
}
//2.拷贝
while (*dest++ = *src++)//*dest++=*src++//*dest=*src dest++,src++
{
;
}
return ret;
}
int main()
{
char arr1[30] = "hello";
char arr2[] = "world";
my_strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
strcmp
int strcmp(const char* str,const char* str2);
- This function starts comparing the fist character of each string. If they are equal to each other,it continues with the following pairs until the characters differ or until a terminating null-character is reached.
- 1.第一个字符串大于第二个字符串,则返回大于0的数字。
- 2.第一个字符串等于第二个字符串,则返回0.
- 3.第一个字符串小于第二个字符串,则返回小于0的数字
模拟实现strcmp
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1,const char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
while (*str1 == *str2)
{
if (*str1 != '\0')//相等
{
return 0;
}
str1++;
str2++;
}
if (*str1 > *str2)//大于
{
return 1;
}
if (*str1 < *str2)//小于
{
return -1;
}
}
int main()
{
char* p1 = "abcde";
char* p2 = "cdefg";
int ret = my_strcmp(p1,p2);
printf("%d", ret);
return 0;
}
3.长度受限制的字符串函数介绍
strncpy
char* strncpy(char* destinal,const char* source,siz_t num);
- Copies the first num characters of source to destination,If the end of the source C string(which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
- 1.拷贝num个字符串从源字符串到目标空间。
- 2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标后面追加0,直到num个。
与strcpy的区别为传参时多一个控制长度的参数
strncat
char* strncat(char* destination, const char* source,size_t num);
- 1.Appends the first num characters of source to destination, plus a terminating null-character.
- 2.If the length of the C string in source is less than num, only the content up to the terminating null- character is copied.
strncat的用法
/* strncat example */
#include <stdio.h>
#include <string.h>
int main () {
char str1[20];
char str2[20];
strcpy (str1,"To be ");
strcpy (str2,"or not to be");
strncat (str1, str2, 6);
puts (str1);
return 0;
}
strncmp
int strncmp (const char* str1,const char* str2,size_t num);
- 1.比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
strncmp的使用
/* strncmp example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
int n;
puts ("Looking for R2 astromech droids...");
for (n=0 ; n<3 ; n++)
if (strncmp (str[n],"R2xx",2) == 0)
{
printf ("found %s\n",str[n]);
}
return 0;
}
4.字符串查找
strstr
char* strstr(const char*,const char*)
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
- 1.查找一个字符串是否是另一个字符串的子串。
- 2.被查找的字符串长度要大于查找的字符串长度。
模拟实现strstr
#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* p1,const char* p2)
{
assert(p1 != NULL);
assert(p2 != NULL);
char* s1 = NULL;
char* s2 = NULL;
char* cur = p1;
if (*p2 == '\0')
{
return (char*)p1;//将p1强制类型转换为char*类型 防止报警告
}
while (*cur)//防止例如arr1="abbbc" arr2="bbc" 这种情况出现 不能只查找一次 需要查找多次 每次查找 s1向后移动一位
{
s1 = cur;
s2 = p2;
while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cur;//找到子串
}
if(*s1=='\0')//判断arr1是否与arr2长
{
return NULL;
}
cur++;//确定下一次s1的位置
}
return NULL;//找不到子串返回空指针
}
int main()
{
char arr1[30] = "abcdef";
char arr2[] = "def";
char* out = my_strstr(arr1,arr2);
printf("%s", out);
return 0;
}
strtok
char*strtok(char t str, const char t sep);
- 1.sep参数是个字符串, 定义了用作分隔符的字符集合。
- 2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
- 3.strtok函数找到str中的下一 个标记, 并将其用\0结尾, 返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串, 所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
- 4.strtok函数的第一 个参数不为NULL, 函数将找到str中第一个标记, strtok函数将保存它在字符串中的位置。
- 5.strtok函数的第一 个参数为NULL, 函数将在同一个字符串中被保存的位置开始, 查找下一个标记。
- 6.如果字符串中不存在更多的标记, 则返回NULL指针。
strtok的使用
#include<stdio.h>
int main()
{
char arr[] = "123456@234.com";
char* p = "@.";
char buf[1024] = { 0 };
strcpy(buf, arr);//strtok是会破坏字符串的 所以拷贝一份arr到buf切割时切割buf
char* ret = NULL;
for (ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p))
//第一次传参为要切割的字符串地址和分割符,它会在需要分割的地方放置'\0'并且记
//录位置以便下一次分割。再次调用传NULL和分隔符它将找到上一次分割的位置继续向
//后分割当遇到'\0'时返回NULL
{
printf("%s\n", ret);
}
return 0;
}
5.错误信息报告
strerror
char* strerror(int errnum);
返回错误码,所对应的错误信息
使用方法
int main()
{
//错误码 错误信息
// 0 - No error
// 1 - Operation not permitted
// 2 - No such file or directory
// ...
//errno 是一个全局的错误码的变量
//当C语言的库函数在执行过程中,发生了错误,就会把对应的错误码
//赋值到errno中
char* str = strerror(errno);
printf("%s", str);
return 0;
}
6.字符串操作
函数 如果他的参数符合下列条件就返回真
iscntrl 控制任何字符
isspace 空白字符:空格' ',换页'\f',换行'\n',回车'\r',制表符'\t'或者垂直制表符'\v'
isdigit 十进制数字 0~9
isxdigit 十六进制数字,包括所以十进制数字,小写字母a~f,大写字母A~F
islower 小写字母a~z
issupper 字母A~Z
isalpha 字母a~z或A~Z
isalnum 字母或者数字,a~z,A~Z,0~9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符
7.字符转换
常用的有:
int tolower(int c);//字母转换为小写
int toupper(int c);//字母转换为大写
8.内存函数
由于上述函数传参为char*类型所以只能在字符串中使用,若想处理其它类型 的数据则需要内存函数。内存函数传参类型为void*类型,所以它可以处理任何类型的数据。
memcpy
memcpy
void* memcpy(void* destination, const void* soure, size_t num);
- 1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
- 2.这个函数在遇到’\0’的时候并不会停下来。
- 3.如果source和destination有任何的重叠,复制的结果都是未定义的。
模拟实现memcpy
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest != NULL);//防止指针为空指针
assert(src != NULL);
while (num--)
{
*(char*)dest = *(char*)src;//由于为void*类型无法进行指针运算需要先强制类型转换
++(char*)dest;
++(char*)src;
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[10] = { 0 };
my_memcpy(arr2,arr1,sizeof(arr1));//(拷贝到arr2,从arr1中拷贝,拷贝大小(字节))
return 0;
}
但是这个函数不能处理字符串重叠的情况例如
int arr[10] = {1,2,3,4,5,6,7,8,9};
memcpy(arr+2,arr,20);
memmove可以解决。
memmove
void* memmove (void* dest, const void* src, size_t count);
- 1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 2.如果源空间和目标空间出现重叠,就得使用memmove函数处理。
模拟实现memmove
#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, void* src, size_t count)
{
void* ret = dest;
assert(dest != NULL);
assert(src != NULL);
if (dest < src)
{
//从前向后拷贝
while (count--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
}
else
{
//从后向前拷贝
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr + 2, arr, 20);
return 0;
}
memcmp
int memcmp(const void* ptr1, const void* ptr2, size_t num);
内存对比
memcmp的使用
int main()
{
//01 00 00 00 02 00 00 00 03 00 00 ...
//01 00 00 00 02 00 00 00 05 00 00 ...
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,5,4,3 };
int ret = memcmp(arr1, arr2, 9);//对比的大小单位是字符
printf("%d\n", ret);
return 0;
}
memset
内存设置
memset用法
int main()
{
char arr[10] = "";
memset(arr,'#',10);
//int arr[10] = { 0 };
//memset(arr, 1, 10);
// err 因为设置的内存大小是字符串
//小端储存中 00 00 00 00 00 00 00 00 00 ...
// 被设置为 01 01 01 01 01 01 01 01 01 ...
}
第一篇博客 若有错误希望指出