strlen函数
strlen是用来统计字符串\0之前的字符的个数
size_t strlen ( const char * str );
由此可见strlen的返回类型是size_t 参数类型是const char*
#include<string.h>
int main()
{
char* p1 = "abcdef";
//传递的是char* 类型变量
printf("%d\n", strlen(p1));
//传递的是首字符'a'的地址
printf("%d\n", strlen("abcdef"));
return 0;
}

//这里要注意strlen函数的返回类型是size_t,是无符号整型
#include<string.h>
int main()
{
size_t len1 = strlen("abc");
size_t len2 = strlen("abcdef");
//这里要注意len1-len2=-3
// 但是数字在内存中以二进制补码形式存储
// 原码 10000000 00000000 00000000 00000011
// 反码 11111111 11111111 11111111 11111100
// 补码 11111111 11111111 11111111 11111101-----这个就是-3在内存中实际的存储情况
// 但是当要计算这两个数字相减时,因为是size_t类型,是无符号整型,
// 在取出时就会把1看作是数据位而不是符号位,那么就是正数,原码反码补码相同
// 那么取出的数据就是 4,294,967,293,远远大于0
//
//
if (len1 - len2 > 0)
{
printf("hehe\n");
printf("%zu\n", len1 - len2);
}
else
{
printf("haha\n");
}
return 0;
}

模拟实现strlen函数
方法一
//计数器加法
#include<assert.h>
size_t my_strlen(const char* p)
{
assert(p);
size_t rst = 0;
while (*p)
{
p++;
rst++;
}
return rst;
}
int main()
{
char* p = "abcdef";
size_t rst = my_strlen(p);
printf("%zu\n", rst);
return 0;
}
方法二
//函数递归的方法
size_t my_strlen(const char* p)
{
assert(p);
if (*p == '\0')
{
return 0;
}
else
return 1 + my_strlen(p + 1);
}
int main()
{
char* p = "abcdef";
size_t rst = my_strlen(p);//长度是6
printf("%zu\n", rst);
return 0;
}
方法三
//指针相减的方法
size_t my_strlen(const char* p)
{
assert(p);
char* p1 = p;
while (*p1)
{
p1++;
}
return p1 - p;
}
int main()
{
char* p = "abcdef";
size_t rst = my_strlen(p);
printf("%zu\n", rst);
return 0;
}
strcpy函数
strcpy函数是用来实现字符串的拷贝的
char* strcpy(char * p1, const char * p2);
strcpy函数的返回类型是char* ,返回的是待拷贝字符串的起始地址
参数类型也是char*,和 const char*,以保证模版不会被修改
p1是等待拷贝的字符串地址,p2是字符串模版
在拷贝时,一直拷贝到遇到字符串模版的\0,并且\0也要拷贝,\0拷贝下来后拷贝结束,所以字符串模版必须要有\0
#include<string.h>
int main()
{
char arr1[15] = { "xxxxxxxxxx" };
char arr2[] = { "hello\0haha" };
//strcpy函数在拷贝时已知拷贝到模版的\0拷贝才停止,\0也要拷贝
//\0拷贝下来后就不再拷贝
strcpy(arr1, arr2);
return 0;
}

注意
1.目标空间必须足够大,以确保能存放源字符串。
2.目标空间必须可变。
3.字符串模版必须要有\0,只有把模版的\0 拷贝下来,拷贝才停止
1.目标空间必须足够大,以确保能存放源字符串。
2.目标空间必须可变。
模拟实现strcpy函数
#include<assert.h>
char* my_strcpy(char* str1, const char* str2)
{
assert(str1 && str2);
char* p = str1;
//先赋值再++,当str2为\0时赋值给str1然后()里面的内容就是0,停止循环
while (*str1++ = *str2++)
{
;
}
return p;
}
int main()
{
char arr1[15] = { "xxxxxxxxxx" };
char arr2[] = { "hello\0haha" };
//strcpy函数在拷贝时已知拷贝到模版的\0拷贝才停止,\0也要拷贝
//\0拷贝下来后就不再拷贝
char* p = my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}

