⭐ 作者:小胡_不糊涂
作者主页:小胡_不糊涂的个人主页
持续更文,谢谢大家支持
函数作用 | 函数名 |
---|---|
求字符串长度 | strlen |
长度不受限制的字符串函数 | strcpy strcat strcmp |
长度受限制的字符串函数 | strncpy strncat strncmp |
字符串查找 | strstr strtok |
错误信息报告 | strerror |
内存操作函数 | memcpy memmove memset memcmp |
字符操作 |
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量适用于那些对它不做修改的字符串函数。
功能: 获取字符串长度
size_t strlen ( const char * str );//返回字符串str的长度
//str--字符串
字符串的长度由终止空字符 '\0'
确定:字符串的长度与字符串开头和终止空字符之间的字符数一样长(不包括终止空字符本身)。
例如:
char str[100]="string ";
定义了一个大小为 100 个字符的字符数组,但初始化 str 时使用的字符串的长度仅为 7 个字符。因此,当 sizeof(str) 的计算结果为 100 时,strlen(str) 返回 7。
通过 strlen函数 比较两个字符串大小
//有符号
#include
#include
int main()
{
const char* str1 = "abcdef";
const char* str2 = "bbb";
if ((int)strlen(str2) -(int) strlen(str1) > 0)
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;
}
//无符号的
#include
#include
int main()
{
const char* str1 = "abcdef";
const char* str2 = "bbb";
if (strlen(str2) - strlen(str1) > 0)
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;
}
注:
字符串str以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
参数指向的字符串必须要以 ‘\0’ 结束。
如果没有 ‘\0’ 结尾,长度会一直计算下去,直到遇到 ‘\0’ 。
注意函数的返回值为size_t,是无符号的。
#include
size_t my_strlen(const char* str)
{
int count = 0;
while (*str != '\0')//终止条件
{
count++;//累计 计算字符串长度
str++;
}
return count;
}
int main()
{
size_t sz = my_strlen("abc");//无符号类型
printf("%u\n", sz);//打印无符号十进制整型
return 0;
}
功能: 复制字符串
char * strcpy ( char * destination, const char * source );
//destination(目的地)--指向要在其中复制内容的目标数组的指针
//source(源)--要复制的字符串
将源指向的字符串复制到目标指向的数组中,包括终止的 ‘\0’ 字符(并在该点停止)。
为避免溢出,目标指向的数组的大小应足够长,以包含与源相同的字符串(包括终止空字符),并且不应在内存中与源重叠。
实例1:
#include
#include
int main()
{
char str1[] = "Sample string";
char str2[40];
char str3[40];
strcpy(str2, str1);//将str1拷贝到str2
strcpy(str3, "copy successful");
printf("str1: %s\nstr2: %s\nstr3: %s\n", str1, str2, str3);
return 0;
}
运行结果:
实例2:
#include
#include
int main()
{
char arr1[] = "xxxxxxxxxx";
char arr2[5] = { 'a', 'b', 'c', 'd', 'e' };
strcpy(arr1, arr2);//将 arr2 里的东西拷贝到 arr1 中
printf("%s\n", arr1);
return 0;
}
为什么结果不是 abcde 呢?
我们在调试时,打开监视窗口观察arr1的变化,虽然 abced 已拷贝给 arr1, 但没有发现结束标志,所以在创建 arr2 时,要在最后加上 ‘\0’
添加了结束标志的 arr2 :
注:
源字符串必须以 ‘\0’ 结束。
会将源字符串中的 ‘\0’ 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
#include
#include
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
assert(dest != NULL);//若字符串为空,就停止运行,并提示
assert(src != NULL);
while (*src != '\0')
{
*dest = *src;//实现拷贝
dest++;//后移一个字符
src++;
}
*dest = *src;// '\0'
return ret;
}
int main()
{
char arr1[20] = "hello world";
char arr2[] = "xxxxx";
my_strcpy(arr1 + 6, arr2);//从arr1的第六个字符之后开始拷贝arr2
printf("%s\n", arr1);
return 0;
}
运行结果:
补充:
assert(表达式)--表达式为真时, 程序继续运行, 如果表达式为假, 那程序就会停止运行, 并提示错误信息
功能: 连接字符串
char * strcat ( char * destination, const char * source );
//destineion--指向目标数组的指针,该数组应包含字符串,并且足够大以包含串联的结果字符串
//source--要追加的字符串
将源字符串的副本追加到目标字符串。
目标中的终止空字符被源的第一个字符覆盖,并且在目标中由两者串联形成的新字符串的末尾包含一个空字符。
目的地和来源不得重叠。
实例:
#include
#include
int main()
{
char str1[100]="hello ";
char str2[] = "world";
printf("%s\n", strcat(str1, str2));
return 0;
}
运行结果:
注:
源字符串必须以 ‘\0’ 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
#include
char* my_strcat(char*dest, const char *src)
{
assert(dest && src);
char* ret = dest;
//1. 找目标空间中的\0
while (*dest)
{
dest++;
}
while (*dest++ = *src++)//实现拷贝
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
功能: 比较两个字符串
int strcmp ( const char * str1, const char * str2 );
将字符串 str1 与字符串 str2 进行比较。
开始比较每个字符串的第一个字符。如果它们彼此相等,则继续以下对,直到字符不同或达到终止空字符。
此函数执行字符的二进制比较。
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
实例1:
#include
#include
int main()
{
printf("%d\n", strcmp("bbq","bcq"));
return 0;
}
运行结果:
-1
实例2:猜动物
#include
#include
int main()
{
char str1[] = "dog";
char str2[80];
do {
printf("Guess my favorite animal? ");
scanf("%s", str2);
} while (strcmp(str1, str2) != 0);
puts("Correct answer!");
return 0;
}
运行结果:
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()
{
int ret = my_strcmp("bbq", "bcq");
if (ret>0)
printf(">\n");
printf("%d\n", ret);//-1
return 0;
}
功能: 从字符串中复制字符
char * strncpy ( char * destination, const char * source, size_t num );
//destination--指向要在其中复制内容的目标数组的指针。
//source--要复制的 C 字符串。
//num--要从源复制的最大字符数。
//size_t 是无符号整数类型。
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于 num,则拷贝完源字符串之后,在目标的后边追加0,直到 num个。
实例:
#include
#include
int main()
{
char str1[] = "To be or not to be";
char str2[40];
char str3[40];
strncpy(str2, str1, sizeof(str2));
strncpy(str3, str2, 5);
str3[5] = '\0';
puts(str1);//打印字符串
puts(str2);
puts(str3);
return 0;
}
运行结果:
#include
#include
char* my_strncpy(char* dest, const char* sou, size_t num)
{
char* ret = dest;
assert(dest != NULL);
assert(sou != NULL);
for (int i = (int)num; i > 0; i--)
*dest++ = *sou++;
return ret;
}
int main()
{
char str1[20] = "abcdef";
char str2[] = "xxx";
my_strncpy(str1, str2, sizeof(str1));
puts(str1);
return 0;
}
功能: 从字符串追加字符
char * strncat ( char * destination, const char * source, size_t num );
//destination--指向目标数组的指针,该数组应包含一个字符串,并且足够大以包含串联的结果字符串,包括其他 null 字符。
//source--要追加的 C 字符串。
//num--要追加的最大字符数。
//size_t是无符号整数类型。
将源的第一个数字字符追加到目标,外加一个终止空字符。
如果源中 C 字符串的长度小于 num,则仅复制终止空字符之前的内容。
实例1:
#include
#include
int main ()
{
char str1[20];
char str2[20];
strcpy (str1,"To be ");
strcpy (str2,"or not to be");
strncat (str1, str2, 6);//将str2的前6个字符追加给str1后面
puts (str1);//To be or not
return 0;
}
int main()
{
char arr1[20] = "abcdef\0yyyyyyyy";
char arr2[] = "xxxxxxxxx";
strncat(arr1, arr2, 3);
puts(arr1);//abcdefxxx
return 0;
}
说明了,遇到了结束标志 '\0' 就开始复制源代码
#include
#include
char* my_strncat(char* dest, const char* soc, size_t num)
{
char* ret = dest;
int i=0;
int count = 0;
assert(dest != NULL);
assert(soc != NULL);
while (*dest != '\0')
{
dest++;
}
while (num--)//终止条件:复制的个数num
*dest++ = *soc++;//追加
*dest = '\0';
return ret;
}
int main()
{
char arr1[20] = "abcdef\0yyyyyyyy";
char arr2[] = "xxxxxxxxx";
my_strncat(arr1, arr2, 3);
puts(arr1);//abcdefxxx
return 0;
}
运行结果:
功能: 比较两个字符串的字符
int strncmp ( const char * str1, const char * str2, size_t num );
将字符串 str1 的字符数与字符串 str2 的字符数进行比较。
此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续使用以下对,直到字符不同,直到达到终止的空字符,或者直到两个字符串中的 num 字符匹配,以先发生者为准。
标准规定:
第一个不匹配的字符在 str1 中的值大于在 str2 中的值,则返回大于0的数字
两个字符串的内容相等,则返回0
不匹配的第一个字符在 str1 中的值低于 str2 中的值,则返回小于0的数字
实例:
//代码1
#include
#include
int main()
{
char arr1[] = "abcioxjnjj";
char arr2[] = "abcdef";
printf("%d\n", strncmp(arr1, arr2, 4));//1
return 0;
}
//代码2:
int main()
{
char arr1[] = "abcdoxjnjj";
char arr2[] = "abcdef";
printf("%d\n", strncmp(arr1, arr2, 4));//0
return 0;
}
strncmp 函数与 strcmp 函数相似,不过它是比较两个字符串的前n个字符,它比较结束的标志是比较出来前n个字符的不同或者直到 ’\0’ 为止。
#include
#include
int my_strncmp(const char* str1, const char* str2, size_t num)
{
assert(str1 != NULL);
assert(str2 != NULL);
while (num && *str1 && *str2)
{
if (*str1 > *str2)
{
return 1;
}
if (*str1 < *str2)
{
return -1;
}
else
{
return 0;
}
num--;
str1++;
str2++;
}
return 0;
}
int main()
{
char* str1 = "abcdoxjnjj";
char* str2 = "abcdef";
int ret = my_strncmp(str1, str2, 4);
printf("%d\n", ret);
return 0;
}
运行结果:
0
功能: 查找子字符串
const char * strstr ( const char * str1, const char * str2 );
//str1--要扫描的字符串。
//str2--包含要匹配的字符序列的字符串
返回指向 str2 中第一次出现的 str1 的指针,如果 str2 不是 str1 的一部分,则返回一个空指针。
匹配过程不包括终止空字符,但它到此为止。
实例:
#include
#include
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
char* ret = strstr(arr1, arr2);
if (ret != NULL)
printf("%s\n", ret);
else
printf("找不到\n");
return 0;
}
运行结果:
#include
char* my_strstr(char* str1, char* str2)
{
char* cp = str1;
char* s1 = cp;
char* s2 = str2;
if (*str2 == '\0')
return str1;
while (*cp)
{
//开始匹配
s1 = cp;
s2 = str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return cp;
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
char* ret = my_strstr(arr1, arr2);
if (ret != NULL)
printf("%s\n", ret);
else
printf("找不到\n");
return 0;
}
功能: 将字符串拆分为标记
char * strtok ( char * str, const char * delimiters );
(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)
实例:
#include
#include
int main()
{
char* p = "woaiCyuyan.com/cn";
const char* sep = "./";
char arr[30];
char* str = NULL;
strcpy(arr, p);//将数据拷贝一份,处理arr数组的内容
for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
运行结果:
功能: 返回错误码,所对应的错误信息
char * strerror ( int errnum );
实例:
#include
#include
#include //必须包含的头文件
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d: %s\n", i, strerror(i));
}
return 0;
}
功能: 复制内存块
void * memcpy ( void * destination, const void * source, size_t num );
//destination--指向要在其中复制内容的目标数组的指针,类型转换为 void* 类型的指针。
//source--指向要复制的数据源的指针,类型转换为 const void* 类型的指针。
//num--要复制的字节数。
//size_t 是无符号整数类型。
函数 memcpy 从 source 的位置开始向后复制 num 个字节的数据到destination的内存位置。
这个函数在遇到 ‘\0’ 的时候并不会停下来。
如果 source 和 destination 有任何的重叠,复制的结果都是未定义的。
实例:
#include
#include
struct {
char name[40];
int age;
} person, person_copy;
int main()
{
char myname[] = "peter";
memcpy(person.name, myname, strlen(myname) + 1);
person.age = 46;
memcpy(&person_copy, &person, sizeof(person));
printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);
return 0;
}
功能: 移动内存块,将字节数的值从源指向的位置复制到目标指向的内存块
void * memmove ( void * destination, const void * source, size_t num );
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
实例:
#include
#include
int main ()
{
char str[] = "i love C";
memmove(str , str +2, 3);
//从l开始的三个字符(lov)移动到str中,且覆盖了str原来的前三个字符
puts (str);
return 0;
}
运行结果: