2025-02-26 学习记录--C/C++-C 库函数gets()、fgets()、strcspn()、puts()

合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。💪🏻

一、C 库函数 - gets() 🍭

C 标准库 - <stdio.h>
在这里插入图片描述

下面是 gets() 函数的声明:👇🏻
char *gets(char *str)

  • gets() 函数 从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
    • 如果成功,该函数返回 str
    • 如果发生错误或者到达文件末尾时还未读取任何字符,则返回 NULL
  • str – 这是指向一个字符数组的指针,该数组存储了 C 字符串。

在这里插入图片描述

#include <stdio.h>  // 引入标准输入输出库,用于使用 printf 和 gets 等函数

int main() // 主函数,程序入口
{
    char str[50]; // 定义一个字符数组 str,用于存储用户输入的字符串,最大长度为 49 个字符(最后一个字符是字符串结束符 '\0')

    printf("请输入一个字符串:"); // 提示用户输入一个字符串
    gets(str); // 使用 gets 函数从标准输入读取用户输入的字符串,并存储到字符数组 str 中

    printf("您输入的字符串是:%s", str); // 输出用户输入的字符串,%s 是格式化字符串的占位符

    return 0; // 返回 0,表示程序正常结束
}

在这里插入图片描述

二、C 中使用 gets() 提示 warning: this program uses gets(), which is unsafe.

在这里插入图片描述

gets() 不安全是因为你给了他一个缓冲区,但是你却没有告诉它这个缓冲区到底有多大,也不知道输入的内容到底有多大,输入的内容可能超出缓冲区的结尾,引起你的程序崩溃。

解决方法可以使用 fgets() 替代:👇🏻

// 使用 gets()
char buffer[4096]; // 定义一个字符数组 buffer,用于存储用户输入的字符串,大小为 4096 个字符
gets(buffer);      // 使用 gets 函数从标准输入读取用户输入的字符串,并存储到 buffer 中

// 使用 fgets() 替换 gets()
char buffer[4096]; // 定义一个字符数组 buffer,用于存储用户输入的字符串,大小为 4096 个字符
fgets(buffer, (sizeof buffer / sizeof buffer[0]), stdin); // 使用 fgets 函数从标准输入读取用户输入的字符串,并存储到 buffer 中
// fgets 的第二个参数是缓冲区的大小,这里通过 (sizeof buffer / sizeof buffer[0]) 计算数组的实际大小。
// (sizeof buffer / sizeof buffer[0]) 是一种通用的计算数组大小的方式,适用于任何类型的数组。
// stdin 表示从标准输入(通常是键盘)读取数据。
  • fgets 会限制输入的字符数量,确保不会超过缓冲区的大小,从而避免缓冲区溢出。
  • fgets 会读取一行内容(直到遇到换行符或文件末尾),并将换行符(如果有)也存储到字符串中
  • 【注意】🌹 如果不需要换行符,可以手动去除: 👇🏻
    • buffer[strcspn(buffer, “\n”)] = ‘\0’; // 去除换行符注意💥:此处的\n用的是双引号哦】

以下是使用 fgets 的完整示例代码,包括去除换行符: 👇🏻

#include <stdio.h>  // 引入标准输入输出库,用于使用 printf 和 fgets 等函数
#include <string.h> // 引入字符串处理库,用于使用 strcspn 函数【strcspn 函数用于查找字符串中第一个匹配指定字符集中任意字符的位置】

int main() // 主函数,程序入口
{
    char buffer[4096]; // 定义一个字符数组 buffer,用于存储用户输入的字符串,大小为 4096 个字符

    printf("请输入一个字符串:"); // 提示用户输入一个字符串
    fgets(buffer, (sizeof buffer / sizeof buffer[0]), stdin); // 使用 fgets 函数从标准输入读取用户输入的字符串,并存储到 buffer 中
    // 参数说明:
    // - buffer:目标字符数组,用于存储输入的字符串。
    // - (sizeof buffer / sizeof buffer[0]):计算 buffer 的大小,确保不会超出缓冲区范围。
    // - stdin:表示从标准输入(通常是键盘)读取数据。

    // 去除 fgets 可能读取的换行符
    buffer[strcspn(buffer, "\n")] = '\0'; // 使用 strcspn 查找换行符的位置,并将其替换为字符串结束符 '\0'
    // 参数说明:
    // - buffer:要查找的字符串。
    // - "\n":要查找的字符集(这里只有换行符)。
    // - strcspn 返回第一个匹配字符的索引,如果没有匹配字符,则返回字符串的长度。

    printf("您输入的字符串是:%s\n", buffer); // 输出用户输入的字符串
    // %s 是格式化字符串的占位符,表示输出一个字符串。

    return 0; // 返回 0,表示程序正常结束
}

