2.4 輸入和顯示

本節必須掌握的知識點:

示例五源代碼

代碼分析

匯編解析

2.4.1?示例五

格式化輸入函數scanf

scanf函數可以從鍵盤讀取輸入的信息。scanf函數同樣可以像printf函數那樣,通過轉換說明“%d”來限制函數只能讀取十進制數。scanf函數的參數為可變參數,參數的個數由格式化說明符的個數決定,可以同時接受鍵盤輸入多個值。scanf函數以回車符、制表符或者空格表示輸入結束。

示例代碼五

/*

顯示并確認輸入的整數值

*/

#include?<stdio.h>

#include?<stdlib.h>

int?main(void)

{

int?num;

printf("請輸入一個整數:");

scanf_s("%d", &num);//注意,scanf函數讀取變量時,變量名前必須加&

printf("您輸入的整數是%d。\n",?num);

system("pause");

return?0;

}

●輸出結果:

請輸入一個整數:12

您輸入的整數是12。

提示

1.?scanf函數讀取變量時,變量名前必須加&地址符,表示接收鍵盤輸入的值存儲到該地址處。

2.使用scanf函數,高版本的VS會顯示錯誤提示信息如下:

error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

1>c:\program files (x86)\windows

kits\10\include\10.0.18362.0\ucrt\stdio.h(1275): note:?參見“scanf”的聲明

解決方法:

方法1:在程序最前面加宏定義:

#define_CRT_SECURE_NO_DEPRECATE

方法2:在程序最前面加:

#pragma warning(disable:4996)

方法3:把scanf改為scanf_s;推薦使用的方法。

方法4:無需在程序最前面加宏定義,只需在新建項目時取消勾選“SDL檢查”即可。

方法5:若項目已建立好,在項目屬性里關閉SDL。

方法6:在工程項目設置一下就行:將報錯的宏定義放到:“項目屬性”>“C/C++”?>?“預處理器”>?“預處理器定義”。

方法7:在“項目屬性”>“C/C++?”>“命令行”中添加:/D _CRT_SECURE_NO_WARNINGS就可以了。

3.scanf_s()?函數并不是C標準庫函數,而是VS提供的函數,其功能雖然與scanf()?相同,但卻比?scanf()?安全,因為?scanf_s()?是針對“?scanf()在讀取字符串時不檢查邊界,可能會造成內存泄露”這個問題設計的。

scanf_s()用于讀取字符串時,必須提供一個數字以表明最多讀取多少位字符,以防止溢出。例如,scanf_s("%s", buf, 5);

當scanf_s()讀取非字符串時,無需考慮內存溢出問題。例如,scanf_s("%d", &num);

2.4.2?代碼分析

int?num;

第一步:聲明一個int類型的變量num,未初始化。

printf("請輸入一個整數:");

第二步:調用輸出函數printf打印提示信息,提示用戶輸入一個整數值,這是非常人性化的設計。

scanf_s("%d", &num);//注意,scanf函數讀取變量時,變量名前必須加&

第三步:調用scanf_s函數,接收鍵盤輸入,格式化說明符’%d’表示接收輸入一個32位整數值,并且存儲到num偏移地址處。&no表示取變量num的地址。

printf("您輸入的整數是%d。\n",?num);

第四步:再次調用printf函數輸出結果。

2.4.3?匯編解析

匯編代碼

;FileName:2-4-1.asm

;例5:示例代碼4-1顯示并確認輸入的整數值

;by:bcdaren

;2023.08.27

;==================

;C標準庫頭文件和導入庫

include vcIO.inc

.data?;全局區

num sdword ?;全局變量

.const??;常量區

szMsg1 db "請輸入一個整數:",0?????

szMsg2 db "%d",0

szMsg3 db "您輸入的整數是%d。",0dh,0ah,0

.code?;代碼區

start:

;提示信息

push offset szMsg1?;格式化常量字符串偏移地址入棧

call printf?;調用printf函數輸出結果

;接收鍵盤輸入

lea esi,num?;取變量num地址

push esi

push offset szMsg2

call scanf

;輸出結果

invoke printf,offset szMsg3,num

;?????

invoke _getch;等待輸入單個字符

ret;結束返回

end start

上述匯編代碼中引用了C標準庫函數scanf,在vcIO.inc頭文件中已聲明。因為沒有使用VS編譯器,因此這里不可以使用scanf_s函數。調用scanf函數前,先使用lea指令取變量num的地址,然后入棧,接著將格式化常量字符串szMsg2入棧,最后call指令調用scanf函數,接收鍵盤輸入一個整數值,并存儲到no偏移地址處。

