自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何在 C 語(yǔ)言中安全地讀取用戶(hù)輸入

開(kāi)發(fā)
getline() 提供了一種更靈活的方法,可以在不破壞系統(tǒng)的情況下將用戶(hù)數(shù)據(jù)讀入程序。

在 C 語(yǔ)言中讀取字符串是一件非常危險(xiǎn)的事情。當(dāng)讀取用戶(hù)輸入時(shí),程序員可能會(huì)嘗試使用 C 標(biāo)準(zhǔn)庫(kù)中的 gets 函數(shù)。它的用法非常簡(jiǎn)單:

char *gets(char *string);

gets() 從標(biāo)準(zhǔn)輸入讀取數(shù)據(jù),然后將結(jié)果存儲(chǔ)在一個(gè)字符串變量中。它會(huì)返回一個(gè)指向字符串的指針,如果沒(méi)有讀取到內(nèi)容,返回 NULL 值。

舉一個(gè)簡(jiǎn)單的例子,我們可能會(huì)問(wèn)用戶(hù)一個(gè)問(wèn)題,然后將結(jié)果讀入字符串中:

#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;
}

輸入一個(gè)相對(duì)較短的值就可以:

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

然而,gets() 函數(shù)非常簡(jiǎn)單,它會(huì)天真地讀取數(shù)據(jù),直到它認(rèn)為用戶(hù)完成為止。但是它不會(huì)檢查字符串是否足夠容納用戶(hù)的輸入。輸入一個(gè)非常長(zhǎng)的值會(huì)導(dǎo)致 gets() 存儲(chǔ)的數(shù)據(jù)超出字符串變量長(zhǎng)度,從而導(dǎo)致覆蓋其他部分內(nèi)存。

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

最好的情況是,覆蓋部分只會(huì)破壞程序。最壞的情況是,這會(huì)引入一個(gè)嚴(yán)重的安全漏洞,惡意用戶(hù)可以通過(guò)你的程序?qū)⑷我鈹?shù)據(jù)插入計(jì)算機(jī)的內(nèi)存中。

這就是為什么在程序中使用 gets() 函數(shù)是危險(xiǎn)的。使用 gets(),你無(wú)法控制程序嘗試從用戶(hù)讀取多少數(shù)據(jù),這通常會(huì)導(dǎo)致緩沖區(qū)溢出。

安全的方法

fgets() 函數(shù)歷來(lái)是安全讀取字符串的推薦方法。此版本的 gets() 提供了一個(gè)安全檢查,通過(guò)僅讀取作為函數(shù)參數(shù)傳遞的特定數(shù)量的字符:

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

fgets() 函數(shù)會(huì)從文件指針讀取數(shù)據(jù),然后將數(shù)據(jù)存儲(chǔ)到字符串變量中,但最多只能達(dá)到 size 指定的長(zhǎng)度。我們可以更新示例程序來(lái)測(cè)試這一點(diǎn),使用 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;
}

如果編譯運(yùn)行,你可以在提示符后輸入任意長(zhǎng)的城市名稱(chēng)。但是,程序只會(huì)讀取 size = 10 數(shù)據(jù)存儲(chǔ)到字符串變量中。因?yàn)?C 語(yǔ)言在字符串末尾會(huì)添加一個(gè)空(\0)字符,這意味著 fgets() 只會(huì)讀取 9 個(gè)字符到字符串中。

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

雖然這肯定比 fgets() 讀取用戶(hù)輸入更安全,但代價(jià)是如果用戶(hù)輸入過(guò)長(zhǎng),它會(huì)“切斷”用戶(hù)輸入。

新的安全方法

更靈活的解決方案是,如果用戶(hù)輸入的數(shù)據(jù)比變量可能容納的數(shù)據(jù)多,則允許字符串讀取函數(shù)為字符串分配更多內(nèi)存。根據(jù)需要調(diào)整字符串變量大小,確保程序始終有足夠的空間來(lái)存儲(chǔ)用戶(hù)輸入。

getline() 函數(shù)正是這樣。它從輸入流讀取輸入,例如鍵盤(pán)或文件,然后將數(shù)據(jù)存儲(chǔ)在字符串變量中。但與 fgets() 和 gets() 不同,getline() 使用 realloc() 調(diào)整字符串大小,確保有足夠的內(nèi)存來(lái)存儲(chǔ)完整輸入。

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

