[初章] 第一幕、請示主人從主命.幕間
Tags
- 初章
主人今天給了小希 200 塊,
小希好開心!收在哪兒好呢?
袖子嗎?裙底嗎?長襪嗎?
還是胸口──咦?主人今天忘了帶錢嗎?
沒關係喔!小希請客吧~
主人的 80,小希的 64,
總共是 144 呢。給。
很快地,在第一幕之後。
我們開始有機會讓使魔自盡程式當掉了。
如果不是一直複製貼上,
相信有人經歷過了。
問題多半會出在 scanf() 的 & 上面。
為什麼 scanf() 需要加 &
為什麼 printf() 卻不需要?
通常忘了加 & 就很容易當掉,
或者出現非預期的結果。
我們來談談這件事。
回顧一下第一幕的重點:
當使魔請求主人輸入一個整數時
必須指定一個記憶格儲存。
沒地方放的東西,就會隨風而去,
再也找不回來。當使魔表達的文字列中,
有暗號指定要置換為一個整數時,
必須指定我們所希望的整數。
否則使魔不會知道我們想置換成什麼數字。
scanf() 需要 『你想儲存的位置在哪裡』
=> 地址
printf() 需要 『你想傳達的數字是什麼』
=> 數值
假設我們現在有個記憶:
int power;
每個記憶都有它的實際儲存地址,
以及它在那地址中儲存的數值。
但光是寫出名字 power
不可能同時表達地址和數值。
我們必須避免一種寫法,有兩種或多種可能的解讀。
而『數值』被使用的機會,遠比『地址』高上太多。
只寫出名字 power 的時候,作為數值解讀。
作為地址解讀,則寫作 &power。
雖然聰明的你可能早就發現了:
只知道數值,無法逆推地址。
但若知道地址,就能知道數值。
那麼,問題來了:
為什麼 printf 不使用地址呢?
讓我們考慮以下狀況:
最近主人似乎有個煩惱。
期待已久的遊戲,還有數日就要發售。
可是主人手上的錢似乎不夠。
小希想幫助主人,所以必須知道還缺多少錢。
小希會從主人那問來整數 n 代表手上有多少錢,
以及整數 m 代表新遊戲的價格。
小希想要知道還缺多少錢。
雖然看起來複雜了些,
實際整理一下會發現其實是差不多的:
- 先有記憶(兩格)
- 再請示主人(兩次)
- 最後告知結果
除了需要更多的記憶外,
主要差別在於我們要的結果是:差多少。
也就是新遊戲售價和手上錢的差。
1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{
int owned, game_price;
scanf("%d%d", &owned, &game_price);
printf("Master needs %d more money!\n", game_price - owned);
return 0;
}
這時,printf() 採用數值的好處就相當明顯了。
它可以接受用運算式來代表一個數值。
game_price - owned
原本不存在於任何儲存空間 (註1),
是在執行到的當下,才開始計算的數值。
printf() 選擇接受數值,
不是沒有道理的。
另外,同類型的記憶,
可以用逗號隔開,一次宣告多個。
scanf() 和 printf() 都可以夾帶多個 %d;
一個蘿蔔一個坑。
若有兩個 %d,就要給兩個地址或數值。
有三個就得給足三個。
一樣使用逗號分隔。
基於先來後到的原則,
第一個 %d 會對到第一個地址或數值,
第二個 %d 會對到第二個地址或數值,
依此類推。
回到前面提及的,
為什麼忘了加 & 可能導致使魔自盡程式當掉呢?
如果說是把數值當地址傳入,
那應該是一定當掉,而不只是可能當掉吧?
因為電腦是用整數作為地址的。
程式執行過程中所有東西,
包括記憶、甚至程式碼本身,
都是放在記憶體中的。
由於都在記憶體中,
就像全世界都在同一條街道上,
地址就只需要門牌號碼,不需要街道名稱。
但我們給的值,不一定是系統配給我們使用的『記憶』的地址。
很可能是系統用的,
或者其它程式用的,
不一定是分配給我們可愛的使魔用的區段。
而我們可愛的使魔,
就可能因任務要把數字記入這些禁區,
卻又沒有足夠的力量與權限,
在了解到這任務不可能達成的那一刻,
只能選擇以死謝罪。
這些悲劇畢竟是身為主人的我們,
在寫下不適當的指令時導致的。
希望各位也能考慮使魔們愚忠的末路,
在編寫咒文時能更謹慎、更小心一些。
那麼,最後來捉弄一下可愛的小希,
看看他困擾時的可愛反應吧!
由主人給予兩個整數 a 和 b,
小希必須將這兩個數字,
按照主人給的順序,反過來回答!
也就是依 b → a 的順序回答。
試試看你能多快讓小希順利照你的意思行動吧!