strcat函数
strcat函数是用来实现字符串的追加的
char * strcat ( char * p1, const char * p2 );
函数的返回类型是char,参数类型char 和const char*
在p1指向 的字符串末尾追加字符串,可以修改
p2指向的是被追加的字符串,所以不可修改
追加方式是在p1指向字符串的\0处追加p2指向的字符串,p1处的\0被p2指向字符串的第一个字符替代
p2指向的字符串被完整的追加到p1后面,包括\0
#include<string.h>
int main()
{
char arr1[20] = { "hello \0xxxxxxxxx" };
char arr2[] = { "world" };
//在arr1的第一个\0处追加字符串"world\0",arr1的第一个\0 被字符'w'替换
strcat(arr1, arr2);
return 0;
}

注意
1.目标空间必须可修改
2.目标空间必须足够大
3.目标空间必须有\0(以保证能找到目标空间的末尾)
4.原字符串必须也有\0,拷贝时拷贝到\0结束
模拟实现strcat函数
#include<assert.h>
char* my_strcat(char* str1, const char* str2)
{
assert(str1 && str2);
char* p = str1;
//首先找到目标空间的末尾,第一个\0处
while (*str1)
{
str1++;
}
//从末尾开始替换,直到模版字符串的结束
while (*str1++ = *str2++)
//*str1 \0 x x x x x
//*str2 w o r l d \0
//先把'w'赋给\0 然后str1和str2再++,把o替换x r替换x
//
{
;
}
return p;
}
int main()
{
char arr1[20] = { "hello \0xxxxxxxxx" };
char arr2[] = { "world" };
//在arr1的第一个\0处追加字符串"world\0",arr1的第一个\0 被字符'w'替换
char* p = my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}

strcmp函数
strcmp函数是用来比较字符串的
比较的不是字符串的长度而是字符串对应位置上的字符的大小

int strcmp ( const char * str1, const char * str2 );
函数的返回类型是int。 参数类型都是const char*
如果str1>str2 就返回一个大于0的数字
如果str1==str2 就但会一个0
如果str1<str2就返回一个小于0的数字

模拟实现strcmp
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
//如果两个指针对应的字符相等
while (*str1 == *str2)
{
//\0就说明两个字符串都已经结束了,且在结束前对应位置的字符相同
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
//说明两个字符串不相等
return *str1 - *str2;
}
int main()
{
char arr1[] = { "abcdef" };
char arr2[] = { "abq" };
int rst = my_strcmp(arr1, arr2);
printf("%d\n", rst);
return 0;
}
strncpy函数
char * strncpy ( char * destination, const char * source, size_t num );
char* strcpy(char * destination, const char * source );
strncpy和strcpy相比多了一个size_t num
这里的num是要拷贝的字符的个数

strncat函数
char * strcat ( char * destination, const char * source );
char * strncat ( char * destination, const char * source, size_t num );
strncat比strcat多了个函数参数size_t num
这里的num是表示要追加的字符个数

strncmp函数
int strncmp ( const char * str1, const char * str2, size_t num );
这里的num是指需要比较的字符个数

strstr函数
strstr函数
函数的功能是在字符串中找出是否有另一个字符串
const char * strstr ( const char *str1, const char * str2);
函数的返回类型是const char*
参数类型是const char*
注意str1是模版
在str1中如果能找到str2,就返回str1中str2第一次出现的位置
如果在str1中不能找到str2,就返回NULL
#include<string.h>
int main()
{
char arr1[] = { "abcdefbcd" };
char arr2[] = { "bcd" };
char arr3[] = { "xxxx" };
//这里可以找到字符串bcd,返回的是第一次找到bcd的位置
char* p1 = strstr(arr1, arr2);
//这里找不到字符串xxxx,返回NULL
char* p2 = strstr(arr1, arr3);
printf("%s\n", p1);
printf("%s\n", p2);
return 0;
}

