【C语言】字符函数,字符串函数,内存函数

简介: C语言中的字符串函数和内存函数

1. 字符函数

1.1 字符分类函数

字符分类函数的头文件为ctype.h

具体用法可以看这个:https://legacy.cplusplus.com/reference/cctype/
image.png

1.2 字符转换函数

字符转换函数的头文件也为ctype.h

1.2.1 tolower(将大写字母转化为小写字母)

函数原型:
image.png

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<ctype.h>

int main() {
   
    char ch = 'B';
    char new_ch = tolower(ch);
    printf("%c", new_ch);
    return 0;
}

image.png

1.2.2 toupper(将小写字母转化为大写字母)

函数原型:
image.png

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<ctype.h>

int main() {
   
    char ch = 'b';
    char new_ch = toupper(ch);
    printf("%c", new_ch);
    return 0;
}

image.png

2. 字符串函数

字符串输入函数和字符串输出函数的头文件均为stdio.h

其它的字符串函数头文件一般为string.h

2.1 字符串输入函数

2.1.1 gets()

函数原型:
image.png

gets() 函数的功能是从输入缓冲区中读取一个字符串存储到字符指针变量 str 所指向的内存空间。缓冲区(Buffer)又称为缓存(Cache),是内存空间的一部分。有时候,从键盘输入的内容,或者将要输出到显示器上的内容,会暂时进入缓冲区,待时机成熟,再一股脑将缓冲区中的所有内容“倒出”,我们才能看到变量的值被刷新,或者屏幕产生变化。

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

int main() {
   
    char str[30];
    gets(str);
    puts(str);
    return 0;
}

image.png

但是这个函数在C或C++不可再用(自C11和C++14起),因为不安全

(不过在实际做题中,我发现有些oj上还是能用的~)
image.png

2.1.2 fgets()

因为前面说了gets()函数不安全,在新版C++已经不可再用,所以fgets()用来替代gets()。

但注意fgets()不会删除行末的回车字符
image.png

fgets()函数是C语言中的一个输入函数,用于从标准输入(例如键盘)读取一行字符串。

函数原型:
image.png

fgets()的作用是读取一行字符并存储到指定的字符串缓冲区中,直到读取到换行符或者达到指定的最大字符数(包括换行符)为止。

其中,str是指向存储读取字符串的缓冲区的指针,num是缓冲区的大小,stream是要读取的文件流(通常使用stdin表示标准输入)。

fgets函数返回指向存储读取字符串的缓冲区的指针,如果读取成功,则返回值与str相同,如果出现错误或者到达文件末尾,则返回NULL。

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

int main() {
   
    char str[30];
    fgets(str,30,stdin);
    puts(str);
    return 0;
}

image.png

2.2 字符串输出函数 puts()

函数原型:
image.png

image.png

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

int main() {
   
    char str[30] = "hello world";
    puts(str);
    return 0;
}

image.png

2.3 字符串求长度函数 strlen

函数原型:
image.png

注意事项:

  1. 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包
    含 '\0' )
  2. 参数指向的字符串必须要以 '\0' 结束。
  3. 注意函数的返回值为size_t,是无符号的。

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

int main() {
   
    char str[30] = "abcdef";
    printf("%d\n", strlen(str));
    return 0;
}

image.png

strlen的模拟实现

size_t my_strlen(const char* str)
{
   
    assert(str);
    int cnt = 0;
    while (*str!='\0')
    {
   
        cnt++;
        str++;
    }
    return cnt;
}

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

2.4.1 字符串复制函数 strcpy

函数原型:
image.png

注意事项:

  1. 源字符串必须以 '\0' 结束。

  2. 会将源字符串中的 '\0' 拷贝到目标空间。

  3. 目标空间必须足够大,以确保能存放源字符串。

  4. 目标空间必须可变。

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main() {
   
    char str1[30] = {
    0 };
    char str2[30] = "abcdef";
    strcpy(str1, str2);
    printf("%s\n",str1);
    return 0;
}

image.png

strcpy的模拟实现

char* my_strcpy(char *dest,const char *src)
{
   
    assert(dest && src);
    char* ret = dest;
    while (*dest++=*src++)
    {
   
        ;
    }
    return ret;
}

2.4.2 字符串连接函数 strcat

函数原型:
image.png

注意事项:

  1. 源字符串必须以 '\0' 结束。

  2. 目标空间必须有足够的大,能容纳下源字符串的内容。

  3. 目标空间必须可修改。

  4. 字符串不能自己追加自己

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main() {
   
    char str1[30] = "hello ";
    char str2[30] = "world";
    printf("%s\n",strcat(str1,str2));
    return 0;
}

image.png

strcat的模拟实现

char* my_strcat(char* dest, const char* src)
{
   
    assert(dest && src);
    char* ret = dest;
    while (*dest!='\0')
        dest++;
    while (*dest++ = *src++)
    {
   
        ;
    }
    return ret;
}

2.4.3 字符串比较函数 strcmp

函数原型:
image.png

标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字。
第一个字符串等于第二个字符串,则返回0。
第一个字符串小于第二个字符串,则返回小于0的数字。

我们结合下图就能很直观理解上面的标准规定~
image.png

用法示例:

情况一:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main() {
   
    char str1[30] = "above";
    char str2[30] = "about";
    printf("%d\n",strcmp(str1,str2));
    return 0;
}

image.png

情况二:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main() {
   
    char str1[30] = "About";
    char str2[30] = "about";
    printf("%d\n",strcmp(str1,str2));
    return 0;
}

image.png

情况三:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main() {
   
    char str1[30] = "about";
    char str2[30] = "about";
    printf("%d\n",strcmp(str1,str2));
    return 0;
}

image.png

strcmp的模拟实现

int my_strcmp(const char* str1, const char* str2)
{
   
    assert(str1 && str2);
    while (*str1 == *str2)
    {
   
        if (*str1 == '\0')
            return 0;
        str1++;
        str2++;
    }
    if (*str1 > *str2) return 1;
    else return -1;
}

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

2.5.1 strncpy

函数原型:
image.png

注意事项

  1. 拷贝num个字符从源字符串到目标空间。

  2. 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main() {
   
    char str1[30] = "abcdef";
    char str2[30] = "xxxxxxxxxxxxxx";
    strncpy(str1, str2, 4);
    printf("%s\n", str1);
    return 0;
}

2.5.2 strncat

函数原型:
image.png

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main() {
   
    char str1[30] = "hello ";
    char str2[30] = "worldxxxxxx";
    strncat(str1, str2, 5);
    printf("%s\n", str1);
    return 0;
}

image.png

2.5.3 strncmp

函数原型:
image.png

逐个比较两个字符串字符的ASCII码值,直到出现不一样的字符或者一个字符串结束或者num个字符全部比较完。
image.png

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main() {
   
    char str1[30] = "abc";
    char str2[30] = "abcdef";
    char str3[30] = "aba";
    printf("%d\n", strncmp(str1, str2, 3));
    printf("%d\n", strncmp(str1, str2, 4));
    printf("%d\n", strncmp(str1, str3, 5));
    return 0;
}

image.png

2.6 字符串查找函数 strstr

函数原型:
image.png

strstr函数的作用是在字符串str1中查找是否含有字符串str2的子串,如果存在,返回str2在str1中第一次出现的地址;否则返回空指针NULL。

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main() {
   
    char str1[30] = "abcdef";
    char str2[30] = "abc";
    if (strstr(str1, str2))
        printf("找到了\n");
    else
        printf("找不到\n");
    return 0;
}

image.png

strstr的模拟实现

