字符串函数
求字符串长度
strlen
1、注意返回size_t,无符号数,参数为char*。
2、以 '\0' 作为结束标识符,返回字符串开头到 '\0' 中间的字符个数。
3、注意与sizeof函数不同
int main()
{
char arr[20] = "abc";
printf("%zd\n", strlen(arr));
printf("%zd", sizeof(arr));
}
4、模拟实现
三种实现方法
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
//1.计数器
//2.递归
//3.指针-指针
size_t my_strlen1(const char* str)
{
size_t ret = 0;
while (*str++ != '\0')
{
ret++;
}
return ret;
}
size_t my_strlen2(const char* str)
{
if (*str == '\0')
{
return 0;
}
else
{
return my_strlen2(str + 1) + 1;
}
}
size_t my_strlen3(const char* str)
{
char* left = str;
while (*str != '\0')
{
str++;
}
return str - left;
}
int main()
{
char arr[10] = { 0 };
gets(arr);
printf("%zd ", my_strlen1(arr));
printf("%zd ", my_strlen2(arr));
printf("%zd", my_strlen3(arr));
return 0;
}
长度不受限制的字符串函数
strcpy
字符串拷贝函数
1、目标空间没有const修饰,必须可以更改。
2、该函数会将源字符串的 '\0' 拷贝到目标空间,所以源字符串必须以 '\0' 结束。
注意上面代码中 arr2 将 arr1[4] 原本的 'x' 修改为 '\0' 。
3、目标空间必须足够大以确保能存放源字符串。
4、模拟实现
#include<stdio.h>
#include<assert.h>
//char* strcpy(char* destination, const char* source)
char* my_strcpy(char* dest, const char* sour)
{
assert(dest && sour);
char* ret = dest;
while (*dest++ = *sour++){}
return ret;
}
int main()
{
char arr1[20] = { 0 };
char arr2[20] = { 0 };
gets(arr2);
printf("%s", my_strcpy(arr1, arr2));
return 0;
}
strcat
字符追加函数
1、
2、目的地中的第一个 '\0' 会被源字符串覆盖,需要源字符串以 '\0' 结束。
3、目的地与源字符串不能重叠。
4、模拟实现
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* sour)
{
assert(dest && sour);
char* ret = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *sour++){}
return ret;
}
int main()
{
char arr1[20] = { "abcde\0xxxxx" };
char arr2[20];
gets(arr2);
printf("%s", my_strcat(arr1, arr2));
return 0;
}
strcmp
字符比较函数
1、
2、从每个字符串的第一个字符开始比较,直至找到不同或者 '\0'。
3、第一个字符串大于第二个字符串返回大于0的数字,相等返回0,小于返回小于0的数字。
4、模拟实现
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
assert(str1, str2);
while (*str1 == *str2)
{
if (*str1 =='\0')
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char arr1[10] = "abc";
char arr2[10];
gets(arr2);
printf("%d", my_strcmp(arr1, arr2));
return 0;
}
长度受限制的字符串函数
strncpy
拷贝num个字符的拷贝函数
1、
2、如果源字符串小于num,就会在拷贝完源字符串后在后面追加 0 ,直至num个
但如果源字符串大于num,字符串拷贝之后将会读取溢出
因为该函数不会在拷贝后在末尾隐式追加终止符。
strncat
追加num个字符的追加函数
1、
2、将源字符串的前num个字符追加给目的地,外加上一个终止符。
3、如果源字符串小于num个字符,则仅复制终止符前的字符。
strncmp
最多比较num个字符的比较函数
1、
2、函数开始比较字符串的每一个字符,直到出现不同或终止符或者num个字符比较完毕。
字符串查找
strstr
字符串查找函数
1、
2、返回指向str1中第一次出现str2的指针,如果没出现则返回null。
3、模拟实现
#include<stdio.h>
const char* my_strstr(const char* str1, const char* str2)
{
if (*str2 == '\0')
{
return str1;
}
char* ret = str1;
char* p = str2;
while (*str1)
{
while (*str1 == *str2)
{
*str1++;
*str2++;
if (*str2 == '\0')
{
return ret;
}
}
ret++;
str2 = p;
str1 = ret;
}
return NULL;
}
int main()
{
char arr1[20] = "abcdefg";
char arr2[20];
gets(arr2);
printf("%s", my_strstr(arr1, arr2));
return 0;
}
strtok
字符串拆分函数
1、
2、delimiters是个字符串,定义了分隔符的字符集合,作为str拆分的标记。
3、函数会找到str中的下一个标记,并用 '\0' 替换这个标记然后作为结尾,返回一个指向这里的指针。
4、当函数的第一个参数不为null,即是第一次拆分该字符串,函数将会找到第一个标记,并会记录这个标记的位置,用作第二次开始。当函数的第一个参数为null,即不是第一次拆分了,函数根据上一次拆分记录的位置开始找下一个标志。如果找到了终止符,即该字符串不存在更多的标记,则返回null。
5、举例
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "- This, a sample string.";
char* pch;
pch = strtok(str, " ,.-");
while (pch != NULL)
{
printf("%s\n", pch);
pch = strtok(NULL, " ,.-");
}
return 0;
}
错误信息报告
strerror
错误码翻译函数
1、
2、返回错误码所对应的错误信息。
字符操作函数
字符分类函数
字符转换函数
大写转小写:int tolower(int c);
小写转大写:int toupper(int c);
内存操作函数
memcpy
内存块拷贝函数
1、
2、将源指向的位置的num个字节的值,直接拷贝给目标指向的内存块。
3、遇到 '\0' 不会停止,而是会将它一并拷贝。
4、标准库中该函数的目标函数与源函数不应重叠,重叠复制的结果都是未定义的,但是在vscode2020中,memcpy函数更加强大,能够自我拷贝。
5、根据标准库建议模拟实现
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* sour, size_t num)
{
assert(dest && sour);
while (num--)
{
*(char*)dest = *(char*)sour;
dest = (char*)dest + 1;
sour = (char*)sour + 1;
}
}
int main()
{
int arr1[10] = { 0,1,2,3,4,5,6,7,8,9 };
int arr2[10] = { 0 };
my_memcpy(arr1 + 3, arr2, 20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
memmove
内存块移动函数
1、
2、在标准库中,memmove与memcpy的区别就是它源内存块与目的内存块重叠可以处理。
3、模拟实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest, const void* sour, size_t num)
{
assert(dest && sour);
if (sour < dest)
{
while (num--)
{
*((char*)dest + num) = *((char*)sour + num);
}
}
else
{
for (int i = 0; i < num; i++)
{
*((char*)dest + i) = *((char*)sour + i);
}
}
}
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
my_memmove(arr, arr+2, 20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
memset
1、
2、将ptr指向的num个字节设置为value,value以int形式传递,以char填充。
3、注意更改是将num个字节更改,下列两个运行实例。
这是char类型的字符串,更改从str开始的三个字节为 'x' 。
这是int类型的数组,更改str+3地址的三个字节,注意内存块的变化。
memcmp
内存块比较函数
1、
2、与strcmp不同,在找到 '\0' 之后仍会继续比较,要把num个字节比较完毕。