反匯編代碼

int num;

printf("請輸入一個整數:");

00E61952?push offset string

"\xc7\xeb\xca\xe4\xc8\xeb\xd2\xbb\xb8\xf6\xd5\xfb\xca\xfd\xa3\xba" (0E67B30h)?

00E61957?call?_printf (0E6104Bh)?

00E6195C?add?esp,4?

scanf_s("%d", &no);//注意,scanf函數讀取變量時,變量名前必須加&

00E6195F?lea eax,[num]?

00E61962?push eax?

00E61963?push offset string "%d" (0E67B44h)?

00E61968?call _scanf_s (0E61154h)?

00E6196D?add esp,8?

printf("您輸入的整數是%d。\n", num);

00E61970?mov eax,dword ptr [num]?

00E61973?push eax?

00E61974?push????????offset string

"\xc4\xfa\xca\xe4\xc8\xeb\xb5\xc4\xd5\xfb\xca\xfd\xca\xc7%d\xa1\xa3\n" (0E67B48h)?

00E61979?call _printf (0E6104Bh)?

00E6197E?add esp,8?

2-4-1.c的反匯編代碼中,編譯器調用的是scanf_s函數,先用lea指令取變量no地址,然后兩個push參數入棧,與匯編代碼一樣。

此外,反匯編代碼中,調用printf函數時的第一個參數格式化常量字符串對應的是中文機內碼,可以參閱《X86匯編語言基礎教程》第四章常用編碼規則講述的漢字編碼規則。

實驗十七:驗證整數常量值作為指令操作數存儲在代碼段中

第一步:打開DtDebug調試器。

第二步:將匯編代碼生成的2-3-1.exe程序拖入調試器。

第三步:按Ctrl+F9,進入程序的入口地址,即程序代碼段的起始位置。

第四步:找到整數常量值的賦值語句,如圖2-9所示。

????????????????圖2-9?整數常量值

結論

【注意】紅色方框內的語句,右邊為常量值的賦值語句MOV DWORD PTR DS:[1E3010],2

意思為將整數常量值2存入數據段的偏移地址0x001E3010地址處。我們再看左側匯編指令對應的硬編碼,05C7為MOV DWORD PTR指令機器碼,001E3010為數據段內的偏移地址,00000002為整數常量值,作為該條機器指令的一部分存儲在代碼段中。注意X86 CPU字節為單位的小端存儲方式,低地址為低字節數據,高地址為高字節數據。

實驗十八:乘法運算

VS新建項目2-4-2.c:

/*

讀取一個整數并顯示其3倍的值

*/

#include?<stdio.h>

#include?<stdlib.h>

int?main(void)

{

int?num;

printf("請輸入一個整數:");

scanf_s("%d", &num);//讀取整數值

printf("它的3倍的值是%d\n", 3 *?num);

system("pause");

return?0;

}

●輸出結果:

請輸入一個整數:11

它的3倍的值是33

請按任意鍵繼續. . .

練習

1、請讀者將2-4-2.c翻譯成匯編語言實現。

2、請讀者分析2-4-2.c的反匯編代碼。

實驗十九:輸出函數puts

VS新建項目2-4-3.c:

/*

顯示讀取到的兩個整數的和

*/

#include?<stdio.h>

#include?<stdlib.h>

int?main(void)

{

int?n1,?n2;

//puts函數功能:輸出字符串并換行,等同于printf("...\n")

puts("請輸入兩個整數。");

printf("整數1:");scanf_s("%d", &n1);

printf("整數2:");scanf_s("%d", &n2);

printf("它們的和是%d。\n",?n1?+?n2);??//顯示和

system("pause");

return?0;

}

●輸出結果:

請輸入兩個整數。

整數1:1

整數2:2

它們的和是3。

請按任意鍵繼續. . .

【注意】puts函數只有一個參數,僅用于輸出零結尾字符串。

練習

1、請讀者將2-4-3.c翻譯成匯編語言實現。

2、請讀者分析2-4-3.c的反匯編代碼。

實驗二十:顯示讀取到的兩個整數的和

VS新建項目2-4-4.c:

/*

顯示讀取到的兩個整數的和

*/

#include?<stdio.h>

#include?<stdlib.h>

int?main(void)