char* my_strstr(char* str1, char* str2)
{
   
    assert(str1 && 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;
}

2.7 字符串分割函数 strtok

strtok函数的作用是将一个字符串按照指定的分隔符进行分割,并返回分割后的子字符串。

函数原型:
image.png

注意事项:

  1. sep参数是个字符串,定义了用作分隔符的字符集合。

  2. 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。

  3. strtok函数找到str中的下一个标记,并将其用' \0' 结尾,返回一个指向这个标记的指针。(注:
    strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
    并且可修改
    。)

  4. strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

  5. strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
    记。

  6. 如果字符串中不存在更多的标记,则返回NULL 指针。

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main() {
   
    char str[] = "Hello, world! How are you today?";
    char delim[] = " ,!?"; // 分隔符包括空格、逗号和感叹号

    // 使用第一次调用strtok函数
    char* token = strtok(str, delim);

    // 循环调用strtok函数以获取每个子字符串
    while (token != NULL) {
   
        printf("%s\n", token);
        token = strtok(NULL, delim);
    }

    return 0;
}

以上代码将输入字符串"Hello, world! How are you today?"按照空格、逗号和感叹号作为分隔符,将其分割成多个子字符串,并依次打印每个子字符串。输出结果如下:
image.png

注意:在整个循环过程中,使用NULL作为第一个参数,以便继续分割原字符串。这样可以依次获取每个子字符串。

2.8 错误处理函数 strerror

strerror的作用是根据给定的错误代码返回相应的错误描述字符串。

具体而言,strerror函数接受一个整数参数errno作为输入,该参数代表了一个错误代码。函数会根据给定的错误代码查找对应的错误描述字符串,并将其返回。

函数原型:
image.png

用法示例:

示例一:

下面代码是将错误码0~9所对应的错误信息给打印出来:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>

int main()
{
   
    int i = 0;
    for (int i = 0; i < 10; i++)
    {
   
        printf("%d:%s\n", i, strerror(i));
    }
    return 0;
}

image.png

示例二:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <errno.h>

int main() {
   
    FILE* file = fopen("nonexistent.file", "r");

    if (file == NULL) {
   
        int error_code = errno;
        const char* error_msg = strerror(error_code);
        printf("Failed to open file: %s\n", error_msg);
    }
    else {
   
        // 文件打开成功,继续其他操作
        // ...
        fclose(file);
    }

    return 0;
}

以上代码尝试打开一个名为"nonexistent.file"的文件,如果文件打开失败,则获取对应的错误代码,并使用strerror函数获取错误描述字符串,最后将错误描述字符串打印出来。输出结果类似于:
image.png

需要注意的是,strerror函数返回的错误描述字符串可能是静态分配的,多次调用strerror函数可能会覆盖之前的结果。因此,建议尽量将结果保存在变量中,而不是直接在printf等函数中使用strerror函数。

3. 内存函数

内存函数的头文件一般也为string.h

3.1 memcpy

memcpy函数作用是将指定长度的内存块从源地址复制到目标地址。

也就是说,memcpy函数用来处理不重叠的内存拷贝。

函数原型:
image.png

注意事项:

  1. 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。

  2. 这个函数在遇到 '\0' 的时候并不会停下来。

  3. 如果source和destination有任何的重叠,复制的结果都是未定义的。

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>

int main() {
   
    int arr1[] = {
    1,2,3,4,5,6,7,8,9,10 };
    int arr2[20] = {
    0 };
    //将arr1中的内容,拷贝到arr2中
    memcpy(arr2, arr1, 40);
    for (int i = 0; i < 20; i++)
        printf("%d ", arr2[i]);
    return 0;
}

image.png

memcpy的模拟实现

void* my_memcpy(void* dest, const void* src, size_t num) //num单位是字节
{
   
    void* ret = dest;
    assert(src && dest);
    while (num--)
    {
   
        *(char*)dest = *(char*)src;
        dest = (char*)dest + 1;
        src = (char*)src + 1;
    }
    return ret;
}

3.2 memmove

memmove函数作用是将指定长度的内存块从源地址移动到目标地址,允许源和目标内存块重叠。

也就是说,memmove函数用来处理重叠内存拷贝。

函数原型
image.png

用法示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>

int main()
{
   
    int arr1[] = {
    1,2,3,4,5,6,7,8,9,10 };
    memmove(arr1 + 2, arr1, 20);
    for (int i = 0; i < 10; i++)
        printf("%d ", arr1[i]);
    return 0;
}

image.png

memmove的模拟实现:

void* my_memmove(void* dest, const void* src, size_t num) //num单位是字节
{
   
    void* ret = dest;
    assert(dest && src);
    if (dest < src)  //前->后拷贝
    {
   
        while (num--)
        {
   
            *(char*)dest = *(char*)src;
            dest = (char*)dest + 1;
            src = (char*)src + 1;
        }
    }
    else  //后->前拷贝
    {
   
        while (num--)
        {
   
            *((char*)dest+num) = *((char*)src+num);
        }
    }
    return ret;
}

3.3 memset

memset函数作用是将指定长度的内存块填充为指定的值。

函数原型:
image.png

用法示例:

示例一:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>


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

image.png

数组arr的所有元素都将被设置为0。

示例二:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main(){
   
    char arr[] = "hello world";
    memset(arr + 1, 'x', 4); //以字节为单位设置的
    printf("%s\n", arr);
    return 0;
}

image.png

3.4 memcmp

memcmp的作用是比较两个内存块的内容。

函数原型:
image.png

注意事项:

比较从ptr1和ptr2指针开始的num个字节
image.png

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main(){
   
    int arr1[] = {
    1,2,1,4,5,6 };
    int arr2[] = {
    1,2,257 };
    int ret = memcmp(arr1, arr2, 10);
    printf("%d\n", ret);
    return 0;
}

image.png

3. 总结

到这里,我们就介绍完了C语言中的字符函数,字符串函数和内存函数。有什么问题欢迎在评论区讨论。如果觉得文章有什么不足之处,可以在评论区留言。如果喜欢我的文章,可以点赞收藏哦!

相关文章
|
6月前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
305 23
|
5月前
|
人工智能 Java 程序员
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
98 1
一文彻底搞清楚C语言的函数
|
6月前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
264 15
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
|
6月前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
119 24
|
6月前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
304 16
|
6月前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
163 3
|
6月前
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
150 2
|
6月前
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
123 1
|
7月前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
257 10