C語言迴圈小技巧

2022-08-27 20:18:09 字數 3679 閱讀 7809

寫**,有兩類追求,一種是追求實用(coder),一種是追求**藝術(artist)

我是那種追實用追膩了,偶然追一下藝術(就是偶然和藝術有一腿)的那種coder

很多人,已經習慣了for(i=0; i= n;

}又或者,有的人知道平方根的優化:

int isprime(int n)

再或者,消除偶數:

int isprime(int n)

當然,這樣還不是很夠的話,我們可以考慮這個事實:

所有大於4的質數,被6除的餘數只能是1或者5

比如接下來的5,7,11,13,17,19都滿足

所以,我們可以特殊化先判斷2和3

但後面的問題就出現了,因為並非簡單的遞增,從5開始是+2,+4,+2,+4,....這樣遞增的

這樣的話,迴圈應該怎麼寫呢?

首先,我們定義乙個步長變數step,迴圈大概是這樣 for (i = 5; i <= s; i += step)

那麼,就是每次迴圈,讓step從2變4,或者從4變2

於是,可以這麼寫:

#include #include int isprime(int n)

return i > s;

}int main()

getchar();

return 0;

}如上**,乙個 step ^= 6; 完成step在2和4之間轉換(這個 ^ 符號是c裡的異或運算)

理由是,2化二進位制是010,4是100,6是110,於是2異或4得到6:

2 ^ 4 => 6

6 ^ 2 => 4

6 ^ 4 => 2

於是利用異或,就可以構造這種步長在兩個值之間來回變化的迴圈

思考題:前面說的是雙值迴圈,那麼如何構造三值或者四值迴圈?

2.菱形列印

很多人,列印菱形在控制台的思路是,把菱形上下拆分,分兩段很接近的**來列印,

其實這樣**很不好看,並且不好閱讀

我們知道,要列印的圖案是這種:

****

*****

****

滿足上下對稱,左右對稱,那麼,你能不能也弄乙個二重迴圈,同樣是對稱的?

很簡單,首先我們要拋開習慣性思維,for迴圈不一定要在0開始或者0結束

我們可以讓迴圈從 -c 到 c ,這樣不就輕鬆產生乙個對稱的嗎?(只要取個絕對值)

我們把菱形的中心看成是座標0,0,那麼,會輸出星號的座標,是 |x| + |y| <= c 的點

由此可得

#include #define iabs(x) ( (x) >= 0 ? (x) : -(x) ) //定義乙個計算絕對值的巨集

void print(int size) // size是這個菱形的半徑,直徑會是size * 2 + 1

putchar('\n');

}}int main()

如果我需要得到空心菱形呢?非常非常簡單,因為菱形邊界上的點,滿足的是|x| + |y| == c

所以,我們只要把那個if裡的小於等於號,改成雙等於號 == 就可以了

再類似地,如果我不要*號,我要最外層是字母a,然後裡一層是b這樣呢?即:

aaba

abcba

abaa

那麼,我們只要在putchar那裡做乙個字元計算:

void print(int size) // size是這個菱形的半徑,直徑會是size * 2 + 1

putchar('\n');

}}類似地,如果我們要列印的是x形:

* *

* **

* ** *

同樣可以利用這個思路完成,這題就作為思考題吧

3. 奇數階幻方

所謂幻方(最基本的那種),就是橫,豎,對角線上的數的和等於乙個常數的數字方陣

4 3 8

9 5 1

2 7 6

以上這個圖,有什麼規律?容易寫成**嗎?

我們把這個圖,向右複製五次,向下複製三次,展開一下:

4 3 8 4 3 8 4 3 8 4 3 8 4 3 8

9 5 [1] 9 5 1 9 5 1 9 5 1 9 5 1

2 7 6 [2] 7 6 2 7 6 2 7 6 2 7 6

4 3 8 4 [3] 8 [4] 3 8 4 3 8 4 3 8

9 5 1 9 5 1 9 [5] 1 9 5 1 9 5 1

2 7 6 2 7 6 2 7 [6] 2 [7] 6 2 7 6

4 3 8 4 3 8 4 3 8 4 3 [8] 4 3 8

9 5 1 9 5 1 9 5 1 9 5 1 [9] 5 1

2 7 6 2 7 6 2 7 6 2 7 6 2 7 6

注意中括號數字的走向

怎麼樣,現在呢?

現在看起來顯得規律性強了很多,但是,你會不會覺得迴圈還是不太好寫?

我們如何從乙個給定的n,直接得知它的座標呢?

不難,找一下規律就可以發現對於任意的數值n+1有(以左上角為0,0座標):

x = 2 + n + n / 3;

y = 1 + n - n / 3;

其實這個規律可以簡單擴充套件到任意奇數階幻方(以下size是奇數):

x = size / 2 + 1 + n + n / size; (注意這裡的除法是取整除法,不帶小數)

y = size / 2 + n - n / size;

這樣,我們就可以把原來複雜的迴圈,化簡成一重簡單迴圈

於是有程式:

#include #define size 5 //定義幻方階數,這個數只能是奇數

int main()

//以下是輸出

for (y = 0; y < size; y++)

return 0;

}這個比你網上能找到的很多求奇數階幻方的**都短小很多(不過網上較多稱之為魔方陣,不知為何)

4. 字串迴圈移位

問題,給你乙個字串,要求迴圈左移n位

比如對"abcdefg" 迴圈左移2位,我們要得到"cdefgab"

附加條件,不能使用連續輔助空間(包括動態分配),只能使用若干單個變數(即o(1)空間)

首先,我們知道,反轉乙個字串操作("abcd"變"dcba"),是不需要額外陣列輔助的,只要頭尾資料交換就可以了

然而,可能你不知道,僅僅使用字串反轉可以實現字串迴圈移位:

//反轉字串,把st與ed所指向的中間的內容反轉(包含st不包含ed)

void str_rev(char* st, char *ed)

}//用三反轉等效左移字串(st與ed之間,包含st不包含ed的內容)

char* str_shl(char* st, char* ed, int n)

#include #include int main()

這裡,如果要迴圈左移n位,只要把原來字串分成兩段,前n字元,和後面其它字元

兩段分別反轉,最後再整體反轉,就實現了迴圈左移(如果先整體再兩部分,就是迴圈右移)

而在那個字串反轉函式裡,參與迴圈的,不再是int,而是兩個指標,

為什麼選擇使用兩個指標呢?如果你寫乙個str_rev(char* str, int len)的版本,相信你就明白了,這裡不多廢話

for迴圈小技巧

for迴圈 語法 for 表示式1 表示式2 表示式3 迴圈體表示式1一般為宣告迴圈變數,記錄迴圈的次數 int i 0 表示式2一般為迴圈條件 i 10 表示式3一般為改變迴圈條件的 使之終有一天不再成立 i 執行過程 程式首先執行表示式1,宣告了乙個迴圈變數用來記錄迴圈的次數,接著執行表示式2,...

c語言中迴圈使用技巧

簡明來說不確定迴圈,不知道何時迴圈停止,而計數迴圈已知要執行多少次迴圈 其中涉及了三個重要部分 1.初始化計數器 2.計數器與有限值比較 3.每次迴圈對計數器進行有規律變化 下面用for迴圈進行舉例 for i 0 i 10 i for i 0 i 10 i 見課本習題五p138頁 17題 incl...

C語言中的小技巧

看看下面一段程式的功能 testrcunit.cpp 定義控制台應用程式的入口點。include typedef void cunit test case func type brief 測試用例鍊錶結點。儲存測試用例的函式指標和測試用例的名字。typedef struct tagcunittest...