字符串函数
1、strlcpy 【字符串拷贝】
(将原字符串中的字符拷贝到目标字符数组中,包括终止符号\0,并在这里停止;为了避免越界,目标字符串数组应该足够大去接收)👆
(返回值是 destination,是个地址,目标字符数组的首地址)
cpp
// strcpy 字符串拷贝
//模拟实现
char* my_strcpy(char* des, const char* sour)
{
assert(sour&&des);
char* ret = des;
/*while (*sour)
{
*des++ = *sour++;
}
*des = *sour;*/
while (*des++ = *sour++)
;
return ret;
}
int main()
{
char arr[20] = { 0 };
char sour[] = "i lovw you";
my_strcpy(arr, sour);
zhangsan
//strcpy(arr, "zhangsan");
//printf("%s\n", arr);
//strcpy(arr, "zhang\0san");
printf("%s\n", arr);
拷贝遇到\0停下
return 0;
}
2、strcat 【字符串追加】
(在目标地址\0处开始,将source指的字符串加到后面,包括source指向字符串的\0也加上去)
返回值是destination指向字符数组的首元素地址
cpp
// strcat 字符串追加
//模拟实现
char* my_strcat(char* des, const char* sour)
{
char* ret = des;
int len = strlen(des);
des = des + len;
while (*des++ = *sour++)
;
return ret;
}
int main()
{
char arr[20] = "hello";
char brr[] = ",lpp!";
printf("%s\n",arr);
my_strcat(arr, brr);
printf("%s\n", arr);
return 0;
}
3、strcmp 【字符串比较】
如何比较呢? 是一一对应的比较
a b c e o 字符串n
a b c p w 字符串m
= = = × ------> m>n
(从俩字符串的第一个字符开始比较,如果相同,继续比较,直到不相等或者\0)
返回值由比较结果决定,前者大于后者,返回>0 ;相等返回 0 ;前小于后,返回 <0
cpp
// strcmp 【比较字符串】
//模拟实现
int my_strcmp(const char* str1, const char* str2)
{
while (*str1++ == *str2++ && *str1 != '\0')
;
return *str1 - *str2;
}
int main()
{
char arr[] = "abwdef";
char brr[] = "abwdefp";
int n=my_strcmp(arr, brr);
printf("%d\n", n);
}
strcmp 、strcpy 、strcat 是长度不受限制的字符串函数↑,由一定风险,发生越界
strncmp、strncpy、strncat 是长度受限制的字符串函数 ↓ (多一个个数的限制)
4、strncpy 【字符串拷贝,限定版】
(跟strcpy用法基本一样,只不过多了一层限定,限定了拷贝字符的个数,
假如限定拷贝5个,source指向的字符串不止5个,就只拷贝 5个
source指向的字符串没有5个,依旧拷贝5个,没有的补 \0 )
cpp
int main()
{
char arr1[20] = "ancd yiw********* ";
char arr2[] = "hello";
strncpy(arr1, arr2, 10);
printf("%s\n", arr1);
return 0;
}
没有 拷贝之前 arr1 里面的字符如下:
拷贝之后 arr1 内字符如下 ↓ (可见,不足要求个数的时候补 \0)
5、strncat 【字符串追加 限定版】
同strcat用法差不多,也是多个限定追加字符的个数
但是当 追加个数(num) 大于sourse指向的字符串 里的字符个数时,不会强制全补 \0,
追加完sourse 指向字符串,就不再追加
cpp
int main()
{
char arr1[20] = "hello \0********";
char arr2[] = "baby";
strncat(arr1, arr2, 7);
printf("%s\n", arr1);
// hello baby
}
追加前 arr1 内情况👇
追加后,arr1 内情况 👇
6、strncmp 【字符串比较 限定版】
(比较停止条件 1、比出不同 2、比到 \0 3、比到超出要求数字(num))
cpp
int main()
{
char arr1[] = "abcde";
char arr2[] = "abcoi";
int n=strncmp(arr1, arr2, 3);
printf("%d ", n);
// 0
return 0;
}
如上: 当num为3 的时候 返回值是0,只比到了第三个字符
当num大于3时,返回值<0,因为第4对的 o 大于 d
如上,是长度受限制的字符串函数 👆
7、strstr 【查找子串】
返回的是查找到的那个字符串的首地址,如果没有查找到,返回空指针。
cpp
int main()
{
char arr[] = "hello my baby nice to meet you.";
char* ptr;
ptr=strstr(arr, "baby");
if (ptr != NULL)
strncpy(ptr, "lpp,", 4);
printf("%s\n", arr);
//hello my lpp, nice to meet you.
return 0;
}
模拟strstr函数,实现它的功能:
cpp
const char* my_strstr(const char* str1, const char* str2)
{
const char* s1 = str1;
const char* s2 = str2;
const char* p = str1;
while (*s1)
{
s1 = p;
s2 = str2;
while (*s1!='\0'&&*s2!='\0'&& * s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return (char*)p;
p++;
}
return NULL;
}
8、strtok 【切割字符串】
>strtok函数找到str中的下一个标记,并将其用\0结尾,返回指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。)
>strtok函数的第一个参数不为 NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串
中的位置。
>strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标
记。
>如果字符串中不存在更多的标记,则返回NULL指针。
(返回值:第一次传非空指针,发现字符串,返回发现字符首字母地址,
然后strtok记忆这个字符地址,下次NLULL进来,继续从这个位置开始,
读取完整个字符,返回NULL)
cpp
int main()
{
char arr[] = "i.study.every.day_365*day.";
char a[100] = { 0 };
strcpy(a, arr);
char* ret;
for (ret = strtok(a, "._*"); ret != NULL;ret=strtok(NULL,"._*"))
{
printf("%s ", ret);
}
return 0;
}
9、字符分类函数 <ctype.h>
|----------|------------------------------------------------------------|
| iscntrl | 任何控制字符 |
| isspace | 空白字符:空格' ' , 换页'\f', 换行'\n', 回车'\r', 制表符'\t', 垂直符'\v' |
| isdigit | 十进制数字0~9 |
| islower | 小写字母 |
| isupper | 大写字母 |
| isalpha | 字母(包括大小写) |
| isalnum | 字母或数字 |
| ispunct | 标点符号,任何不属于数字或字母的图形字符 |
| isgraph | 任何图形字符 |
| isprint | 任何可打印字符,包括图形字符和空白字符 |
| isxdigit | 十六进制数字,包括所有十进制数字, 小写字母a~f,大写字母A~F |
| 函数 ↑↑↑ | 如果·它的参数符合上面条件 就返回真 |
[字符分类函数]
用法相似,举个列子,isupper 函数
因为字符在内存中都是以·ASCII值储存的
cpp
int main()
{
char a = 'a';
char b = 'A';
printf("%d %d", isupper(a), isupper(b));
// 0 1
return 0;
}
假,返回 0,真,返回>0的值(1)
10、字符转换函数 tolower toupper
tolower 将 大写字母 变成 小写字母
toupper将 小写字母 变成 大写字母
其他不符合条件的字符不会改变
cpp
int main()
{
char a = 'A';
char b;
b = tolower(a);
printf("%c\n", b);
//a
b = tolower(b);
printf("%c\n", b);
//a
b = toupper(b);
printf("%c\n", b);
//A
b = toupper('@');
printf("%c\n", b);
//@
return 0;
}
11、strerror 【将错误码转换成错误信息】
c语言的库函数,在执行失败的时候,都会设置错误码
(给它一个错误信息码,它会找到对应的错误字符串,并且将首地址返回给你)
errno 是c语言设置的一个全局的 错误码 存放的变量 头文件<errno.h>
cpp
int main()
{
//printf("%s\n", strerror(0));//No error
//printf("%s\n", strerror(1));//Operation not permitted
//printf("%s\n", strerror(2));//No such file or directory
//printf("%s\n", strerror(3));//No such process
//fopen 是打开文件的函数, 里面放的是文件路径,和打开方式 r是 读
//如果打开失败 返回值是NULL
FILE* pf = fopen("C:\\Users\\嗷~里~个~嗷\\Desktop", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
}
else
{
;
}
//Permission denied
return 0;
}
内存函数
12、memcpy 【内存拷贝】
与strncpy不同的是,memcpy是适用于所有类型,第三个参数,是字节个数
其 返回值是 destination 所指向的首地址
memcpuy 负责 拷贝两块独立空间的数据,
不适用于重叠内存之间的数据拷贝
cpp
// 模拟实现
void* my_memcpy(const void* dis, const void* sou, size_t num)
{
//因为要保证整个函数具体范性,所以一个字节一个字节进行
//char* ,一次访问一个字节
char* ret =(char*) dis;
while (num--)
{
*(char*)dis = *(char*)sou;
dis = (char*)dis + 1;
sou = (char*)sou + 1;
}
return ret;
}
int main()
{
int i = 0;
int arr1[] = { 1,2,3,4,5,6,7,8 };
int arr2[4] = { 11,22,33,44 };
my_memcpy(arr1, arr2, sizeof(arr2));
for (i = 0; i < (sizeof(arr1) / sizeof(arr1[0]));i++)
printf("%d ",arr1[i]);
putchar('\n');
double brr1[] = { 1.1,2.2,3.3,4.4 };
double brr2[] = { 11.11,22.22,33.33,44.44 };
my_memcpy(brr1, brr2, sizeof(brr2));
for (i = 0; i < (sizeof(brr1) / sizeof(brr1[0])); i++)
printf("%.2lf ", brr1[i]);
return 0;
}
13、memmove 【内存拷贝,加强版】
与memcpy相比,它可以实现,重叠内存数据的拷贝,其他用法一样。
cpp
void test_cpy()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr + 2, arr, 20);
int i = 0;
for (i = 0; i < 10; i++)
printf("%d ", arr[i]);
putchar('\n');
}
void test_move()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr + 2, arr, 20);
int i = 0;
for (i = 0; i < 10; i++)
printf("%d ", arr[i]);
putchar('\n');
}
int main()
{
test_cpy();
test_move();
return 0;
}
模拟实现 👇
cpp
void* my_memmove(const void* des, const void* sour, size_t num)
{
assert(des && sour);
void* ret = des;
if (des < sour)
{
//从前往后拷贝
while (num--)
{
*(char*)des = *(char*)sour;
des = (char*)des + 1;
sour = (char*)sour + 1;
}
}
else
{
// 从后往前拷贝
while (num--)
{
*((char*)des + num) = *((char*)sour + num);
}
}
}
图解如下所示:
14、memcmp 【内存比较】
strncmp 函数相比,它是适用所有类型,其他基本一样
cpp
int main()
{
int arr[] = { 1,2,3,4,5 };
int brr[] = { 1,2,3,8,5 };
int x = memcmp(arr, brr, 12);
int y = memcmp(arr, brr, 16);
printf("%d %d", x, y);
// 0 -1
}
15、memset 【内存设置】
ptr 是指向我们要改变的位置,
value 是我们要变成的对象,
num是要改变字节的个数
cpp
int main()
{
char arr[] = "hello baby.";
memset(arr, '*', 5);
printf("%s\n", arr);
//***** baby.
int brr[5] = { 1,2,3,4,5 };
int i = 0;
memset(brr+1, 0, 8);
for (i = 0; i < 5; i++)
printf("%d ", brr[i]);
// 1 0 0 4 5
//一个字节一个字节来
return 0;
}
👏👏👏👏👏👏👏👏👏👏👏