{

int?n1,?n2;

int?sum;//和

puts("請輸入兩個整數:");

printf("整數1:");scanf_s("%d", &n1);

printf("整數2:");scanf_s("%d", &n2);

sum?=?n1?+?n2;

printf("它們的和是%d。\n",?sum);//顯示和;

system("pause");

return?0;

}

●輸出結果:

請輸入兩個整數:

整數1:1

整數2:2

它們的和是3。

請按任意鍵繼續. . .

【注意】實驗十九和實驗二十的區別,實驗二十定義了一個int類型變量sum,用于保存變量n1+n2的和。當我們需要多次使用變量和的情況下,應該定義一個sum變量保存變量和。如果只打印一次,則不需要定義變量sum,可以根據實際需要,靈活設計。

總結

1.計算機的內存是一個以字節為單位的線性存儲空間,每個字節都有一個獨立的地址編號。計算機程序通過內存地址讀寫該地址相應的存儲空間。

2.源程序中的變量和常量都是存儲在內存中的數據。全局變量存儲在全局區,局部變量存儲在棧區,字符串常量存儲在常量區。整數常量或字符常量作為機器指令的操作數存儲在代碼區,可以直接引用,無需地址編號。

3.變量名就是用符號表示的地址編號。全局變量是相對于全局區內的偏移地址,局部變量是相對于棧區的偏移地址,常量字符串是相對于常量區的偏移地址。

4.對變量的引用:

在匯編語言中,使用mov指令引用變量時,表示從該變量偏移地址處取該地址存儲的值。例如,mov eax,[a](與mov eax,a等價)表示將變量a地址處的值送入eax寄存器。如果取變量的地址,則使用lea指令。例如,lea esi,a表示將變量a的地址送入esi寄存器。

在C語言中,沒有辦法通過指令來區分取變量地址還是取值,因此變量名表示該地址處存儲的值,變量名前添加地址符&表示變量地址,地址前添加*號(解引用運算符)表示取該地址處的值。后面我們將要學習的指針就是地址的意思,從匯編的角度理解指針是一件再簡單不過的事情了。

例如:

a = 1;該語句執行后,變量名a表示變量的值為1。而這條語句的真實含義是指將整數常量值1存儲到變量a偏移地址處,即&a地址處。

*(&a) = 1;這條語句的含義是將整數常量值1送入變量a地址處,等價于語句a = 1;這里的*號表示解引用,即表示變量a地址處的值等于1。

5.常量字符串:

在匯編代碼中,常量字符串需要使用一個符號表示常量字符串在常量區內的偏移地址。例如示例五匯編代碼中的szMsg1,使用操作符offset取szMsg1的偏移地址:offset szMsg1。

取出常量字符串的偏移地址就可以對字符串進行讀操作了。

如果字符串存儲到全局區或者棧區,那么該字符串就變成了變量了,一個以ASCII字符組成的數組,不僅可以對字符串進行讀操作,還可以對字符串進行寫操作。我們將在第十一章字符和字符串章節中詳細講解。

在C語言中,常量字符串存儲在常量區,采用直接引用的方式對常量字符串進行操作。例如puts("請輸入兩個整數:");puts函數的唯一參數是一個常量字符串,可以直接對其引用。但是記住,對常量字符串的引用其實是直接引用該常量字符串的在常量區內的偏移地址。

何以證明?請看puts語句對應的反匯編語句:

push offset string "\xc7\xeb\xca\xe4\xc8\xeb\xc1\xbd\xb8\xf6\xd5\xfb\xca\xfd\xa3\xba" (0F27B30h)

offset string就表示該常量字符串的偏移地址(0F27B30h)。

6.const是C語言編譯器的修飾詞,用于修飾變量。例如const int j;表示在變量j的存續期間,不可以修改變量j的值,把變量j當作是常量看待,其實并沒有改變變量j的真實屬性,即變量j并不會因此而變成一個常量,不會改變變量j的存儲區。編譯器在編譯源程序時會檢查const修飾過的變量的值是否被修改,如果被修改,則會提示錯誤信息error C2166:?左值指定?const?對象。const修飾詞的作用是幫助程序員避免不必要的錯誤。程序員在無意中修改了本來不該被修改的變量的值,特別是對全局變量的無意修改。而在匯編語言中并沒有類似const這樣的修飾詞,因此匯編語言對程序員的要求更高。

練習

1、?編寫一段程序,從鍵盤讀取兩個整數,計算并顯示兩個整數的乘積。

