十分钟让你了解 Linux ABI

news2024/12/26 20:49:40

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

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

char *gets(char *string);

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

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

#include <stdio.h>
#include <string.h>
int main()
{
  char city[10]; // 例如 "Chicago"
  // 这种方法很糟糕 .. 不要使用 gets
  puts("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.coloradmin.cn/o/772202.html

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

相关文章

socket编程代码示例

1. TCP server client模拟聊天对话框 server.c /* server.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include &l…

jmeter使用PerfMon插件监测服务器资源时 连接超时

异常提示&#xff1a; ERROR: java.net.ConnectException: Connection timed out: connect 解决方案&#xff1a; 一种情况下是端口未启用&#xff1b; 另一种情况更新端口号&#xff0c;将默认端口进行修改 4444 修改为其他未使用的端口号&#xff08;例如&#xff1a;4445 &…

vue基础-axios详解

1.1 背景 Axios 是一个基于 promise 的 HTTP 库&#xff0c;可以用在浏览器和 node.js 中, 也是 vue 官方推荐使用的 http 库&#xff1b;封装axios&#xff0c;一方面为了以后维护方便&#xff0c;另一方面也可以对请求进行自定义处理。 1.2 vue请求模块选择 2 应用 2.1 安…

第八十八回:创建一个调色板

文章目录 概念介绍实现方法整体思路具体步骤 示例代码 我们在上一章回中介绍了打印日志相关的内容&#xff0c;本章回中将介绍 如何创建一个调色板.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在本章回中介绍的调色板是一个具有各种颜色的窗口&#xff0c…

大口径均匀性大于98%积分球均匀光源

大口径宽视场光学成像遥感器的探测元件采用阵列探测器或多片阵列探测器拼接而成,由于阵列探测器像元间辐射响应差异和光学系统的非理想性&#xff0c;影响了光学成像遥感器的成像质量&#xff0c;进而影响测量的准确性&#xff0c;因此在有效应用前必须对大口径宽视场光学成像遥…

【hadoop】hadoop的体系架构

hadoop的体系架构 HDFS的体系架构NameNodeedits文件&#xff08;客户端的操作日志&#xff09;fsimage文件&#xff08;元信息文件&#xff09; DataNodeSecondary NameNode Yarn的体系架构HBase主从架构的单点故障的问题 HDFS的体系架构 NameNode NameNode&#xff1a;主节点…

idea-实现热部署

idea-实现热部署 今天在进行idea 开发时突然发现热部署失败了&#xff0c;每次修改内容都要去restart server一次 这样比较麻烦&#xff0c;故而总结一下idea实现热部署的方法&#xff1a; 步骤一&#xff1a; 选择edit configuration 然后跳出server 的配置&#xff0c;方框…

Go语言之并发编程练习

GO协程初识 package mainimport ("fmt""sync""time" )func read() {defer wg.Done()fmt.Println("read start")time.Sleep(time.Second * 3)fmt.Println("read end") }func listenMusci() {defer wg.Done()fmt.Println(&qu…

ENSP实验三:搭建VPN(GRE,未配置安全策略)

目录 1、基础配置&#xff1a;IP地址&#xff0b;防火墙安全区域&#xff1b; 2、使ISP&#xff08;运营商&#xff09;网络的路由可达-OSPF&#xff1b; 3、建立VPN隧道&#xff08;两个防火墙之间&#xff09;&#xff1b; 4、引流 1、基础配置&#xff1a;IP地址&#xf…

c语言小项目——通讯录中阶(动态内存版)

通讯录初阶&#xff1a;点这里 通讯录高阶&#xff1a;点这里 动态内存版改进之处结构体初始化通讯录添加联系人销毁通讯录 完整代码contact.hcontact.ctest.c 动态内存版改进之处 结构体 contact.c 初始化通讯录 contact.h contact.c 添加联系人 contact.c 销毁通讯录 te…

Linux挂载iso镜像文件为yum源

场景 工作中&#xff0c;经常需要在公司的内网环境节点安装一些第三方的服务&#xff08;例如HaProxy&#xff09;&#xff0c;一般他们都依赖一些基础工具&#xff0c;或者基础库&#xff0c;例如 openssl 、openssl-devel、gcc 等等。如果能联网&#xff0c;直接通过 yum 命…

干洗店预约下单小程序,洗衣店洗鞋店收银软件会员取衣管理

干洗店预约下单小程序&#xff0c;洗衣店洗鞋店收银软件会员取衣管理 干洗店洗鞋店同城预约上门洗衣系统小程序洗护软件APP码上洗鞋 主要功能&#xff1a; 1、专业的收衣收鞋功能。接收客户的预洗衣物&#xff0c;根据要求和提示输入衣物详细信息&#xff0c;包括衣服的颜色&a…

selenium-多窗口和frame处理

1.切换窗口 适用场景&#xff1a;点击按钮后&#xff0c;重新打开一个窗口&#xff0c;想要在新的窗口定位操作&#xff0c;就需要切换窗口 原理&#xff1a;获取窗口的唯一标识就是句柄&#xff0c;获取到句柄&#xff0c;就可以切换到对应的窗口了 处理方法&#xff1a; …

M7二极管-ASEMI迷你贴片整流二极管M7二极管

编辑&#xff1a;ll M7二极管-ASEMI迷你贴片整流二极管M7二极管 型号&#xff1a;M7二极管 品牌&#xff1a;ASEMI 芯片个数&#xff1a;1 芯片尺寸&#xff1a;46MIL 封装&#xff1a;SMAF 恢复时间&#xff1a;ns 工作温度&#xff1a;-50C~150C 浪涌电流&#xff1…

python实现拼多多商品详情接口API

最近工作需要用到拼多多的一些接口&#xff0c;官方竟然没有提供&#xff0c;python的sdk&#xff0c;于是就自己简单的写了一个商品SKU接口的api。 1、代码 #!/usr/bin/python3# -*- coding: utf-8 -*-# Time : 2020/3/29 0021 下午 19:40# Author : xiaozhi&#xff01;…

docker基础1——架构组成、安装配置

文章目录 一、发展起源1.1 传统虚拟化与容器虚拟化1.2 docker底层核心技术1.2.1 命名空间1.2.2 控制组 1.3 docker工作方式1.4 docker容器编排1.5 docker优劣势1.6 docker架构组成 二、yum安装docker三、配置docker加速器 一、发展起源 背景了解&#xff1a; 容器是内核里的一项…

重磅升级 | 睿士主机威胁溯源系统全新升级,助力用户2023网络攻防演练

攻防演练至今已走过7个年头&#xff0c;逐渐成为网络安全防御体系中至关重要的一环。随着攻防演练对抗水平不断升级&#xff0c;攻击手段愈发隐蔽&#xff0c;攻击自动化程度逐步提高&#xff0c;技术储备也越来越有针对性&#xff0c;从广撒网到精准打击&#xff0c;这些都给蓝…

解决find: ‘/run/user/1000/gvfs’: 权限不够

问题描述 在用find查找对应的文件时&#xff0c;突然报错这个问题 解决办法 其实这个目录是空的&#xff0c;所以删除就好了执行下列操作&#xff1a; umount /run/user/1000/gvfs rm -rf /run/user/1000/gvfs 之后的查找中就没有了报错提示。

Spring AOP的介绍与实现

文章目录 Spring AOP1. Spring AOP概念2. Spring AOP的作用3.AOP的组成4. Spring AOP的实现4.1 添加Spring AOP依赖4.2 定义切面&#xff08;创建切面类&#xff09;4.3 定义切点&#xff08;配置拦截规则&#xff09;4.3.1 切点表达式语法 4.4 定义通知的实现 5. Spring AOP实…

【Java】Mybatis使用Collection属性

前言 这篇文章实现一下不使用left join等连接关键字来实现Mybatis的联表查询功能。包括json类型数据映射到Java实体类中。 库表 父表db1_json 子表db1_json_attach&#xff0c;子表parent_id对应副本的id。 实体类 新建Db1JsonDTO数据传递对象实体。 Data public class Db…