在这里插入图片描述

总结: 🐯

  • gets 的问题:不安全,容易导致缓冲区溢出,不推荐使用。

  • fgets 的优点:安全,可以限制输入长度,避免缓冲区溢出。

  • 改进建议:在实际开发中,始终使用 fgets 替代 gets,并根据需要处理换行符。

三、C 库函数 - fgets() 🍭

C 标准库 - <stdio.h>

在这里插入图片描述

下面是 fgets() 函数的声明:👇🏻
char *fgets(char *str, int n, FILE *stream)

  • fgets() 函数 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
    • 如果成功,该函数返回相同的 str 参数。
    • 如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。
    • 如果发生错误,返回一个空指针。
  • str – 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
  • n – 这是要读取的最大字符数(包括最后的空字符)。通常是使用str 传递的数组长度
  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。

在这里插入图片描述

#include <stdio.h>  // 引入标准输入输出库,用于使用文件操作函数(如 fopen、fgets、puts 等)

int main() // 主函数,程序入口
{
   FILE *fp;       // 定义一个文件指针 fp,用于操作文件
   char str[60];   // 定义一个字符数组 str,用于存储从文件中读取的内容,最大长度为 59 个字符(最后一个字符是字符串结束符 '\0')

   /* 打开用于读取的文件 */
   fp = fopen("file.txt", "r"); // 以只读模式打开名为 "file.txt" 的文件,并将文件指针赋值给 fp
   if (fp == NULL) { // 检查文件是否成功打开
      perror("打开文件时发生错误"); // 如果文件打开失败,使用 perror 输出错误信息
      return -1; // 返回 -1,表示程序异常结束
   }

   /* 从文件中读取内容 */
   if (fgets(str, 60, fp) != NULL) { // 使用 fgets 从文件中读取一行内容(最多 59 个字符),并存储到 str 中
      /* 向标准输出 stdout 写入内容 */
      puts(str); // 使用 puts 将读取的内容输出到标准输出(通常是屏幕)
   }

   fclose(fp); // 关闭文件,释放文件指针

   return 0; // 返回 0,表示程序正常结束
}

在这里插入图片描述

四、C 库函数 - strcspn() 🍭

C 标准库 - <string.h>
在这里插入图片描述

下面是 strcspn() 函数的声明:👇🏻
size_t strcspn(const char *str1, const char *str2)

  • strcspn() 函数 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符。
    • 该函数返回 str1 开头连续都不含字符串 str2 中字符的字符数。
  • str1 – 要被检索的 C 字符串。
  • str2 – 该字符串包含了要在 str1 中进行匹配的字符列表。

在这里插入图片描述

#include <stdio.h>  // 引入标准输入输出库,用于使用 printf 等函数
#include <string.h> // 引入字符串处理库,用于使用 strcspn 等函数

int main() // 主函数,程序入口
{
    int len; // 定义一个整型变量 len,用于存储 strcspn 函数的返回值
    const char str1[] = "ABCDEF4960910"; // 定义一个常量字符数组 str1,初始化为 "ABCDEF4960910"
    const char str2[] = "013"; // 定义一个常量字符数组 str2,初始化为 "013"
    
	// 使用 strcspn 函数计算 str1 开头连续都不含字符串 str2 中字符的字符数:ABCDEF496 共9个
    len = strcspn(str1, str2); 

    // 输出结果:第一个匹配的字符 前 有 len 个,所以 第一个匹配的字符 位置 是 len + 1
    printf("第一个匹配的字符是在 %d\n", len + 1);

    return 0; // 返回 0,表示程序正常结束
}

在这里插入图片描述

(一)、strcspn() 的名字来源 🌺

strcspn()C 标准库中的一个字符串处理函数,它的名字来源于 “string complement span”。