2、?編寫一段程序,從鍵盤讀取三個整數,計算并顯示三個整數的和。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/11113.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/11113.shtml
英文地址,請注明出處:http://en.pswp.cn/web/11113.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【算法訓練 day25 修剪二叉搜索樹、將有序數組轉化為二叉搜索樹、把二叉樹搜索轉化為累加樹】

目錄 一、修剪二叉搜索樹-LeetCode 669思路實現代碼個人代碼視頻鏈接代碼 個人問題 二、將有序數組轉化為二叉搜索樹-LeetCode 108思路實現代碼個人問題 三.把二叉樹搜索轉化為累加樹-LeeCode 538思路實現代碼個人問題 一、修剪二叉搜索樹-LeetCode 669 Leecode鏈接: leetcode…

項目管理-計算題公式【復習】2/2

2.【成本】相關公式 2.1掙值分析 三個參數 &#xff08;1&#xff09;計劃價值(PV&#xff0c;Plan Value): PV&#xff1a;計劃工作分配的經批準的預算&#xff0c;是為完成某活動或 WBS 組成部分而準備的一份經批準的預算。不包括管理儲備。 注意&#xff1a;按照計劃截止目…

LwIP 之九 詳解 UDP RAW 編程、示例、API 源碼、數據流

我們最為熟知的網絡通信程序接口應該是 Socket。LwIP 自然也提供了 Socket 編程接口,不過,LwIP 的 Socket 編程接口都是使用最底層的接口來實現的。我們這里要學習的 UDP RAW 編程則是指的直接使用 LwIP 的最底層 UDP 接口來直接實現應用層功能。這里先來一張圖,對 LwIP 內部…

React 和 Vue兩個流行的前端 JavaScript 框架有什么區別?

設計理念&#xff1a; React 是由 Facebook 開發的&#xff0c;專注于構建 UI 組件。它采用了一種聲明式的、組件化的開發模式&#xff0c;通過使用虛擬 DOM 來實現高效的 UI 更新。 Vue 是由尤雨溪開發的&#xff0c;旨在提供一個靈活且易于上手的框架。Vue 也支持組件化開發…

電商技術揭秘營銷相關系列文章合集(4)

相關系列文章 電商技術揭秘相關系列文章合集&#xff08;1&#xff09; 電商技術揭秘相關系列文章合集&#xff08;2&#xff09; 電商技術揭秘相關系列文章合集&#xff08;3&#xff09; 文章目錄 引言集合說明集合文章列表 引言 在數字化浪潮的推動下&#xff0c;電商行…

【35分鐘掌握金融風控策略25】定額策略實戰2

目錄 基于收入和負債的定額策略 確定托底額度和蓋帽額度 確定基礎額度 基于客戶風險評級確定風險系數 計算最終授信額度 確定授信有效期 基于收入和負債的定額策略 在實際生產中&#xff0c;客戶的收入和負債數據大多無法直接獲得&#xff0c;對于個人的收入和負債數據&…

【JavaEE】Spring Boot 入門:快速構建你的第一個 Spring Boot 應用

