目录
1、字符串函数
1.1求字符串长度
1.1.1strlen函数
1.2长度不受限制的字符串函数
1.2.1strcpy函数
1.2.2strcat函数
1.2.3strcmp函数
1.3长度受限制的字符串函数介绍
1.3.1strncpy函数
1.3.2strncat函数
1.3.3strncmp函数
1.4字符串查找
1.4.1strstr函数
1.4.2strtok函数
1.5错误信息报告
1.5.1strerror函数
2、内存函数
2.1memcpy函数
2.2memmove函数
2.3memset函数
2.4memcmp函数
1、字符串函数
1.1求字符串长度
1.1.1strlen函数
C语言 strlen 函数用来求字符串的长度(包含多少个字符)。strlen() 函数从字符串的开头位置依次向后计数,直到遇见\0
,然后返回计时器的值。最终统计的字符串长度不包括\0
。
函数头文件:
#include <string.h>
函数原型:
size_t strlen(const char* str);
参数:str:表示要求长度的字符串
返回值:字符串str的长度
sizeof 统计出的字符串长度比 strlen() 函数的统计值大 1。原因很简单,sizeof 统计了字符串结尾的\0
,而 strlen() 函数没有。但是,sizeof 和 strlen() 函数的功能并不相同,strlen() 函数才是专门用来统计字符串长度,而 sizeof 不是。
sizeof() 和 strlen() 是 C 语言中两个非常常用的函数,它们都与计算内存大小有关,但是它们的作用是不同的。
sizeof() 和 strlen() 的主要区别在于:
sizeof()
是一个运算符,而strlen()
是一个函数。sizeof()
计算的是变量或类型所占用的内存字节数,而strlen()
计算的是字符串中字符的个数。sizeof()
可以用于任何类型的数据,而strlen()
只能用于以空字符 '\0' 结尾的字符串。- sizeof() 计算字符串的长度,包含末尾的 '\0',strlen() 计算字符串的长度,不包含字符串末尾的 '\0'。
sizeof() 函数是一个运算符而不是函数,用于计算一个类型或变量所占用的内存字节数。可以用它来获取任何类型的数据的字节数,包括基本数据类型、数组、结构体、共用体等等。
sizeof:
sizeof(type) //type:类型名 sizeof(variable) //variable:变量名strlen:
strlen(string) //string:string 是一个以空字符 '\0' 结尾的字符串
测试案例代码如下:
int main(void)
{
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;
}
1.2长度不受限制的字符串函数
1.2.1strcpy函数
C语言 strcpy() 函数用于对字符串进行复制(拷贝)。
函数头文件:
#include <string.h>
函数原型:
char* strcpy(char* strDestination, const char* strSource);
参数:strDestination:目的字符串,指向用于存储复制内容的目标数组。
strSource:源字符串,要复制的字符串。
返回值:该函数返回一个指向最终的目标字符串 dest 的指针。
strcpy() 会把 strSource 指向的字符串复制到 strDestination。必须保证 strDestination 足够大,能够容纳下 strSource,否则会导致溢出错误。C语言提供一种限制长度的字符串函数strncpy。
- 源字符串必须以 '\0' 结束。
- 会将源字符串中的 '\0' 拷贝到目标空间。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可变
测试案例代码如下:
int main(void)
{
char dest[50] = { 0 };
char src[50] = { "sakura0908" };
strcpy(dest, src);
puts(dest);
return 0;
}
1.2.2strcat函数
C 库函数 strcat 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。也可以说为用来将两个字符串连接(拼接)起来。
函数头文件:
#include <string.h>
函数原型:
char*strcat(char* strDestination, const char* strSource);
参数:strDestination:目的字符串,指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串。
strSource:源字符串,指向要追加的字符串,该字符串不会覆盖目标字符串。
返回值:该函数返回一个指向最终的目标字符串 dest 的指针
strcat() 函数把 strSource 所指向的字符串追加到 strDestination 所指向的字符串的结尾,所以必须要保证 strDestination 有足够的内存空间来容纳两个字符串,否则会导致溢出错误。C语言提供一种限制长度的字符串函数strncat。
注意:strDestination 末尾的\0
会被覆盖,strSource 末尾的\0
会一起被复制过去,最终的字符串只有一个\0
。
- 源字符串必须以 '\0' 结束。
- 目标空间必须有足够的大,能容纳下源字符串的内容。
- 目标空间必须可修改。
测试案例代码如下:
int main()
{
char src[50], dest[50];
strcpy(src, "This is source");
strcpy(dest, "This is destination");
strcat(dest, src);
printf("最终的目标字符串: |%s|", dest);
return(0);
}
1.2.3strcmp函数
C语言 strcmp() 函数用于对两个字符串进行比较(区分大小写)。
函数头文件:
#include <string.h>
函数原型:
int strcmp(const char *str1, const char *str2);
参数:str1 -- 要进行比较的第一个字符串。
str2 -- 要进行比较的第二个字符串。
返回值:该函数返回值如下:
如果返回值小于 0,则表示 str1 小于 str2。
如果返回值大于 0,则表示 str1 大于 str2。
如果返回值等于 0,则表示 str1 等于 str2。
strcmp() 会根据 ASCII 编码依次比较 str1 和 str2 的每一个字符,直到出现不到的字符,或者到达字符串末尾(遇见\0
)。
注意,C语言标准并没有具体规定 strcmp() 函数的返回值是多少,大多数编译器选择了以下两种方案:
- 返回两个字符串的差值,即找到两个字符串中首个不相等的字符,然后返回这两个字符的差值;
- 返回 -1、0 或者 +1;
例如,glibc 库(GNU C 运行时库)中使用的是第一种方案,而微软编译器使用的是第二种方案
测试案例代码如下:
int main()
{
char str1[50] = { 0 };
char str2[50] = { 0 };
int i = 1;
do {
printf("******第%d次输入******\n", i);
gets(str1);
gets(str2);
i++;
} while (strcmp(str1, str2));
return 0;
}
1.3长度受限制的字符串函数介绍
1.3.1strncpy函数
C 库函数 strncpy把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充,相当于升级版的strcpy函数
函数头文件:
#include <string.h>
函数原型:
char *strncpy(char *dest, const char *src, size_t n);
参数:dest:指向用于存储复制内容的目标数组。
src:要复制的字符串。
n:要从源中复制的字符数。
返回值:该函数返回最终复制的字符串。
测试案例代码如下:
int main()
{
char src[40] = { 0 };
char dest[12] = { 0 };
strcpy(src, "This is sakura0908");
strncpy(dest, src, 10);
printf("最终的目标字符串: %s\n", dest);
return(0);
}
1.3.2strncat函数
C 库函数 strncat把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止,相当于升级版的strcat函数。
函数头文件:
#include <string.h>
函数原型:
char *strncat(char *dest, const char *src, size_t n);
参数:dest:指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串,包括额外的空字符。
src:要追加的字符串。
n:要追加的最大字符数。
返回值:该函数返回一个指向最终的目标字符串 dest 的指针。
测试案例代码如下:
int main ()
{
char src[50], dest[50];
strcpy(src, "This is source");
strcpy(dest, "This is destination");
strncat(dest, src, 15);
printf("最终的目标字符串: |%s|", dest);
return(0);
}
1.3.3strncmp函数
C 库函数strncmp把 str1 和 str2 进行比较,最多比较前 n 个字节,相当于升级版的strcmp函数。
函数头文件:
#include <string.h>
函数原型:
int strncmp(const char *str1, const char *str2, size_t n);
参数:str1:要进行比较的第一个字符串。
str2:要进行比较的第二个字符串。
n:要比较的最大字符数。
返回值:该函数返回值如下:
如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str1 大于 str2。
如果返回值 = 0,则表示 str1 等于 str2。
测试案例代码如下:
int main()
{
char str1[15];
char str2[15];
int ret;
strcpy(str1, "abcdef");
strcpy(str2, "ABCDEF");
ret = strncmp(str1, str2, 4);
if (ret < 0)
{
printf("str1 小于 str2");
}
else if (ret > 0)
{
printf("str2 小于 str1");
}
else
{
printf("str1 等于 str2");
}
return(0);
}
1.4字符串查找
1.4.1strstr函数
C 库函数 strstr在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0',用于查找字符串。
函数头文件:
#include <string.h>
函数原型:
char *strstr(const char *haystack, const char *needle);
参数:haystack:要被检索的 C 字符串。
needle:在 haystack 字符串内要搜索的小字符串。
返回值:该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 NULL。
测试案例代码如下:
int main()
{
const char haystack[20] = "sakura0908";
const char needle1[10] = "0908";
const char needle2[10] = "hello";
char* ret = NULL;
ret = strstr(haystack, needle1);
printf("子字符串是: %s\n", ret);
ret = strstr(haystack, needle2);
printf("子字符串是: %s\n", ret);
return 0;
}
1.4.2strtok函数
C库函数strtok切割字符串,将str切分成一个个字串。
函数头文件:
#include <string.h>
函数原型:
char *strtok(char *str, const char *delim);
参数:str:要被分解的字符串
delim:用作分隔符的字符(可以是一个,也可以是集合)
返回值:该函数返回被分解的第一个子字符串,若无可检索的字符串,则返回空指针
测试代码案例如下:
int main()
{
char str[] = "https://blog.csdn.net/sakura0908?spm=1010.2135.3001.5343";
char* pch = NULL;
printf("%s\n", str);
pch = strtok(str, ":/?=.");
while (pch != NULL)
{
printf("%s\n", pch);
pch = strtok(NULL, " ,.-");
}
return 0;
}
- 第一次调用strtok(),传入的参数str是要被分割的字符串,而成功后返回的是第一个子字符串{http};
- 而第二次调用strtok的时候,传入的参数应该为NULL,使得该函数默认使用上一次未分割完的字符串继续分割 ,就从上一次分割的位置{//blog}作为本次分割的起始位置,直到分割结束。
- strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
- 如果字符串中不存在更多的标记,则返回 NULL 指针。
strtok注意事项:
1)delim 替换成 \0
在这个函数里strtok()在分解字符串的时候,第一个参数str是在不断变化的,这个函数是在改变原字符串,把原字符串通过第二个参数delim将所有的分割符{:?=.}替换成字符串结束标志字符{\0},则原字符串变化为{https\0//blog\0csdn\0net/sakura0908?spm=1010\02135\03001\05343\0}
错误案例代码如下:
int main()
{
char* str = "https://blog.csdn.net/sakura0908?spm=1010.2135.3001.5343";
const char s[2] = "/";
char* token;
// 获取第一个子字符串
token = strtok(str, s);
// 继续获取其他的子字符串
while (token != NULL)
{
printf("%s\n", token);
token = strtok(NULL, s);
}
return 0;
}
注意:在这里,我实现函数的时候将字符串数组直接用指针指向它了,结果运行错误,后面发现虽然第一个参数是可以传指针,但我们要考虑空间内存布局,在strtok()函数里是delim的{分隔符}替换{ \0}改变原字符串,而我们用指针指向这个字符串的时候,其实指向的是字符串常量,它的内存分布在文字常量区是不可被改变的,所以出现了错误!
(2)delim分隔符
- strtok()的第二个参数delim,delim里可以是所有分隔符的集合,第二个参数delim可以是{:?/.},用一个或多个分隔符去分解字符串都可以
(3)delim分隔符可不可以出现在第一个字符?
当strtok分解的字符串首字符就是分隔符,那么strtok()会忽略首个分隔符,直接从第二个分隔符往下继续分解,例如:{- aaa - bbb} 那么strtok()会忽略第一个{-},还是以{aaa - bbb}的字符串形式继续分解。
1.5错误信息报告
1.5.1strerror函数
C 库函数 strerro从内部数组中搜索错误号 errnum,并返回一个指向错误消息字符串的指针。strerror 生成的错误字符串取决于开发平台和编译器。
函数头文件:
#include <string.h>
#include <errno.h>
函数原型:
char *strerror(int errnum);
参数:errnum:错误号,通常是 errno
返回值:该函数返回一个指向错误字符串的指针,该错误字符串描述了错误 errnum
测试案例代码如下:
int main()
{
FILE* pf = fopen("unexist.ent", "r");
if (pf == NULL)
printf("Error opening file unexist.ent: %s\n", strerror(errno));
return 0;
}
函数 | 如果他的参数复合下列条件就返回值 |
iscntrl | 任何控制字符 |
isspace | 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v' |
isdigit | 十进制数字 0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 字母a~z或A~Z |
isalnum | 字母或者数字,a~z,A~Z,0~9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
2、内存函数
2.1memcpy函数
C 库函数 memcpy 从存储区 str2 复制 n 个字节到存储区 str1。这个函数在遇到'\0'的时候并不会停下来。如果str1和str2有任何的重叠,复制的结果都是未定义的。
memcpy与strcpy的区别
1.复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2.复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3.用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
函数头文件:
#include <string.h>
函数原型:
void *memcpy(void *str1, const void *str2, size_t n);
参数:str1:指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
str2:指向要复制的数据源,类型强制转换为 void* 指针。
n:要被复制的字节数。
返回值:该函数返回一个指向目标存储区 str1 的指针。
测试案例代码如下:
int main()
{
const char src[50] = "sakura0908";
char dest[50] = { 0 };
memcpy(dest, src, strlen(src) + 1);
printf("dest = %s\n", dest);
return(0);
}
2.2memmove函数
C库函数memmove用于内存拷贝的函数,没有类型限制,但是memmove使用要考虑内存重叠问题,memmove() 是比 memcpy() 更安全的方法。如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同
函数头文件:
#inlcude <string.h>
函数原型:
void * memmove(void * destination, const void * source, size_t num);
参数:destination:指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
source:指向要复制的数据源,类型强制转换为 void* 指针。
num:要被复制的字节数。
返回值:该函数返回一个指向目标存储区 destination 的指针。
测试案例代码如下:
int main()
{
char str[] = "memmove can be very useful......";
memmove(str + 20, str + 15, 11);
printf("str = %s\n", str);
return 0;
}
2.3memset函数
定义变量时一定要进行初始化,尤其是数组和结构体这种占用内存大的数据结构。在使用数组的时候经常因为没有初始化而产生“烫烫烫烫烫烫”这样的野值,俗称“乱码”。
每种类型的变量都有各自的初始化方法,memset() 函数可以说是初始化内存的“万能函数”,通常为新申请的内存进行初始化工作。它是直接操作内存空间,mem即“内存”(memory)的意思。
函数头文件:
#include <string.h>
函数原型:
void *memset(void *s, int c, unsigned long n);
参数:s:void* 型的指针变量,可以为任何类型的数据进行初始化,指向要填充的内存块
c:要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式
n:要被设置为该值的字符数
返回值:该值返回一个指向存储区 s 的指针
注意:
-
memset赋值为任意字符都是可以的,初始化成0是最常用的。int类型的一般都是赋值0或-1,其他的值都不行。
-
memset赋值的时候是按字节赋值,是将参数化成二进制之后填入一个字节。
-
若str指向char型地址,value可为任意字符值;若str指向非char型,如int型地址,要想赋值正确,value的值只能是-1或0,因为-1和0转化成二进制后每一位都是一样的,设int型占4个字节,则-1=0XFFFFFFFF, 0=0X00000000。
测试案例代码如下:
int main()
{
char str[50];
strcpy(str, "This is sakura0908's csdn!");
puts(str);
memset(str, '$', 7);
puts(str);
return(0);
}
2.4memcmp函数
C 库函数 memcmp 把存储区 str1 和存储区 str2 的前 n 个字节进行比较。
函数头文件:
#include <string.h>
函数原型:
int memcmp(const void *str1, const void *str2, size_t n);
参数:str1:指向内存块的指针。
str2:指向内存块的指针。
n:要被比较的字节数。
返回值:
如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str1 大于 str2。
如果返回值 = 0,则表示 str1 等于 str2。
strcmp函数与memcmp函数的区别
二者都可以用于字符串的比较,但是二者是有比较大的差异的,因为strcmp是按照字节(byte-wise)比较的,并且比较的过程中会检查是否出现了"/0"结束符,一旦任意一个字符串指针前进过程中遇到结束符,将终止比较。而memcmp函数是用于比较两个内存块的内容是否相等,在用于字符串比较时通常用于测试字符串是否相等,不常进行byte-wise的字符串比较。如果要比较的对象中包含一些由于边界对齐需求而填入结构对象中的空格、联合 (union)结束的额外空格、字符串所分配的空间未使用完的部分引起的“holes”的话,最好使用memcmp来完成。这些“holes”的内容是不确定的,在执行byte-wise比较时结果也是不明确的。
测试案例代码如下:
int main()
{
char str1[15];
char str2[15];
int ret;
memcpy(str1, "abcdef", 6);
memcpy(str2, "ABCDEF", 6);
ret = memcmp(str1, str2, 5);
if (ret > 0)
{
printf("str2 小于 str1");
}
else if (ret < 0)
{
printf("str1 小于 str2");
}
else
{
printf("str1 等于 str2");
}
return(0);
}