getline() 實(shí)際上是一個(gè)名為 getdelim() 的類(lèi)似函數(shù)的裝飾器,它會(huì)讀取數(shù)據(jù)一直到特殊分隔符停止。本例中,getline() 使用換行符(\n)作為分隔符,因?yàn)楫?dāng)從鍵盤(pán)或文件讀取用戶(hù)輸入時(shí),數(shù)據(jù)行由換行符分隔。

結(jié)果證明這是一種更安全的方法讀取任意數(shù)據(jù),一次一行。要使用 getline(),首先定義一個(gè)字符串指針并將其設(shè)置為 NULL ,表示還沒(méi)有預(yù)留內(nèi)存,再定義一個(gè) size_t 類(lèi)型的“字符串大小” 的變量,并給它一個(gè)零值。當(dāng)你調(diào)用 getline() 時(shí),你需要傳入字符串和字符串大小變量的指針,以及從何處讀取數(shù)據(jù)。對(duì)于示例程序,我們可以從標(biāo)準(zhǔn)輸入中讀?。?/p>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
  char *string = NULL;
  size_t size = 0;
  ssize_t chars_read;
  // 使用 getline 讀取長(zhǎng)字符串
  puts("Enter a really long string:");
  chars_read = getline(&string, &size, stdin);
  printf("getline returned %ld\n", chars_read);
  // 檢查錯(cuò)誤
  if (chars_read < 0) {
    puts("couldn't read the input");
    free(string);
    return 1;
  }
  // 打印字符串
  printf("<%s> is length %ld\n", string, strlen(string));
  // 釋放字符串使用的內(nèi)存
  free(string);
  return 0;
}

使用 getline() 讀取數(shù)據(jù)時(shí),它將根據(jù)需要自動(dòng)為字符串變量重新分配內(nèi)存。當(dāng)函數(shù)讀取一行的所有數(shù)據(jù)時(shí),它通過(guò)指針更新字符串的大小,并返回讀取的字符數(shù),包括分隔符。

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

注意,字符串包含分隔符。對(duì)于 getline(),分隔符是換行符,這就是為什么輸出中有換行符的原因。 如果你不想在字符串值中使用分隔符,可以使用另一個(gè)函數(shù)將字符串中的分隔符更改為空字符。

通過(guò) getline(),程序員可以安全地避免 C 編程的一個(gè)常見(jiàn)陷阱:你永遠(yuǎn)無(wú)法知道用戶(hù)可能會(huì)輸入哪些數(shù)據(jù)。這就是為什么使用 gets() 不安全,而 fgets() 又太笨拙的原因。相反,getline() 提供了一種更靈活的方法,可以在不破壞系統(tǒng)的情況下將用戶(hù)數(shù)據(jù)讀入程序。

責(zé)任編輯:龐桂玉 來(lái)源: Linux中國(guó)
相關(guān)推薦

2022-12-25 10:09:44

2019-04-11 08:00:00

Windows刪除文件

2018-03-21 07:08:40

2022-10-12 15:15:56

數(shù)字孿生物聯(lián)網(wǎng)

2016-05-11 14:16:20

2014-06-06 14:33:29

BYOD移動(dòng)安全

2010-03-11 19:16:32

Python語(yǔ)言

2022-07-04 10:11:33

云安全混合云云計(jì)算

2024-03-14 11:22:54

2024-01-10 17:27:00

Python開(kāi)發(fā)

2021-09-14 09:00:00

私有云安全云架構(gòu)

2019-06-17 08:00:55

multipassbash腳本

2022-05-18 07:09:35

C#語(yǔ)言架構(gòu)

2023-10-11 17:38:43

Linux磁盤(pán)數(shù)據(jù)

2019-12-13 11:30:33

云計(jì)算IT安全

2013-12-30 10:43:15

云計(jì)算移動(dòng)數(shù)據(jù)云安全

2019-03-21 10:15:57

Windows 10關(guān)閉計(jì)算機(jī)Windows

2023-04-01 10:32:36

2024-10-10 15:08:40

2024-01-22 16:38:00

AI人工智能GenAI
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)