十分钟让你了解 Linux ABI

getline() 提供了一种更灵活的方法,可以在不破坏系统的情况下将用户数据读入程序。

在 C 语言中读取字符串是一件非常危险的事情。当读取用户输入时,程序员可能会尝试使用 C 标准库中的 gets 函数。它的用法非常简单:

char *gets(char *string);

gets() 从标准输入读取数据,然后将结果存储在一个字符串变量中。它会返回一个指向字符串的指针,如果没有读取到内容,返回 NULL 值。

举一个简单的例子,我们可能会问用户一个问题,然后将结果读入字符串中:

#include <stdio.h>
#include <string.h>
int main()
{char city[10]; // 例如 "Chicago"// 这种方法很糟糕 .. 不要使用 getsputs("Where do you live?");gets(city);printf("<%s> is length %ld\n", city, strlen(city));return 0;
}

输入一个相对较短的值就可以:

Where do you live?
Chicago
<Chicago> is length 7

然而,gets() 函数非常简单,它会天真地读取数据,直到它认为用户完成为止。但是它不会检查字符串是否足够容纳用户的输入。输入一个非常长的值会导致gets()存储的数据超出字符串变量长度,从而导致覆盖其他部分内存。

Where do you live?
Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch
<Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch> is length 58
Segmentation fault (core dumped)

最好的情况是,覆盖部分只会破坏程序。最坏的情况是,这会引入一个严重的安全漏洞,恶意用户可以通过你的程序将任意数据插入计算机的内存中。

这就是为什么在程序中使用 gets() 函数是危险的。使用 gets() ,你无法控制程序尝试从用户读取多少数据,这通常会导致缓冲区溢出。

安全的方法

fgets() 函数历来是安全读取字符串的推荐方法。此版本的 gets() 提供了一个安全检查,通过仅读取作为函数参数传递的特定数量的字符:

char *fgets(char *string, int size, FILE *stream);

fgets() 函数会从文件指针读取数据,然后将数据存储到字符串变量中,但最多只能达到 size 指定的长度。我们可以更新示例程序来测试这一点,使用 fgets() 而不是  gets() 

#include <stdio.h>
#include <string.h>
int main()
{char city[10]; // 例如 "Chicago"puts("Where do you live?");// fgets 虽好但是并不完美fgets(city, 10, stdin);printf("<%s> is length %ld\n", city, strlen(city));return 0;
}

如果编译运行,你可以在提示符后输入任意长的城市名称。但是,程序只会读取 size = 10 数据存储到字符串变量中。因为 C 语言在字符串末尾会添加一个空\0字符,这意味着 fgets() 只会读取 9 个字符到字符串中。

Where do you live?
Minneapolis
<Minneapol> is length 9

虽然这肯定比 fgets() 读取用户输入更安全,但代价是如果用户输入过长,它会“切断”用户输入。

新的安全方法

更灵活的解决方案是,如果用户输入的数据比变量可能容纳的数据多,则允许字符串读取函数为字符串分配更多内存。根据需要调整字符串变量大小,确保程序始终有足够的空间来存储用户输入。

getline() 函数正是这样。它从输入流读取输入,例如键盘或文件,然后将数据存储在字符串变量中。但与fgets() 和 gets() 不同,getline()使用 realloc() 调整字符串大小,确保有足够的内存来存储完整输入。

ssize_t getline(char **pstring, size_t *size, FILE *stream);

getline()实际上是一个名为 getline()的类似函数的装饰器,它会读取数据一直到特殊分隔符停止。本例中,getline() 使用换行符(\n)作为分隔符,因为当从键盘或文件读取用户输入时,数据行由换行符分隔。

结果证明这是一种更安全的方法读取任意数据,一次一行。要使用 getline(),首先定义一个字符串指针并将其设置为 NULL ,表示还没有预留内存,再定义一个 size_t 类型的“字符串大小” 的变量,并给它一个零值。当你调用 getline()时,你需要传入字符串和字符串大小变量的指针,以及从何处读取数据。对于示例程序,我们可以从标准输入中读取:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{char *string = NULL;size_t size = 0;ssize_t chars_read;// 使用 getline 读取长字符串puts("Enter a really long string:");chars_read = getline(&string, &size, stdin);printf("getline returned %ld\n", chars_read);// 检查错误if (chars_read < 0) {puts("couldn't read the input");free(string);return 1;}// 打印字符串printf("<%s> is length %ld\n", string, strlen(string));// 释放字符串使用的内存free(string);return 0;
}