strcspn() 的名字来源于其功能:

  • str:字符串操作。
  • c:补集(complement),表示与指定字符集相反。
  • spn:计算字符串的区间长度(span)。

这个名字虽然看起来有些复杂,但它准确地反映了函数的行为:计算字符串中 不包含指定字符集 的初始段的长度。

(二)、与 strspn() 的对比 🌺

  • C 标准库中还有一个类似的函数 strspn(),它的功能是计算字符串中 完全由指定字符集组成 的初始段的长度。

    • strspn()计算字符串中 属于指定字符集 的初始段的长度
    • strcspn()计算字符串中 不属于指定字符集 的初始段的长度
  • 两者的命名逻辑一致:👇🏻

    • strspn()str + spn(字符串的区间长度)。
    • strcspn()str + c(补集) + spn(字符串的区间长度)。

在这里插入图片描述

#include <stdio.h>  // 包含标准输入输出库,用于使用printf函数
#include <string.h> // 包含字符串处理库,用于使用strcspn函数

int main() {        // 主函数,程序的入口
    const char *str = "hello123world"; // 定义一个字符串str,内容为"hello123world"
    const char *reject = "0123456789"; // 定义一个字符串reject,内容为"0123456789",表示需要匹配的字符集(数字)

    size_t len = strcspn(str, reject); // 调用strcspn函数,计算字符串str中不包含reject字符集的初始段长度
                                      // strcspn函数会从str的开头开始扫描,直到遇到第一个属于reject字符集的字符为止
                                      // 返回的是从str开头到第一个匹配字符之前的字符数量
                                      // 结果存储在len变量中

    printf("Length of initial segment without digits: %zu\n", len); // 输出结果
                                                                  // %zu是size_t类型的格式化输出占位符
                                                                  // 输出内容是字符串str中不包含数字的初始段长度

    return 0; // 返回0,表示程序正常结束
}

在这里插入图片描述

字符串 “hello123world” 中,前 5 个字符 “hello” 不属于字符集 “0123456789”,因此 strcspn() 返回 5

关键点 🪁
  • strcspn() 函数的作用是计算字符串中 不包含指定字符集 的初始段长度。
  • 在这个例子中,str 的前 5 个字符 “hello” 不包含任何数字(“0123456789”),因此返回值为 5
  • 如果 str 的开头就是数字字符(“0123456789”),则返回值为 0

五、C 库函数 - puts() 🍭

C 标准库 - <stdio.h>
在这里插入图片描述

下面是 puts() 函数的声明:👇🏻
int puts(const char *str)

  • puts() 函数 把一个字符串写入到标准输出 stdout,直到空字符,但不包括空字符换行符会被追加到输出中。
    • 如果成功,该函数返回一个非负值为字符串长度(包括末尾的 \0);
    • 如果发生错误则返回 EOF
  • str – 这是要被写入的 C 字符串。

在这里插入图片描述

#include <stdio.h>  // 引入标准输入输出库,用于使用 puts 等函数
#include <string.h> // 引入字符串处理库,用于使用 strncpy 等函数

int main() // 主函数,程序入口
{
    char str1[15]; // 定义一个字符数组 str1,用于存储字符串,大小为 15 个字符
    char str2[15]; // 定义一个字符数组 str2,用于存储字符串,大小为 15 个字符

    // 使用 strncpy 替代 strcpy,指定最大复制长度
    strncpy(str1, "FIGHTING1", sizeof(str1) - 1); // 将字符串 "FIGHTING1" 复制到 str1 中,最多复制 sizeof(str1) - 1 个字符
    strncpy(str2, "FIGHTING2", sizeof(str2) - 1); // 将字符串 "FIGHTING2" 复制到 str2 中,最多复制 sizeof(str2) - 1 个字符

    // 手动添加字符串结束符
    str1[sizeof(str1) - 1] = '\0'; // 确保 str1 的最后一个字符是字符串结束符 '\0'
    str2[sizeof(str2) - 1] = '\0'; // 确保 str2 的最后一个字符是字符串结束符 '\0'

    puts(str1); // 使用 puts 函数输出 str1 的内容(自动添加换行符)
    puts(str2); // 使用 puts 函数输出 str2 的内容(自动添加换行符)

    return 0; // 返回 0,表示程序正常结束
}

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小呀小萝卜儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值