常见字符函数和字符串函数

常见字符函数和字符串函数

前言

C语言中对字符和字符串的处理非常频繁,但是C语言本身没有字符串的类型,字符串通常放在常量字符串中或者字符数组中。

字符串常量适用于那些对它不做修改的字符串函数。

求字符串长度

strlen

函数:size_t strlen(const char* str);

参数:

  • 入参:const char* str为待计算的字符串首地址。
  • 返回值:size_t为计算出的字符串长度。

说明:

  • 字符串以’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前出现的字符个数(不包括’\0’)。
  • 入参指向的字符串必须以’\0’结尾。
  • 注意函数的返回值size_t是无符号的(易错)

案例:

​ 请思考以下代码段的执行结果:

int main()
{
    if(strlen("abc") - strlen("abcdef") > 0)
    {
        printf("111\n");
    }
    else
    {
        printf("222\n");        
    }
    return 0;
}

答案:以上代码的输出结果为111,这是因为strlen的返回值类型size_t 是一个无符号整型(unsigned int类型),两个无符号类型相减结果为无符号类型,无符号类型数一定大于等于0。

长度不受限制的字符串函数

strcpy

函数:char* strcpy(char* destination, const char* source);

参数:

  • 形参1:char* destination被拷贝的目标地址
  • 形参2:const char* source为待拷贝的字符串首地址
  • 返回值:char*被拷贝的目标地址

说明:

  • 入参指向的字符串必须以’\0’结尾。
  • 会将字符串中的’\0’拷贝到目标空间。
  • 目标空间必须足够大,确保能存放源字符串。
  • 目标空间必须可变(不能指向常量字符串)。

案例:

​ 请思考以下代码段的执行结果:

int main()
{
	char arr1[] = {'a','b'};
	char arr2[] = ”abcdef“;
	
	strcpy(arr2, arr1);
	return;
}

答案:错误代码,程序会崩溃。因为arr1没有以’\0’结尾,strcpy不知道结束标志,可能出现数组下标越界访问。

strcat

函数:char* strcat(char* destination, const char* source);

参数:

  • 形参1:char* destination待追加的目标空间首地址
  • 形参2:const char* source为待追加的字符串首地址
  • 返回值:char*被追加后的目标空间首地址

说明:

  • 入参指向的字符串必须以’\0’结尾。
  • 会将字符串中的’\0’拷贝到目标空间。
  • 目标空间必须足够大,确保能存放源字符串。
  • 目标空间必须可变(不能指向常量字符串)。
  • 不能自己追加自己

案例:

​ 请思考以下代码段的执行结果:

int main()
{
	char arr1[30] = "abc";

	strcat(arr1, arr1);
	return;
}

答案:错误代码,程序会崩溃。自己追加自己会导致strcat函数一直找不到’\0’,最总下标越界访问。

strcmp

函数:int strcmp(const char* str1, const char* str2);

参数:

  • 形参1:const char* str1待比较的字符串1
  • 形参2:const char* str2待比较的字符串2
  • 返回值:int比较结果
    • str1 > str2 ,则返回>0
    • str1 = str2 ,则返回0
    • str1 < str2 ,则返回0

说明:

  • 注意,str1 = str2 的返回值并不是-1,0,1。当str1与str2不相等时,返回结果为*str1 - *str2的值。

长度受限制的字符串函数

说明:

长度不受限制的字符串在使用时,常出现目标空间不够或者下标越界的问题。所以为了提高编码的可靠性,C语言库函数提供了一些长度受限的字符串函数。

strncpy

函数:char* strcpy(char* destination, const char* source, size_t num);

说明:

  • 拷贝num个字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串后,在后面追加’\0’,直到num个。

strncat

函数:char* strcat(char* destination, const char* source, size_t num);

strncmp

函数:int strcmp(const char* str1, const char* str2, size_t num);

字符串查找

strstr

函数:char* strstr(const char* string, const char* strCharSet);

参数:

  • 形参1:const char* string主串
  • 形参2:const char* strCharSet子串
  • 返回值:char*子串在主串中首次出现的起始位置,未找到则返回空指针

