陣列的誤用

2021-05-26 07:07:13 字數 2366 閱讀 8851

我上次寫了篇文章列舉了我所看到的一些不好的c++教學,並且承諾詳細地解釋這些技術。這篇就是其中的第一篇。 我見到有歸因於trenchard more(*定義了more array theory)的斷言,說陣列是所有資料結構中最基本的乙個。 事實上幾乎沒有哪個在世的程式設計師沒有使用過陣列。如果沒有足夠的證據,想象一下陣列是一種線性定址機制的抽象,它是所有計算機硬體通常使用的最基礎的部分。

線性定址的想法認為計算機的記憶體由一組具有連號位址的儲存單元構成。通過使用普通的整數來計算儲存單元的位址,我們可以很容易從「陣列的第幾個元素」的概念出發找到相應的位址。

因為這種陣列概念與底層位址概念上的聯絡,陣列操作在所有支援它的程式語言中都很相似。 乙個陣列有許多元素,每個元素都有乙個下標或索引,並且這些索引數都是連續的整數。 有些語言從0開始索引,另外一些則從1開始,也有少數一些可以從任意位置開始,這關乎於語言間的差異性。

大多數支援陣列的語言都會阻止在陣列建立後修改陣列的大小。 c與c++要求的更多: 它們要求資料的大小必須在編譯時明確。不然,程式必須建立乙個動態陣列,它雖然和簡單的陣列有類似的屬性,在一些細節上還是有所不同。 即便是這些動態陣列,也不能在建立後修改大小。

現在讓我們來考慮一下程式如何使用陣列。大部分的程式設計師有三種完全不同的方式使用陣列。有時這三件事是交錯的,但通常一次只做一件:

1. 儲存資料

2. 訪問資料

3. (可選)取出所有資料

第2步包括重新安排資料, 或許是排序。 第3步包括列印資料。

舉個例子,考慮乙個程式來計算素數。 每次它測試乙個數字以檢查它是不是乙個素數,它也許使用在陣列中已經儲存的資料(第2步).每次它發乙個素數,就會將它儲存到乙個陣列中 (第1步). 最後,它也許要將所有找到資料列印出來 (第3步). 在這裡,第1步和第2步是交錯進行的,第3步有可能交錯,也有可能獨力執行。(*取決於邊找找輸出,還是最後一次性輸出。)

當程式按這三步來運算元組時,必須面對兩個問題。首先,如果程式語言要求程式設計師在建立陣列時就凍結它的大小,那麼程式設計師必須知道需要多少元素。再者,即使程式設計師已經知道元素數量,固定的大小意味著在程式執行的大部分情況下,陣列中總是有元素的值是沒有意義的。

這些限定就引出兩個一般性的程式設計實踐,以我的觀點來看,它們比學習如何程式設計要難得多:

*推測陣列應當需要多少元素

*使用乙個輔助變數來追蹤使用了多少元素

例如,讓我們回到之前假設的素數程式. 你應當看到過許多程式以類似下面的方式開始:

int primes[1000]; // 我們不需要超過1000個素數

primes[0] = 2; // 第乙個素數是2

n = 1; // 目前為止我們已經有乙個素數 

這個程式推測出我們會發現的素數數量(1000),並且使用乙個輔助變數(n)來追蹤我已經得到了多少素數。當我們得到乙個新的素數時,程式會執行:

primes[n++] = prime;

如果程式經過認真思考,就會使用檢查是否n>=1000的語句,否則程式就可能因為溢位而crash.

從教學的觀點來看這個程式很差,三個理由:

*它為程式的能力強加了乙個限制 -- 它不能計算超過指定數量的素數。

*在只需要乙個變數時卻使用了兩個(primes和n),因此使得**遠比它所需要的複雜。

*它在分配陣列時浪費了資源。 

標準的vector模板可以避免這三個問題。對於上面的例子,我們可以使用如下**重寫:

vectorprimes; // primes開始並沒有任何元素

primes.push_back(2); //第乙個素數是2

在即將發布的c++標準,我們可以將這個例子簡化為一句話:

vectorprimes = ;

當得到乙個新的素數時,我們可以通過下面的語句來追加:

primes.push_back(prime);

這個語句會將primes的大小增加1,追加了乙個變數prime的複本到primes中. 實際上,它是將prime壓到primes的背後。這樣我們就處理掉了之前三個問題中的兩個:1.使用vector替代資料移除了在元素數量上的約束。 2.只需要使用乙個變數 (不再需要額外的輔助變數)。

當然,這並沒有解決資源浪費的問題,因為vector在背後也分配了超出陣列所需要的記憶體。然而現在是程式在浪費記憶體,而不是程式設計師。而且這種浪費讓程式設計師有機會在不徹底重寫**的情況下,在多種空間與時間的權衡中進行選擇。相對於教初學者如何寫不必要的晦澀**,我們可以教他們寫合適的**,然後在**可以工作後,再來判斷如何或者是否需要進行優化。

簡言之,程式設計師往往樂於使陣列在程式執行過程中增長。c/c++中內建的資料並不能達到要求,而vector可以做到。所以使得vcetor對教學目的而言更為有用,特別是面對初學者的時候。 此外,陣列並不能限制學生撰寫本質上不值得的**。相反地,學生可以獲得乙個良好的習慣:首先讓程式可以執行,然後就只需要思考如何進行優化。

別誤用指標

1 c c 中,很容易因誤用指標而犯錯誤,請考慮以下 它的目的是在鍊錶的前面插入乙個元素 bool insertinfront intelement head,int data 前面的 是不正確的,因為它只更新了頭指標的 本地拷貝 正確的版本是傳入乙個頭元素指標的指標 bool insertinfr...

(程式設計基礎)void main的誤用

很多同學喜歡用void main 認為是無返回的main函式,這樣用可能有如下幾種可能 1 為了省事,可以少寫返回值 小弟以前就屬於這種 2 看到krc裡面用main 以為就是void main 主要因為krc的時候還沒有完善的c語言標準,這個用法在c99裡面已經明確禁止了,而且c 之父strous...

Selenium中被誤用的XPath

用selenium實現自動化測試的過程中,如果選擇頁面上的元素並且對之進行各種操作,是乙個常見的任務。selenium提供了多種定位方法 網上很多selenium的介紹文章,在講述如何利用xpath定位元素的時候,通常都是這樣子說的 開啟firefox瀏覽器,安裝firebug外掛程式,然後就能方便...