C語言相關探討,細究指標(pointer)與參照(reference)

感謝網友『阿仁』對於我BLOG裡面程式碼的訂正,在參考過『More Effective C++』中,對於指標使用上的補充順便加入Reference的一些資料。所以一併將這些資料整理在這裡,順便提一下今天侯捷老師講解一些關於Reference Counting 的概念。只能說很多東西要不斷的複習,不然真的都會遺忘,這幾次的面試有很多間公司都搞砸了也就是因為這個原因,原本五專時代都記得的東西,因為許久沒有使用,真的都忘的乾乾淨淨。 **指標(Pointer)與參照(Reference) **在C語言中,雖然指標與參照在使用上極為類似,但是實際上有許多地方式都是不同的。我將這些不同做成以下列表出來: <table cellspacing="1" border="1" width="62%" > <tr >   指標(Pointer) (type *p) 參照(Reference) (type &p) </tr> <tr > 記憶體配置 配置指標記憶體(4Byte) 不配置記憶體,本身為別名(Alias) </tr> <tr > 初始值給定 可以後來指定(不建議,但是允許這樣給值) 必須在變數成立的時候,直接給定初始值 </tr> <tr > 內容值(p) 代表一個記憶體位置,指向給定的目標值 直接代表目標值 </tr> <tr > 設定位置 (目標值Q) p=&Q p=Q (在此為將Q另外設定一個名字p) </tr> <tr > 給值 (目標值Q) *p=Q (將Q的值給*p) p=Q (在此為將Q另外設定一個名字p) </tr> </table> 根據以上的表格,順道提到一般課本常提到的Call by address與 Call by reference的參照方式,撰寫如下: <table cellspacing="1" border="1" width="57%" > <tr > Call by Address (use Pointer) Call by Reference (use Reference) </tr> <tr > #include void fun1(int * p, int * q) { *p=*p+*q; } void main() { int i=3,j=4,k; fun1(&i,&j); cout <<i; } </td> #include void fun1(int & p, int & q) { p=p+q; } void main() { int i=3,j=4,k; fun1(i,j); cout <<i; } </td> </tr> </table> 透過這個列表,可以清楚的兩者的差異,所以在之前文章所提到的錯誤為: int x=10; int *v; *v=x;; 在此錯誤為,由於我的指標 *v 並沒有初始化指標,所以v的值是一個系統給的亂數(或是之前變數留下來的資料),其實這樣去指定是相當危險的一件事情。所以要設定v去指定x的時候,應該使用 v=&x 去設定一個位置在v之中。之前會這樣想也因為我對於字串指標的設定有一點混淆 char *s="test ~~~ string~~~"; 像這樣的句子,雖然也是起使一個指標,但是由於電腦會先根據字串"test ~~~ string~~~"去分配一個位置給他,然後再把位置指定給s ,所以不需要再配置一次位置(記得這個問題在趨勢與友立似乎也一直被問到~~) 但是這裡順道一提 char *s="test...
繼續閱讀

MT-管理許多鍊結時,就用Blogrolling吧?

對於難以管理的友站鍊結,我也決定使用BlogRolling了,至於怎麼使用,我想憂鬱馬戲團上面的教學實在很詳細。此外,身邊的人也很多人這樣使用,不過規勸想使用的人~~~他對中文的支援實在鳥到受不了,每次輸入中文都得切換編碼到[UTF-8],仔細思考阿~~ 就醬~~~
繼續閱讀

軟體試用-MyDriver您的驅動程式管理員

由百分之八十的完美這個BLOG所看到的一個軟體,MyDriver是一套很好用的試用軟體,基本上他算是一個簡單的Driver檔案總管的功能,在我用過裡面的一些功能之後,大家可以去原始網站下載試用版,一共有十五天的試用期,剛下載完安裝的時候語言版本請選「English」,等到執行程式的時候,會自動轉成「簡體中文」(對岸同胞真是厲害~~),MyDriver這個軟體主要功能敘述如下: 自動搜尋系統所有設備的驅動程式 備份系統設備驅動程式 線上更新設備驅動程式 安裝與恢復舊有的驅動程式 其實這些功能實在相當的好用,在這邊展示一下他線上更新Driver的功能給大家看,首先在執行程式之後,選擇第一個選項之後會出現以下的畫面: 1.進入管理畫面後,選擇更新驅動,他就會自動抓取電腦上所有的驅動程式   2.之後列出所有的驅動程式(可能有些不太清楚),就選取可以更新的下載,然後在自行安裝到電腦上   3.選取好設備之後的下載視窗     結論: 使用過後來說,對於公司的MIS來說,這套軟體實在有購買的必要,不論是幫你備份驅動程式,或是尋找與更新相對應的驅動程式,若是沒有這個軟體,難保許多人員還要拆開電腦一個個設備去確認與尋找光碟片,有了這個軟體可以解決掉資訊人員在重灌電腦的慘痛經驗,並且也可以節省掉保存一大盒驅動程式的必要(網路卡還是需要,畢竟還是透過網路來更新驅動程式)
繼續閱讀

MT 整個單篇文章與匯出模版給大家參考