说明:

  • 拷贝num个字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串后,在后面追加’\0’,直到num个。

strtok

函数:char* strtok(char* str, const char* sep);

参数:

  • 形参1:const char* string待分割的主串,它包含了0个或多个由sep字符串中的一个或多个分隔符分割的标记。
  • 形参2:const char* sep是一个字符串,定义了作分隔符的字符集合(注意,是一个集合,也就是说可以有多种分隔符)
  • 返回值:char*子串在主串中首次出现的起始位置,未找到则返回空指针

说明:

  • strtok函数会找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可以修改。)
  • strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个函数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回NULL指针。

案例:

请思考以下代码段的两次输出结果:

int main()
{
    char arr[] = "abc.def@gh@";
    char *p = ".@";
    char temp[100] = {0};
    strcmp(temp, arr);
    char p1 = NULL;
    
    p1 = strtok(temp, p);
    printf("%s\n", p1);
    
    p1 = strtok(NULL, p);
    printf("%s\n", p1);    
}

答案:

第一次输出:“abc”

第二次输出:“def”

因为第一次调用strtok时,将字符串中的第一个.号修改为了\0并返回了被切割后的子串"abc"的首地址。第二次调用strtok时,将字符串中的第一个@号修改为了\0并返回了被切割后的子串"def"的首地址。

strerror

函数:char* strerror(int errnum);

参数:

  • 形参1:coint errnum错误码信息
  • 返回值:char*错误码在C语言中对应的错误信息字符串

说明:

  • strerror函数的作用是返回错误码,所对应的错误信息。
  • strerror函数需要与erron搭配使用。erron是一个全局的错误码的变量,当C语言的库函数在执行过程中,发生了错误,就会把对应的错误码赋值到erron中,通过 strerror函数就可以解析erron变量获取到错误信息。

案例:

int main()
{
	FILE* pf = fopen("text.txt", "r");	// 以读方式打开文件
    
    if(NULL == pf)	// pf为空,表示文件打开失败
    {
        /* fopen方法执行失败时,会将错误码赋值给全局变量errno,使用strerror函数可以解析错误码对应的含义。*/
        printf("%s\n", strerror(errno));
    }
    else
    {
        printf("open file success.\n");       
    }
}

字符操作

字符分类:

函数如果他的参数符合以下条件就返回true
iscntrl任何控制字符
isspace空白字符:空格’ ‘,换页’\f’,换行’\n’,回车’\r’,制表符’\t’,垂直制表符’\v’
isdigit十进制0~9
isxdigit十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
islower小写字母a~z
isupper大写字母A~Z
isalnum字母或数字,az,AZ,0~9
ispunct标点符号,任意不属于数组或字母的图形符号(可打印)
israph任何图形字符
isprint任何可打印字符,包括图形字符和空白字符

字符转换:

大写字母转小写:int tolower(int c)

小写字母转大写int toupper(int c)

参数:

  • 形参1:int c表示待转换的字符
  • 返回值:int表示转换后的字符

说明:

  • 把大写字母转换为小写字母,如果参数c不是大写字母就不转换
  • tolower函数的参数和返回值是整数,不是字符,因为在C语言中,字符就是整数

内存操作函数

memcpy

函数:void* memcpy(void* destination, const void* source, size_t num);

参数:

  • 形参1:void* destination被拷贝到的目标地址
  • 形参2:const void* source待拷贝的原始数据地址
  • 形参3:size_t num需要拷贝几个字节
  • 返回值:void*目的地的起始地址

说明:

  • 函数memcpy会从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • memcpy函数遇到\0时不会停下来。
  • 如果source和destination有任何的重叠,复制的结果都是未定义的。(使用memcpy时,要避免源地址和目的地址有重叠,如果内存空间有重叠,一般推荐使用memmove函数)

案例:

int main()
{
    int arr1[] = {1,2,3,4,5};
    int arr2[5] = {0};
    memcpy(arr2, arr1, sizeof(arr1));
}