使用getline()读取数据时,它将根据需要自动为字符串变量重新分配内存。当函数读取一行的所有数据时,它通过指针更新字符串的大小,并返回读取的字符数,包括分隔符。

Enter a really long string:
Supercalifragilisticexpialidocious
getline returned 35
<Supercalifragilisticexpialidocious
> is length 35

注意,字符串包含分隔符。对于 getline(),分隔符是换行符,这就是为什么输出中有换行符的原因。 如果你不想在字符串值中使用分隔符,可以使用另一个函数将字符串中的分隔符更改为空字符。

通过 getline(),程序员可以安全地避免 C 编程的一个常见陷阱:你永远无法知道用户可能会输入哪些数据。这就是为什么使用 gets() 不安全,而fgets() 又太笨拙的原因。相反,getline()提供了一种更灵活的方法,可以在不破坏系统的情况下将用户数据读入程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/4811.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kubernetes对象深入学习之三:对象属性

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 本文是《Kubernetes对象深入学习》系列的第三篇&#xff0c;主要内容是关于对象属性的知识点&#xff0c;关于对象属性&#xff0c;先通过一个具体…

系统架构设计师 9:软件可靠性

一、软件可靠性 软件可靠性是软件产品在规定的条件下和规定的时间区间完成规定功能的能力。 1 软件可靠性的定量描述 1. 规定时间。 使用执行时间最为准确。 执行时间&#xff1a;软件运行过程中&#xff0c;CPU执行程序指令所用的时间总和。 2. 失效概率。 用 F(t) 表示&a…

LeetCode·每日一题·1851. 包含每个查询的最小区间·优先队列(小顶堆)

题目 示例 思路 离线查询&#xff1a; 输入的结果数组queries[]是无序的。如果我们按照输入的queries[]本身的顺序逐个查看&#xff0c;时间复杂度会比较高。 于是&#xff0c;我们将queries[]数组按照数值大小&#xff0c;由小到大逐个查询&#xff0c;这种方法称之为离线查询…

Ceph 服务的运用

目录 一、资源池 pool 管理 1.创建一个 Pool 资源池 2.查看集群 Pool 信息 3.查看资源池副本的数量 4.查看 PG 和 PGP 数量 5.修改 pg_num 和 pgp_num 的数量为 128 6.修改 Pool 副本数量为 2 7.修改默认副本数为 2 8.删除 Pool 资源池 8.1修改配置文件 8.2推送 ceph…

word页码怎么从第二页开始

视频&#xff1a;https://product.pconline.com.cn/itbk/vedio/1810/11904520.html 1/15 本视频由Office2010进行演示&#xff0c;打开Word 2/15 点击“插入” 3/15 点击“页码” 4/15 选择自己需要的页码位置和格式 5/15 点击“页面布局” 6/15 点击“页面设置” 7/15 点击“…

TypeScript 1 - 小记

文章目录 关于 TypeScript 关于 TypeScript TypeScript is a superset of JavaScript that compiles to clean JavaScript output. 官网&#xff1a;https://www.typescriptlang.orggithub : https://github.com/microsoft/TypeScriptplayground : https://www.typescriptlan…

BTP Integration Suite学习笔记 - (Unit3) Developing with SAP Integration Suite

BTP Integration Suite学习笔记 - (Unit1) Developing with SAP Integration Suite BTP Integration Suite学习笔记 - (Unit2) Developing with SAP Integration Suite 带着一个问题去学&#xff1a;明明可以直接访问一个后端系统的OData服务&#xff0c;为什么还要再多绕一道C…

MACOS查找并解决端口占用

当在Mac上遇到端口占用问题时&#xff0c;可以通过以下步骤解决&#xff1a; 打开终端应用程序&#xff08;Terminal&#xff09;。使用以下命令查找占用特定端口的程序&#xff1a;sudo lsof -n -P | grep :<port>将 <port> 替换为要查找的端口号。例如&#xff…

C语言实现通讯录

今天分享一个通讯录的代码&#xff0c;代码可以正常运行&#xff0c;但是可能有一点点缺陷&#xff0c;完成的是我们的通讯录功能 contact.h #pragma once #include<string.h>#include<stdio.h> #include<assert.h> #define MAX 1000 #define NAME_MAX 20 #…

