字符串与相应函数(下)
字符串处理函数分类
- 求字符串长度:strlen
- 长度不受限制的字符串函数:strcpy,strcat,strcmp
- 长度受限制的字符串函数:strncpy,strncat,strncmp
- 字符串查找:strstr
- 字符串切割:strtok
- 错误信息报告:strerror
- 字符操作,内存操作函数:memcpy,memmove,memset,memcmp
strstr
strstr函数是C标准库中的一个字符串处理函数,用于在一个字符串中查找子字符串的第一次出现位置。strstr函数用于在字符串中查找子字符串的第一次出现位置。如果找到,则返回指向该位置的指针;如果未找到,则返回NULL
strstr函数的特点
strstr函数的模拟实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
if (str2 == "\0")
{
return (char*)str1;
}
const char* s1 = str1;
const char* s2 = str2;
const char* cp = str1;
while (*cp)
{
s1 = cp;
s2 = str2;
while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char*)cp;
}
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "aabbbcdef";
char arr2[] = "bbc";
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("找不到\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
strstr函数的使用
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "This is a simple string";
char* pch;
pch = strstr(str, "simple");
if (pch != NULL)
strncpy(pch, "sample", 6);
puts(str);
return 0;
}
strtok
strtok函数是C标准库中的一个字符串处理函数,它主要用于将输入字符串按照指定的分隔符进行分割,并返回每个子字符串的指针。这个函数非常适合处理各种常见的文本分割任务,如路径分隔、配置文件解析和数据文件处理
strtok函数的特点
字符串破坏:strtok函数会修改原始字符串,将其分割后的部分用\0
字符填充,因此原始字符串在分割后会失去原有的形式。
- 线程安全性:strtok函数不是线程安全的,因为它使用了静态分配的空间来存储被分割的字符串位置。这意味着在多线程环境中使用strtok函数可能会导致不可预测的行为。
- 分隔符的多样性:strtok函数支持多个分隔符,只需在
delim
中列出所有分隔符即可
strtok函数的使用
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "198.168.120.50";
char* p = ".";
char buf[20] = { 0 };
strcpy(buf, arr);
char* ret = NULL;
for (ret = strtok(buf, p);ret != NULL;ret = strtok(NULL, p))
{
printf("%s\n", ret);
}
return 0;
}
strerror
strerror函数是C语言中的一个函数,用于将指定的错误码转换为对应的错误信息字符串。
strerror函数的特点
- strerror函数的头文件:strerror函数定义在errno.h头文件中,因此在使用该函数之前,必须包含这个头文件。
- strerror函数的返回值 :strerror函数的返回值是一个指向错误消息字符串的指针,这个消息字符串即为出错信息的字符串。如果函数调用成功,返回值是指向错误信息字符串的指针;如果发生错误,则返回一个空指针(NULL)。
- strerror函数的注意事项 :需要注意的是,strerror函数不是线程安全的,因为在多线程环境中,多个线程可能会同时调用strerror函数并覆盖errno的值。因此,在多线程程序中,建议使用strerror_r函数,它是strerror的线程安全版本。
- strerror函数的使用场景:strerror函数通常在系统调用或库函数出错时使用。当这些函数返回错误时,会设置errno变量,此时可以使用strerror函数将errno的值转换为人类可读的错误信息,便于调试和日志记录。
strerror函数的使用
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
//打开文件
FILE* pf = fopen("text.exe", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
}
//读文件
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
在此我们看见我们还需要写一个输出语句,那么我们还可以使用perror函数,可以更加直接明了的发现错误
perror=printf+error
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
//打开文件
FILE* pf = fopen("text.exe", "r");
if (pf == NULL)
{
//printf("%s\n", strerror(errno));
perror("fopen");
return 1;
}
//读文件
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
memcpy
memcpy是C语言中的一个标准库函数,用于将源内存区域的内容复制到目标内存区域。
memcpy函数的特点
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
- 这个函数在遇到 '\0' 的时候并不会停下来。
- 如果source和destination有任何的重叠,复制的结果都是未定义的。
memcpy函数与strcpy函数的区别
1. 复制内容
- strcpy:专门用于复制字符串,它会一直复制直到遇到源字符串中的 '\0'结束符。
- memcpy:可以复制任意内容,如字符数组、整型、结构体、类等。它按照指定的字节数进行复制,而不是基于 '\0' 结束符。
2. 函数原型
- strcpy: char* strcpy(char* dest, const char* src); ,返回指向目标缓冲区 `dest` 的指针。
- memcpy:void* memcpy(void* dest, const void* src, size_t n); ,其中 n 是要复制的字节数,同样返回指向目标缓冲区 dest 的指针 。
3. 安全性
- strcpy :由于其不检查目标缓冲区的大小,若源字符串长度超过了目标缓冲区的大小(不包括 '\0' ),就 会发生缓冲区溢出,这是一个常见的安全隐患。例如,目标缓冲区只能容纳 5 个字符,而源字符串有 10 个字符,使用 ` strcpy 就会导致溢出 。
- memcpy :虽然它提供了复制字节数的选项,但如果指定了错误的字节数或目标缓冲区大小不足,也可能导致问题。不过,由于其提供了明确的字节数,所以相比于 strcpy ,它在某些情况下可能更安全 。
4. 用途
- strcpy :主要用于字符串的复制。当明确知道要复制的是字符串时,使用 strcpy 较为方便。
- memcpy :用于复制任意类型的内存块,特别是当需要复制的数据中可能包含 '\0' 字符时(因为 strcpy 在遇到 '\0' 时会停止复制)。例如,复制一个包含图像数据的内存块,就需要使用 memcpy 。
5. 实现方式
- strcpy :通过逐个字符复制直到遇到 '\0' 结束符来实现字符串的复制。
- memcpy :通过逐个字节复制来实现内存块的复制,直到达到指定的字节数 `n`。在地址不对齐的情况下,它是一个字节一个字节地拷,地址对齐以后,就会使用 CPU 字长(32bit 或 64bit)来拷,还会根据 CPU 的类型选择一些优化的指令来进行拷贝 [[4]()]。
6. 效率 :在拷贝相同字符串和字节数时,`strcpy` 的效率略高于 `memcpy`。不过 `memcpy` 是一个效率较高的内存拷贝函数,其实现与 CPU 类型、操作系统、cLib 相关。
memcpy函数的使用
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,0 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, 20);
int i = 0;
for (i = 0;i < 5;i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
memmove
memmove函数是C语言中用于内存操作的一个重要工具,它主要用于从源内存区域拷贝一定数量的字节到目标内存区域。memmove函数的一个显著特点是它可以处理源内存区域和目标内存区域重叠的情况,这使得它在处理某些特定的内存操作时非常有用
memmove函数的特点
1. 处理内存重叠
Memmove函数的一个显著特点是它可以处理源内存区和目标内存区重叠的情况。这意味着,如果源内存区和目标内存区的部分区域重叠,memmove仍然可以正确地复制字节,而不会像memcpy那样导致数据损坏。
2. 内存操作的安全性
由于memmove能够处理内存重叠,它在进行内存操作时更加安全。当源和目标内存区域重叠时,memmove会从高地址向低地址进行拷贝,以确保数据的正确性和完整性。
3. 返回值
Memmove函数的返回值是指向目标内存区的指针。这一点与memcpy相同。
4. 使用场景
Memmove通常在需要处理内存重叠的情况下使用,例如在字符串操作中移动字符串,或者在数组中移动元素。它的这些特点使得它在C语言编程中成为一个非常有用的工具。
5. 实现细节
虽然memmove的具体实现可能会有所不同,但它的基本思想是使用中间缓冲区的方式来复制数据,从而允许目标和源重叠。这种实现方式确保了数据的安全复制。
memmove函数的使用
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
char str[] = "memmove can be very useful......";
memmove(str + 20, str + 15, 11);
puts(str);
return 0;
}
memset
memset
函数的作用是将指针变量s
所指向的前n
字节的内存单元用一个整数c
替换。这个函数通常用于新申请的内存做初始化工作,例如将一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为''
或'/0'
.
memset函数的特点
1. 内存空间初始化
memset函数主要用于内存空间的初始化。它可以将一段内存空间全部设置为某个字符,通常用在对定义的字符串进行初始化为''或'\0'。例如,可以使用memset将一个字符数组初始化为空字符串2memset()函数及其作用_cc2530 memset(re,0,20)。
2. 清空结构体变量或数组
memset可以方便地清空一个结构类型的变量或数组。这对于大型数据结构的快速清零非常有用,避免了手动逐个成员清零的繁琐1memset()函数及其作用。
3. 字节级操作
memset函数以字节为单位进行操作,这意味着它可以将指定内存区域的每个字节设置为相同的值。这使得它非常适合用于初始化或清空原始内存块2memset()函数及其作用_cc2530 memset(re,0,20)。
4. 快速操作
对于较大的结构体或数组,memset是进行清零操作的一种最快方法。它的实现通常是优化过的,能够在较短时间内完成大量内存的初始化
memset函数的使用
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
char str[] = "haha xixi yesyes nono.";
memset(str, '@', 10);
puts(str);
return 0;
}
输出结果:
memcmp
memcmp 函数是C语言中的一个标准库函数,用于比较两个内存区域的内容。
memcmp函数的特点
- 逐字节比较:memcmp函数是按字节比较的,它逐个比较内存区域buf1和buf2的前count个字节。
- ASCII码比较:memcmp函数比较的是字节的ASCII码值,而不是字符的实际意义。
- 返回值:当buf1小于buf2时,返回值小于0;当buf1等于buf2时,返回值等于0;当buf1大于buf2时,返回值大于0。
- 不受字符串结束符影响:与strcmp函数不同,memcmp函数不会受到字符串结束符(如'\0')的影响,它只比较前count个字节。
- 适用范围:memcmp函数不仅可以用于比较字符串,还可以用于比较任何类型的内存区域,这使得它在处理二进制数据时非常有用。
- 效率:由于memcmp函数不需要寻找字符串结束符,因此在处理大型数据块时,它的效率通常比strcmp函数高。
memcmp函数的使用
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "abgrdsd";
char str2[] = "nxcjkdbc";
int n = 0;
n = memcmp(str1, str2, sizeof(str1));
if (n > 0)
printf("str1>str2\n");
else if(n == 0)
printf("str1=str2\n");
else
printf("str1 < str2");
return 0;
}