memmove

函数:void* memove(void* dest, const void* src, size_t count);

参数:

  • 形参1:void* dest被拷贝到的目标地址
  • 形参2:const void* src待拷贝的原始数据地址
  • 形参3:size_t count需要拷贝几个字节
  • 返回值:void*目的地的起始地址

说明:

  • 函数memove会从src的位置开始向后复制count个字节的数据到dest的内存位置。
  • memove函数遇到\0时不会停下来。
  • 如果src和dest有任何的重叠,复制的结果都不会受到影响。

memset

函数:void* memset(void* dest, int c, size_t count);

参数:

  • 形参1:void* dest待设置缓冲区的起始目标地址
  • 形参2:int c待设置的字符
  • 形参3:size_t count需要设置几个字节
  • 返回值:void*在函数运行结束后返回这块空间的起始地址.

说明:

  • memset函数的主要功能是将一段内存区域设置为指定值
  • memset函数用于按字节初始化内存块(易错)
  • memset函数用于使用单一字节值填充整个内存区域。对于需要复杂填充模式的情况,如交替字节值,应采用循环或其他编程逻辑来实现。

案例:

请思考以下代码段的输出结果:

int main()
{
    int arr[10] = {0};
    memset(arr, 1, 10);
    
    for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) {
   		printf("%d ", arr[i]);
    }
    
    return 0;
}

答案:

输出结果为:16843009 16843009 257 0 0 0 0 0 0 0

因为memset是以字节为单位初始化内存的,执行memset(arr, 1, 10);后,会将arr地址开始往后10个字节全部改成1,但是一个int类型占4个字节。

memcmp

函数:int memcmp(const void *str1, const void *str2, size_t n);

参数:

  • 形参1:const void *str1指向内存块的指针
  • 形参2:const void *str2指向内存块的指针
  • 形参3:size_t count要被比较的字节数
  • 返回值:
    • 如果返回值 < 0,则表示 str1 小于 str2
    • 如果返回值 > 0,则表示 str2 小于 str1
    • 如果返回值 = 0,则表示 str1 等于 str2

说明:

  • memset函的功能是把存储区 str1 和存储区 str2 的前 n 个字节进行比较
  • s1,s2为字符串时候memcmp(s1,s2,1)就是比较s1和s2的第一个字节的ascII码值
C语言中有两个相关概念,函数指针和指针函数。 1. 函数指针(Function Pointers):函数指针是指向函数的指针变量。它可以用来存储和调用特定类型的函数。通过函数指针,可以在运行时动态地选择要执行的函数函数指针的声明形式为:`返回类型 (*指针变量名)(参数列表)`。例如,以下是一个函数指针的示例: ```c #include <stdio.h> void display(int num) { printf("Number: %d\n", num); } int main() { void (*func_ptr)(int); // 声明一个函数指针变量 func_ptr = display; // 将函数的地址赋值给函数指针变量 func_ptr(10); // 通过函数指针调用函数 return 0; } ``` 2. 指针函数(Pointer to a Function):指针函数是一个返回指向函数的指针的函数。它返回的是函数的地址,而不是函数的返回值。指针函数的声明形式为:`返回类型 (*函数名)(参数列表)`。以下是一个指针函数的示例: ```c #include <stdio.h> int add(int num1, int num2) { return num1 + num2; } int subtract(int num1, int num2) { return num1 - num2; } int (*getOperation(char op))(int, int) { if (op == '+') { return add; // 返回add函数的地址 } else { return subtract; // 返回subtract函数的地址 } } int main() { int num1 = 10, num2 = 5; char op = '+'; int (*operation)(int, int); // 声明一个指针函数变量 operation = getOperation(op); // 将指针函数的返回值(函数地址)赋值给指针函数变量 int result = operation(num1, num2); // 通过指针函数调用对应的函数 printf("Result: %d\n", result); return 0; } ``` 以上就是函数指针和指针函数的基本概念和用法。通过它们,可以实现更灵活的函数调用和动态选择执行的函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值