Linux5.16 Ceph集群

文章目录 计算机系统5G云计算第四章 LINUX Ceph集群一、Ceph1.存储基础1&#xff09;单机存储设备2&#xff09;单机存储的问题3&#xff09;商业存储解决方案4&#xff09;分布式存储&#xff08;软件定义的存储 SDS&#xff09;5&#xff09;分布式存储的类型 2.Ceph 简介3.C…

获得servlet相关API,获得请求头和cookie-spring23

后台能够成功打印 如何获得请求头 如何获得cookie 获取浏览器信息 把network下user Agent的值赋给他 这个值可以直接赋给Cookie 就是这个cookie 把cookie的值赋值给一边JasonId&#xff0c; 这里面的Value代表着名字,名字是cookie后面那一块&#xff1a;

spring-boot-2.2.13.RELEASE 升级 2.6.6 记录

一、版本升级 spring-boot-2.2.13.RELEASE 升级 2.6.6 <properties>...<spring.boot.version>2.6.6</spring.boot.version><spring-cloud.version>2021.0.1</spring-cloud.version><spring-cloud-alibaba.version>2021.0.1.0</spring-…

librdkafka的rdk:broker-1线程cpu百分百问题分析

问题调用栈&#xff1a; (gdb) bt #0 0x000000000068307c in rd_kafka_q_pop_serve (rkq0x1ff31a0, timeout_ms<optimized out>, versionversionentry0, cb_typecb_typeentryRD_KAFKA_Q_CB_RETURN, callbackcallbackentry0x0, opaqueopaqueentry0x0) at rdkafka_queue.…

nginx推流环境搭建

目录 1、创建安装文件夹2、安装编译 nginx 所需要的库3、下载 nginx-1.21.6.tar.gz下载 nginx-rtmp-module4、解压解压nginx文件解压rtmp模块5、编译6、安装7、启动nginx,检测nginx是否能成功运行8、配置nginx使用RTMP9、重启nginx服务器1、创建安装文件夹 cd ~ mkdir nginx …

React Hooks

React Hooks basic hooks useStateuseEffectuseContext useState useState接收一个参数&#xff0c;返回的是一个数组&#xff0c;参数表示初始值&#xff0c;数组的第1项就是定义的变量&#xff0c;第2项就是改变变量的方法。 参数可以是基本数据类型&#xff0c;如string…

Comparator.comparing()实现中文排序及空指针处理

一、 Comparator.comparing()的用法请详见以下上一篇文章的汇总介绍。 Comparator用法_乞力马扎罗の黎明的博客-CSDN博客 二、应用示例&#xff1a; 1、中文排序、空值处理 Collator instance Collator.getInstance(Locale.CHINA); checkItemVoList.stream().sorted(Compar…

每日科技分享-POE新增文件和链接发送功能

POE推出新功能 注意POE需要魔法上午才能进去。 实测 实测可以发送论文给chatgpt&#xff0c;然后和AI进行共享的对话。 POE网站链接&#xff1a; 也可以发送链接&#xff0c;实测了一下&#xff0c;似乎有时候并不准确&#xff0c;我发送了关于分层强化的文章&#xff0c;但是…

<数据结构>NO11.归并排序|递归|非递归|优化

文章目录 归并排序递归写法非递归写法修正方案1.归并一段拷贝一段修正方案2.修正区间 算法优化算法分析 归并排序的应用外排序和内排序 归并排序 递归写法 思路: 如果给出两个有序数组&#xff0c;我们很容易可以将它们合并为一个有序数组。因此当给出一个无序数组时&#xf…

http和https的区别(面试题)

概念 Http&#xff1a;HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写。HTTP 协议和 TCP/IP 协议族内的其他众多的协议相同&#xff0c; 用于客户端和服务器之间的通信。从WWW服务器传输超文本到本地浏览器的传输协议&#xff0c;它可以…

一个月学通Python(二十):Python制作报表(Web开发)

专栏介绍 结合自身经验和内部资料总结的Python教程,每天3-5章,最短1个月就能全方位的完成Python的学习并进行实战开发,学完了定能成为大佬!加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础)》 文章目录 专栏介绍制作报表导出Excel报表导出PDF报表生成前端…