濟南做網(wǎng)站注冊一個域名需要多少錢
簡介:本系列博客為C深度解剖系列內(nèi)容,以某個點為中心進行相關詳細拓展
適宜人群:已大體了解C語法同學
作者留言:本博客相關內(nèi)容如需轉載請注明出處,本人學疏才淺,難免存在些許錯誤,望留言指正
作者博客鏈接:睡覺待開機
下面是本節(jié)博客的大綱梳理:
引言
在生活中,我需要下載一個視頻或者軟件時候,往往需要較長的時間(相對來說),但是我們?nèi)绻麆h除相應的>視頻或者軟件時候,反而會很快(相對來說),這是為什么呢?
這是一個比較奇特的現(xiàn)象,(在不懂的人看來)。
下面針對該問題進行探討,為了便于大家理解,我直接回答相關問題,最后再做示例演示。
正文
答案:計算機的數(shù)據(jù)下載,需要把大量二進制數(shù)據(jù)進行拷貝。而計算機的數(shù)據(jù)刪除,本質上設置該數(shù)據(jù)無效即可,無需清空數(shù)據(jù)。
1.數(shù)據(jù)下載與刪除所需時間不同的原因:
計算機數(shù)據(jù)的存入,需要把相應數(shù)據(jù)全部復制到存儲硬件(內(nèi)存、硬盤)中進行存儲,也就是需要把該視頻的音頻數(shù)據(jù),圖像數(shù)據(jù)的所有二進制文件全部拷貝到計算機中,雖然計算機的處理速度很快,但是一個大一點的電影就是十幾個G,再快也得幾分鐘才可以搞定。但是對于計算機而言,刪除數(shù)據(jù)并不會像我們想象那樣,需要把該視頻文件全部回歸初始狀態(tài),而是計算機直接宣布放該視頻的這塊內(nèi)存空間允許被其他內(nèi)容覆蓋。明白了這些,自然數(shù)據(jù)下載很慢,而數(shù)據(jù)刪除很快了,因為壓根就沒刪。
為了便于大家理解,我做一個比喻:計算機的數(shù)據(jù)下載類似于我們蓋一個新的大樓,說起蓋大樓要先打地基,再向上一步一步搞,總之非常麻煩。但是,如果要拆除一座大樓呢?寫個拆字就行了。當然與之不同的是大樓拆除是會破壞原來大樓的結構的,但是計算機為了效率的原因直接讓那龐大的數(shù)據(jù)在那里就可以了,便不再管了,直到這塊空間再次被使用,才會覆蓋為新的內(nèi)容。
那這里其實大家就可以聯(lián)想到為什么有些人建議不要賣掉你的手機或者電腦,原因嘛,上面的說明就是一個大概的一個情況,具體這方面數(shù)據(jù)刪除很復雜,明白上面所說即可。
但是可能有人就想問了,為啥計算機不把我們需要刪除的內(nèi)容進行修改防止個人信息泄露呢?
一是為了效率問題:如果要對刪除內(nèi)存空間進行初始化修改,計算機估計要多一倍的工作量,計算機是十分看重效率的,這么做我想設計者也是為了追求效率吧。
二是為了減少計算機本身的硬件損耗:這其實是硬件層面的知識了,我也不太清楚,只能說如果計算機對內(nèi)存操作越頻繁,那么存儲硬件損耗會越快,我想這么做也是為了硬件壽命考量吧。
2.C語言中函數(shù)棧幀問題:
了解到上面所講的計算機對數(shù)據(jù)的下載和刪除原理之后,那么就可以聯(lián)系到我們C語言中的函數(shù)棧幀了。我們知道我們C語言是由函數(shù)所構成的,那么函數(shù)是在哪里進行存儲的呢?是在內(nèi)存,在具體而言是在內(nèi)存??臻g。
這里就不得不提一下C程序地址空間的相關概念了,這個C程序地址空間實際并不存在,是為了便于我們理解人們所抽象出來的操作系統(tǒng)進程地址空間,不是真正意義上的內(nèi)存空間(不是內(nèi)存真正的空間!)。
每當我們C程序調用一個函數(shù)時候,會預先給這個函數(shù)一塊固定大小的空間,讓該函數(shù)中的變量在所給該函數(shù)的??臻g中開辟屬于變量的內(nèi)存空間。在函數(shù)調用開始時候操作系統(tǒng)會把我們計算機內(nèi)存中的一塊空間給我們某個函數(shù)使用,一旦該函數(shù)調用結束,那么就收回該空間。
我們一般稱操作系統(tǒng)給函數(shù)的這塊空間為棧幀。
有同學可能好奇,為啥計算機知道要給這個函數(shù)分配多少空間啊?我可以比較形象的解釋一下這個問題,因為計算機提前看了一眼你寫的代碼,雖然沒有執(zhí)行,但是大概知道你寫的函數(shù)需要給多少空間啦。
總結下來就是,調用函數(shù),形成棧幀,結束函數(shù),釋放棧幀,同理,這里釋放棧幀只是允許其他內(nèi)容覆蓋該棧幀空間,并不是真正意義上的刪除原先數(shù)據(jù)。
那么,實際上上面所說的內(nèi)容,可以回答兩個問題:
一是為啥局部變量具有臨時性的問題:原因很簡單,因為局部變量都是在函數(shù)內(nèi)部進行定義的,也就是說變量的存在依托于他所在函數(shù)的存在,他函數(shù)所在空間都被收回了,作為在里面的變量自然也就消失了。
為了大家理解,我可以舉個比喻性的例子,就是古代西方國家與貴族的例子吧,一個古代西方國家有一個國王還有一堆貴族組成,函數(shù)在這里就類似于國家,變量類似于貴族,你說國家都滅亡了,這個國家的貴族還能有嗎?哈哈,對吧。這恰到好處的解釋了為什么局部變量具有臨時性的問題,你可能會疑問,那全局變量呢?全局變量的空間開辟并不是在函數(shù)內(nèi)完成,而是跑到了全局數(shù)據(jù)區(qū),伴隨著程序的消亡而消亡,這又是另一個話題了。
二可以回答函數(shù)無限遞歸導致崩潰的問題:也很好理解,函數(shù)無限遞歸,也就是說在第一個函數(shù)里調用第二個函數(shù),第二個函數(shù)里調用第三個函數(shù)…,一直調用,我們操作系統(tǒng)一直沒有機會去收回我們函數(shù)的空間,棧空間遲早有一天會被無限遞歸占滿,那么自然會導致棧溢出崩潰。
3.return數(shù)據(jù)與臨時變量接收的本質
在C語言中,有一個關鍵字叫return,專門用來返回一個函數(shù)的返回值。我們說了,一個函數(shù)調用結束便意味著消亡,那么這個函數(shù)內(nèi)的值是怎么返回到調用這個函數(shù)的函數(shù)中去的?
為了便于大家理解我說的啥意思,我直接給一個具體的例子:
//如何正確理解這段代碼
#include <stdio.h>
#include <windows.h>
char* show()
{
char str[] = "hello bit";
return str;
}
int main()
{
char *s = show();
printf("%s\n", s);
system("pause");
return 0;
}
實際上,是借助了寄存器。
那么該如何驗證呢?需要看反匯編。
上面代碼的結果是:函數(shù)及時被銷毀了,但是如果數(shù)據(jù)沒有被覆蓋那么依然可以找到數(shù)據(jù),但是如果被覆蓋了,那顯示結果大概就是亂碼了。
在這個例子中,覆蓋show函數(shù)數(shù)據(jù)的函數(shù)是printf函數(shù)。
未覆蓋數(shù)據(jù)之前,還可以看到原本的值:
然后最后再說一點,就是函數(shù)返回值與函數(shù)返回值的接收,是獨立的。
完。