目錄 第一個SpringBoot程序介紹項目創建創建項目目錄介紹輸出Hello World 第一個SpringBoot程序 介紹 在學習SpringBoot之前, 我們先來認識?下Spring 我們看下Spring官?(https://spring.io/)的介紹 可以看到, Spring讓Java程序更加快速, 簡單和安全. Spring對于速度、簡單…

【論文閱讀筆記】MapReduce: Simplified Data Processing on Large Clusters

文章目錄 1 概念2 編程模型3 實現3.1 MapReduce執行流程3.2 master數據結構3.3 容錯機制3.3.1 worker故障3.3.2 master故障3.3.3 出現故障時的語義 3.4 存儲位置3.5 任務粒度3.6 備用任務 4 擴展技巧4.1 分區函數4.2 順序保證4.3 Combiner函數4.4 輸入和輸出的類型4.5 副作用4.…

用balenaEtcher燒錄ubuntu的iso文件都失敗,所以選用了另一種燒錄的軟件Rufus,然后燒錄成功了+安裝ubuntu的坑

https://releases.ubuntu.com/bionic/進入網頁下載ubuntu 選擇燒錄軟件將下載的Ubuntu燒錄到U盤中 之前用這個U盤燒錄過一次&#xff0c;成功了&#xff0c;后來應該是U盤受損或者是什么其他原因使得用這個U盤總是燒錄失敗 換思路&#xff1a;由于一直使用balenaEtcher燒錄ubu…

3 ESP32的PWM控制

Esp32的PWM控制也配置庫函數&#xff0c;以下就是PWM所用到的函數 1 PWM通道初始化設置 函數原型uint32_t ledcSetup(uint8_t chan, uint32_t freq, uint8_t bit_num)函數功能設定指定LEDC通道的PWM信號頻率和占空比分辨率返回值通道PWM信號的頻率參數說明chan&#xff08;LE…

WebView基礎知識以及Androidx-WebKit的使用

文章目錄 摘要WebView基礎一、啟動調整模式二、WebChromeClient三、WebViewClient四、WebSettings五、WebView和Native交互 Androidx-WebKit一、啟動安全瀏覽服務二、設置代理三、安全的 WebView 和 Native 通信支持四、文件傳遞五、深色主題的支持六、JavaScript and WebAssem…

ipa 功能包調試,分區算法,覆蓋算法測試

參考 wiki 流網絡 flow network 解釋 相關文章 ipa 分區算法 ipa 分區算法總結&#xff0c;部分算法圖解 環境 ubuntu20&#xff0c;ros 版本 noetic 運行測試 按照 readme 提示進行測試&#xff0c;跳過第一個步驟&#xff0c;并不需要 turtlebot3。 執行第三個 launch 報…

vue element checkbox的實現

實現多選非常簡單: 手動添加一個el-table-column&#xff0c;設type屬性為selection即可&#xff1b;默認情況下若內容過多會折行顯示&#xff0c;若需要單行顯示可以使用show-overflow-tooltip屬性&#xff0c;它接受一個Boolean&#xff0c;為true時多余的內容會在 hover 時以…

Java8 快速實現List轉map 、分組、過濾等操作

Java 8 是 Java 編程語言的一個重要版本&#xff0c;它引入了許多新特性和改進&#xff0c;使得 Java 開發變得更加高效和現代。 下面我們就來使用Java8 快速實現List轉map 、分組、過濾等操作。 定義1個用戶對象 public class User {private Integer id;private String nam…

計算機通信

一.進程和線程的區別? 1. 進程是資源分配的最小單位, 線程是cpu進行調度的最小單位。 2. 一個進程可以看做一個運行的程序, 一個進程中可以包含多個線程, 線程在進程內執行。 3. 多進程是指操作系統能同時運行多個任務&#xff08;程序&#xff09;&#xff0c;多線程是指在同…

數據挖掘原理與應用------分類預測

在數據挖掘和機器學習領域&#xff0c;TPR&#xff08;True Positive Rate&#xff09;是指在實際為陽性的情況下&#xff0c;模型正確預測為陽性的比例。TPR也被稱為靈敏度&#xff08;Sensitivity&#xff09;或召回率&#xff08;Recall&#xff09;。它是評估分類模型性能的…

【Linux】探索 Linux du 命令:管理磁盤空間的利器

給我一個擁抱 給我肩膀靠靠 你真的不需要 對我那么好 思念就像毒藥 讓人受不了的煎熬 我會迷戀上癮賴在你懷抱 &#x1f3b5; 陶鈺玉《深夜地下鐵》 在 Linux 系統管理中&#xff0c;磁盤空間管理是一項基礎而重要的任務。du&#xff08;disk usage&#…

如何解決IntelliJ IDEA中pom.xml依賴項引發的安全漏洞黃線警告問題

背景 在開發過程中&#xff0c;當我們在pom.xml文件中添加依賴項時&#xff0c;經常會發現IntelliJ IDEA報出黃色警告線條&#xff0c;提示存在潛在的安全漏洞。警告的具體展現形式如下&#xff1a; 解決方案 首先&#xff0c;打開設置菜單界面&#xff0c;接著選擇編輯器選…

vue3土味情話pinia可以持久保存再次修改App樣式

我是不是你最疼愛的人-失去愛的城市 <template><div class"talk"><button click"getLoveTalk">土味情話</button><ul><li v-for"talk in talkStore.talkList" :key"talk.id">{{ talk.title }}<…

用 Supabase CLI 進行本地開發環境搭建

文章目錄 &#xff08;零&#xff09;前言&#xff08;一&#xff09;Supabase CLI&#xff08;1.1&#xff09;安裝 Scoop&#xff08;1.2&#xff09;用 Scoop 安裝 Supabase CLI &#xff08;二&#xff09;本地項目環境&#xff08;2.1&#xff09;初始化項目&#xff08;2…