今日來學校加班論文,老師卻不在@﹍﹍﹍@”,但是看見酋長的部落格格式實在不錯,所以將自己的部落格也作了一些修改,修改如下: 將本來主索引中「友站鍊結」整理成一個鍊結方便以後整理 單篇文章的顯示模版(Individual Entry Archive)整合到主模版(main index)之中用來顯示 將每個模版整理出來(詳細資料,請看以下介紹~~~) 依照酋長的部落格,我思考到雖然之前有波一些整合介面的文章,但是深怕大家不太會使用我所提出的一些MT調教的手則,但是雖然像所酋長的部落格所提到一樣可以匯出檔案,我也發現如果要正確的重建所有的檔案,所有的檔案還是需要恢復成原來的名稱(也就是『主索引』還是要改回為index.html)這點倒是讓我想不透,所以我後來的處理方式如下: 將Blog下所有html 檔案(原來的模版檔案,複製到一個自製的目錄區) 更改檔案內容為 txt 如果你的主機系統是在LINUX下面,有一個更方便的方式 建立一個目錄為 template 在 /template 建立 LINK ( ln -s 目的.txt 來源) 比如說 『主索引模版』( ln -s ../index.html ./index.htm.txt )   雖然這個方法很麻煩,不過我還是將模版列出如下: 主索引::index 樣式表::styles-site.css 總彙整索引::archives 分類彙整 單篇彙整 按時彙整 要參考的請按滑鼠右鍵後,選取另存新檔即可打開
繼續閱讀

MT新知,MT3.0 Develop Edition 開始使用

由酋長的部落格看到的 敲敲地,MT發表了3.0的Development Edition,一往以前好用的軟體都會開始收費的方式,到了3.0也開始比較強迫性的收費,其實根據那些收費的標準來看個人版$99.95 (美金) 實在是有點太貴,(商業版也才兩個個人版的價位????)有點讓我懷疑,MT的下一步是不是要讓一些大型的部落格獨佔優勢而讓像我們這些個人使用者慢慢消失ㄌㄟ?? 不過收費標準裡面也有提到,如果要用免費的MT也是會有以下的限制(在3.0之前有許多似乎是沒有的) 沒有來自於Six Apart的協助(那~~~~是幹嘛的?) 不能存取安裝過程服務(也還好~~ 反正有 Jedi 大大) 不能存取付費服務(這個還在看手冊~~ 似乎在舊版沒有什麼付費服務?) 不能宣傳你的weblog 在一些網址(反正有很多群落格可以幫忙宣傳~~) 不能作商業用途~~(現在BLOG 用商業用途的也很少~~~) 不能超過三個Weblogs 與每個Weblogs 只能有一個作者 ( 個人認為,這個算是很大的限制~~個人用戶就忍耐點~~) 在酋長的部落格感受到似乎很多人對於這樣收費措施有點不滿意,不過我對於這樣的收費措施是鼓勵的,只是到底Web Programming所產生出的服務有多少可以收費的空間,我還是一直很好奇,從以前一直在接CASE的時候就在想,常常思考把一些Include FILE設成遠端的,強制收費不然網站功能就會被 Disable掉, 但是又覺得網路程式的收費性實在很難去界定。 不過~~~ MT的收費實在是太貴了,不然我本身很想付費使用這套系統的說 :p
繼續閱讀

Buffer Overflow 的範例程式

關於buffer overflow的範例程式,就如同上一篇文章裡面有提到,buffer overflow 主要是利用C++對於陣列大小沒有限制的概念,當你輸入一個過大的數值,回傳值(return value)會被蓋掉,即使你輸入錯誤的數值,你會也因為這樣而成功的登入電腦(或是使某個安全認證通過~~~) 一個好朋友(生魚片)寫了一個範例程式,但是我看了一下總是覺得哪裡怪怪的,因為我記得雖然記憶return value會在記憶體位置之中,但是很難確切抓出function的回傳位置就在變數之後,並且他設定的函數為void,照理說也是無法回傳的才對~所以我大膽猜測他所寫的程式主要是將func的副程式加以執行過後的結果,與我們原先探討的Buffer Overflow有所差異,所以我寫了一個範例程式如下: #include #include char func(void) { char *p; char r_c; char buf[1]; p=buf; *p=’N’; *(p+1)=’N’; *(p+2)=’N’; *(p+3)=’N’; *(p+4)=’N’; if (buf[0]==’y’){ r_c=’N’;} return r_c; } int main(int argc, char* argv[]) { char Return_char; if (func()==’N’){ printf(“system ~~~ passing~~~n”); } else{ printf("system is not passing~~~n"); } } 在這個範例程式之中,副函示有數個變數宣告,buf[1],*p, r_c 所以記憶體分配方式如下_(先宣告的記憶體位址比較後面,後宣告的記憶體位置比較前面)_: | +-----------------------+ | (other variable) | +-----------------------+ | 指標 p | +-----------------------+ | (other variable) | +-----------------------+ | r_c (1 bytes) | +-----------------------+ | (other variable) | +-----------------------+ | buf (1 bytes) | +-----------------------+ | (other data in stack) | | . | +-----------------------+ | return address of | | this function | | . | | . | 當你在VC++編輯的時候,若是使用 [F11]來一個階段,一個階段的DEBUG,去一個個參照變數的位置(Address)的時候,你會發現以下的結果 [ ](http://www.evanlin.com/blog/archives/0514/0514-1.jpg) 也就是透過指標*p,回傳變數r_c會被該更改到,使得回傳的值變的有誤。 所以這個程式明明不該輸出『System passing 』卻因為回傳值變成r_c所以產生~~~~錯誤造成程式的錯誤  
繼續閱讀