模拟实现strstr函数
#include<assert.h>
const char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
//s1和s2是作为标志,来遍历两个字符串
const char* s1;
const char* s2;
//p1是记录在arr1中第一次找到与arr2中字符串相同的位置
const char* p1;
// 如果要在模版中找空字符串,就直接返回模版字符串的首地址
if (*str2 == '\0')
{
return str1;
}
p1 = str1;
// 如果标志p1遍历到\0也就是把模版字符串遍历完停下
while (*p1)
{
//让遍历的指针从标志开始
s1 = p1;
s2 = str2;
//当s1和s2指向的字符相同且都不为\0 进入循环
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
//s1++,s2++比较下一个字符是否相同
}
//当跳出while循环,并且s2为\0,说明就s2被遍历了一遍,
//此时就在模版中找到了字符串,就返回p1记录的位置
if (*s2 == '\0')
{
return p1;
}
p1++;
}
//如果在前面没有返回就说明在模版字符串中没有找到,返回NULL
return NULL;
}
int main()
{
char arr1[] = { "abbbcdef" };
char arr2[] = { "bbc" };
char arr3[] = { "xxxx" };
//这里可以找到字符串bcd,返回的是第一次找到bcd的位置
const char* p1 = my_strstr(arr1, arr2);
//这里找不到字符串xxxx,返回NULL
const char* p2 = my_strstr(arr1, arr3);
printf("%s\n", p1);
printf("%s\n", p2);
return 0;
}
strtok
char * strtok ( char * str, const char * sep );
函数的返回类型是char*
用来切割字符串的
sep参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串
中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
记。
如果字符串中不存在更多的标记,则返回 NULL 指针
#include<string.h>
int main()
{
char arr1[] = { "hello*world#haha" };
char arr2[20] = { 0 };
//在进行strtok分隔函数时,会对字符串修改,所以调用strcpy函数拷贝副本
strcpy(arr2, arr1);
char* p = "#*";//这里把'#'和'*'都当作字符串的分隔符
//第一次,传递非空指针时从起始位置向后找
char* s1 = strtok(arr2, p);
//在调用strtok函数时,arr2数组的字符串遇到#或者*时,就会把#或者*替换成\0,并保存#或者*的位置
// 如在第一次遇到*时会把*替换成\0并保存\0所在的位置
// 最后返回的是h的地址
printf("%s\n", s1);
//当第二次,传递空指针时,就从上一次保存的位置开始找,也就是\0的位置
char* s2 = strtok(NULL, p);
//这一次把#替换成\0 并保存\0所在位置
// 返回w的地址
printf("%s\n", s2);
//第三次,传递空指针就从上一次保存的位置开始找,也就是\0的位置
char* s3 = strtok(NULL, p);
//这一次没有#或者*就直接返回haha中h的地址
printf("%s\n", s3);
char* s4 = strtok(NULL, p);
//因为上一次调用没用找到#或者* ,所以这一次调用返回空指针
return 0;
}

#include<string.h>
int main()
{
char arr1[] = { "hello#world*haha" };
char arr2[20] = { 0 };
strcpy(arr2, arr1);
char* s = NULL;
char* p = "*#";
for (s = strtok(arr2, p); s != NULL; s = strtok((NULL), p))
{
printf("%s\n", s);
}
return 0;
}
strerror函数
是将错误码翻译成错误信息,返回错误信息字符串的起始地址
在C语言中使用库函数时,如果发生错误就会把错误码放在errno变量中
errno是全局变量
char * strerror ( int errnum );
函数的返回类型是char*,返回的是错误信息字符串的起始地址
参数类型是int

字符分类函数和字符转换转换函数
这些函数的头文件都是#include<ctype.h>
字符分类函数

int islower ( int c );
判断字母是不是小写字母,如果是小写字母就返回一个非0的数字,如果不是,就返回0
int main()
{
//判断是不是小写字母,是返回一个非0的值,不是返回0
int rst1 = islower('a');
printf("%d\n", rst1);
//判断是不是十进制数字0~9,是返回一个非0的值,不是返回0
int rst2 = isdigit('9');
printf("%d\n", rst2);
//判断是不是十六进制数字0~9包括大写字母A~F和小写字母a~f,是返回一个非0的值,不是返回0
int rst3 = isxdigit('F');
printf("%d\n", rst3);
return 0;
}

字符转换函数
int tolower ( int c );
int toupper ( int c );
函数要包含头文件<ctype.h>
tolower是把大写字母转换成小写字母,toupper是把小写字母转化为大写字母
函数的参数类型是int,传递的是字母的ASCII码值,返回的也是字母的ASCII值

//把字符串Test String.\n转换成小写
#include<string.h>
int main()
{
char arr[] = { "Test String.\n" };
size_t i = 0;
for (i = 0; i < sizeof(arr); i++)
{
//判断是不是大写字母,如果是就是非0,进入转换成小写
if (isupper(arr[i]))
{
arr[i] = tolower(arr[i]);
}
}
printf("%s", arr);
return 0;
}

memcpy
函数需要头文件<string.h>
void * memcpy ( void * destination, const void * source, size_t num );
函数的参数是把source中的内容拷贝到destination中,
num规定了拷贝的字节数,注意在拷贝时时一个字节一个字节的拷贝
用void* 作为函数的返回类型和参数类型,可以接收任意类型指针
返回的是目标空间的起始地址
//memcpy函数
#include<string.h>
int main()
{
int arr1[10] = { 0 };
int arr2[] = { 1,2,3,4,5 };
memcpy(arr1, arr2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
return 0;
}

memcpy函数的模拟实现
#include<assert.h>
void* my_memcpy(void* p1, const void* p2, size_t num)
{
assert(p1 && p2);
void* p = p1;
size_t i = 0;
while (i < num)
{
//void*类型不能进行+-和解引用操作,先强制类型转换然后解引用赋值
*((char*)p1) = *((char*)p2);
// void*类型先强制类型转换后+1
p1 = (char*)p1 + 1;
p2 = (char*)p2 + 1;
i++;
}
return p;
}
int main()
{
int arr1[10] = { 0 };
int arr2[] = { 1,2,3,4,5 };
void* p = my_memcpy(arr1, arr2, 20);
return 0;
}

memmove函数
void * memcpy ( void * destination, const void * source, size_t num )
C语言标准规定:memcpy实现不重叠的内存拷贝,重叠的内存拷贝,用memmove实现
#include<string.h>
int main()
{
//希望把前五个元素1,2,3,4,5拷贝到arr[2]arr[3]...这就导致内存重叠
//用的函数就是memmove
int arr[] = { 1,2,3,4,5,6,7,8,9 };
memmove(arr + 2, arr, 20);
return 0;
}

模拟实现memmove函数

#include<assert.h>
void* my_memmove(void* p1, const void* p2, size_t num)
{
assert(p1 && p2);
void* p = p1;
size_t i = 0;
//模版在后面,从前往后拷贝
if ((char*)p2 > ((char*)p1))
{
while (num--)
{
*(char*)p1 = *(char*)p2;
p1 = (char*)p1 + 1;
p2 = (char*)p2 + 1;
}
}
else//模版在前面,从后往前拷贝
{
p1 = (char*)p1 + num - 1;
p2 = (char*)p2 + num - 1;
while (num--)
{
//*((char*)p1 + num) = *((char*)p2 + num);
*(char*)p1 = *(char*)p2;
p1 = (char*)p1 - 1;
p2 = (char*)p2 - 1;
}
}
return p;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
void* p = my_memmove(arr + 2, arr, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}

memset
void* memset(void* ptr,int value,size_t num)
函数的返回类型是void*
ptr是要替换的起始位置,
value 表示要替换的字符的ASCII值
num表示要替换的字符个数
//memset是以字节为单位设置内存的
#include<string.h>
int main()
{
char arr1[] = { "hello world" };
memset(arr1 + 6, 'x', 3);
printf("%s\n", arr1);
// int arr2[10] = { 0 };
// memset(arr2, 1, 40);
// //这样 并不能得到是个1
// int i = 0;
// for (i = 0; i < 10; i++)
// {
// printf("%d ", arr2[i]);
// }
return 0;
}


memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
与strcmp类似 ,也是以字节为单位进行比较,但是memcmp可以比较的类型不止char型int double等都可以比较
#include<string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7 };
int arr2[] = { 1,2,3 };
int arr3[] = { 1,2,5 };
int arr4[] = { 1,2,2 };
int rst1 = memcmp(arr1, arr2, 12);
int rst2 = memcmp(arr1, arr3, 12);
int rst3 = memcmp(arr1, arr4, 12);
printf("%d\n", rst1);
printf("%d\n", rst2);
printf("%d\n", rst3);
return 0;
}





1586

被折叠的 条评论
为什么被折叠?



