1. 程式人生 > >5到8章知識點總結

5到8章知識點總結

第五章 選擇

  • 表示式i < j < k在C語言中是合法的,但可能不是你所期望的含意
    因為**<運算子是左結合的**,所以這個表示式等價於 (i < j) < k
    換句話說,表示式首先檢測i是否小於j,然後用比較後產生的結果(1或0)來和k進行比較。
    這個表示式並不是測試j是否位於i和k之間。(正確的表示式應該是 i < j && j < k)

  • 短路特性

  • 不要混淆 == 運算子和 = 運算子,if(a==b)

  • switch後邊必須跟著圓括號括起來的整型表示式,可以用字元,不能用浮點數和字串。而且圓括號後面沒有;

  • case分支標號中的常量表達式的值必須是整數(字元也可以)

  • 雖然switch語句中的最後一個分支不需要break語句,但通常還是會放一個break語句在那裡,以防止將來增加分支數目時出現“丟失break"的問題。

問與答

  • 當我用=代替==時我所用的編譯器沒有發出警告。是否有辦法可以強制編譯器注意這類問題?
  • 針對複合語句,C語言的書籍好像使用了很多種縮排和放花括號的風格。哪種風格最好呢?
  • 如果i是int型變數, 而f是float型變數,那麼條件表示式(i > 0 ? i : f)是哪一種型別的值?
  • 為什麼C99為布林型別提供了一個更好的名字?
  • 明白了。但是為什麼_Bool這個名字就不會影響已有的程式呢?
  • 本章中的switch語句模板被稱為是“最常用格式”,是否有其他格式呢?
  • 我已見過一些縮排switch語句的方法,哪種方法最好呢?

第六章 迴圈

問與答

  • 6.1節有如下迴圈:
    while (i > 0)
    printf (“T minus %d and counting\n”, i–);
    為什麼不刪除“> 0”判定來進一步縮短迴圈呢?
    while (i)
    printf (“T minus %d and counting\n”, i–);
  • 6.3節提到,大多數for迴圈可以利用標準模式轉換成while迴圈。能給出一個反例嗎?
  • 哪個無限迴圈格式更可取,while(1)還是for( ; ; )?
  • 聽說程式設計師應該永不使用continue語句。這種說法對嗎?
  • goto語句有什麼不好?
  • 除了說明迴圈體為空外,空語句還有其他用途嗎?
  • 除了把空語句單獨放置在一行以外,是否還有其他方法可以凸顯出空迴圈體?

第七章 基本型別

一、整數型別

有符號整數和無符號整數

  • 有符號整數。如果為正數或零,那麼最左邊的位(符號位)為0;如果是負數,則符號位為1。因此,最大的16位整數的二進位制表示形式是0111111111111111,對應的值是32767(即215- 1)。而最大的32位整數是01111111111111111111111111111111,對應的數值是2147483647(即231 - 1)。
    不帶符號位的整數(最左邊的位是數值的一部分)稱為無符號整數。最大的16位無符號整數是65535 (即216 - 1),而最大的32位無符號整數是4294967295 (即232 - 1)。
  • 預設情況下,C語言中的整型變數都是有符號的。也就是說最左位保留為符號位。若要告訴編譯器變數沒有符號位,需要把它宣告成unsigned型別。 無符號整數主要用於系統程式設計和底層與機器相關的應用。

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

  • 表中給出的取值範圍不是C標準強制的,會隨著編譯器的不同而不同。
    對於特定的實現,確定整數類型範圍的一種方法是檢查<limits.h>
    該頭是標準庫的部分,其中定義了表示每種整數型別的最大值和最小值的巨集。

整數常量

  • C語言允許用十進位制、八進位制、十六進位制形式書寫整數常量。

二、浮點型別

在這裡插入圖片描述

  • 可以在頭<float.h>中找到定義浮點型別特徵的巨集。

浮點常量

  • 字母e之前必須有數字,e後面的指數必須為整數
  • 預設情況下, 浮點常量都以雙精度數的形式儲存。
    換句話說,當C語言編譯器在程式中發現常量57.0時,它會安排資料以double型別變數的格式儲存在記憶體中。
  • 在某些極個別的情況下,可能會需要強制編譯器以float或long double格式儲存浮點常量。
    為了表明只需要單精度,可以在常量的末尾處加上字母F或f (如57.0F);而為了說明常量必須以long double格式儲存,可以在常量的末尾處加上字母L或l (如57.0L)。

讀/寫浮點數

  • 讀取double型別的值時,在e、f或g前放置字母l:
    double d;
    scanf(“If”, &d):
    注意:只能在scanf函式格式串中使用 l ,不能在printf函式格式串中使用。
    在printf函式格式串中,轉換e、f和g可以用來寫float型別或double型別的值。
    (C99允許printf函式呼叫中使用%le、%lf和%lg,不過字母l不起作用。)
  • 讀寫long double型別的值時, 在e、f或g前放置字母L:
    long double ld;
    scanf(“Lf”, &ld);
    printf(“Lf”, ld);

三、字元型別

  • char型別的變數可以用任意單字元賦值:
    char ch;
    ch = ‘A’;
  • 注意,字元常量需要用單引號括起來,而不是雙引號。
  • 字元常量事實上是int型別而不是char型別
    當計算中出現字元時,C語言只是使用它對應的整數值。

有符號字元和無符號字元

  • 既然C語言允許把字元作為整數來使用,那麼char型別也應該像整數型別一樣也存在有符號型和無符號型兩種。
  • 通常有符號字元的取值範圍是-128-127。而無符號字元的取值範圍則是0~255。
  • C語言標準沒有說明普通char型別資料是有符號型還是無符號型,有些編譯器把它們當作有符號型來處理,有些編譯器則將它們當作無符號型來處理。(甚至還有一些編譯器允許程式設計師通過編譯器選項來選擇把char型別當成有符號型還是無符號型。)
  • 大多數時候,人們並不真的關心char型別是有符號型還是無符號型。但是,我們偶爾確實需要注意,特別是當使用字元型變數儲存一個小值整數的時候。 基於上述原因,標準C允許使用單詞 signed 和 unsigned 來修飾char型別:
    signed char sch;
    unsigned char uch;
  • 可移植性技巧 不要假設char型別預設為signed或unsigned。如果有區別,用signed char或unsigned char代替char。

轉義序列

字元處理函式

字元的輸入/輸出

四、型別轉換

問與答

  • 7.1節說到%o和%x分別用於以八進位制和十六進位制書寫無符號整數。那麼如何以八進位制和十六進位制書寫普通的(有符號)整數呢?
  • 但是,如果數是負數該怎麼辦呢? 如何以八進位制或十六進位制形式書寫它?
  • 浮點常量為什麼儲存成double格式而不是float格式?
  • 十六進位制的浮點常量是什麼樣子? 使用這種浮點常量有什麼好處?
  • 為什麼使用%lf讀取double型別的值, 而用%f進行顯示呢?
  • char的正確發音是什麼?
  • 什麼時候需要考慮字元變數是有符號的還是無符號的?
  • 我無法理解換行 (new-line) 符怎麼會是ASCII碼的回車 (line-feed) 符。當用戶錄入輸入內容並且按回車鍵時,程式不會把它作為回車符或者回車加回行符讀取嗎?
  • 使用轉義序列 ? 的目的是什麼?
  • 既然getchar函式的讀取速度更快,為什麼仍然需要使用scanf函式讀取單個的字元呢?
  • 在什麼情況下,整值提升會把字元或短整數轉換成unsigned int型別?
  • 如果把超出變數取值範圍的值賦值給變數,究竟會發生什麼?
  • 為什麼C語言要提供型別定義呢? 定義一個BOOL巨集不是和用typedef定義一個Bool型別一樣好用嗎?
  • 你提到“編譯器本身通常就能夠確定sizeof表示式的值”。難道編譯器不總能確定sizeof表示式的值嗎?

第八章 陣列

  • 因為程式以後改變時可能需要調整陣列的長度,所以較好的方法是用巨集來定義陣列的長度。

  • C語言不要求檢查下標的範圍。當下標超出範圍時,程式可能執行不可預知的行為。 下標超出範圍的原因之一 是:忘記了n元陣列的索引是從0到n-1, 而不是從到1到n
    (正如一位教授喜歡說的,“在這件事情上,你總是偏離了一位。” 他顯然是對的。)
    下面的例子給出了由這種常見錯誤導致的奇異效果:
    int a[10], i;
    for (i = 1; i <=10; i++)
    a[i] = 0;
    對於某些編譯器來說,這個表面上正確的for語句卻產生了一個無限迴圈!
    當變數的值變為10時,程式將數值0儲存在a[10]中。但是a[10]這個元素並不存在,所以在元素a[9]後數值0立刻進入記憶體。如果記憶體中變數i放置在a[9]的後邊(這是有可能的),那麼變數將會被重置為0,進而導致迴圈重新開始。

  • 當陣列下標有副作用時一定要注意。
    例如,下面這個迴圈想把陣列b中的元素複製到陣列a中,但它可能無法正常工作:
    i = 0;
    whlle (i < N)
    a[i] = b[i++];
    表示式通過a[i] = b[i++]訪問並修改i的值,這樣會導致未定義的行為。
    當然,通過從下標中移走自增操作可以很容易避免此類問題的發生:
    for(i = 0; i < N; i++)
    a[i] = b[i];

對陣列使用sizeof運算子

  • 用陣列的大小除以陣列元素的大小可以得到陣列的長度
    sizeof(a) / sizeof(a[0])
  • 陣列a的清零操作可以寫成如下形式:
    for(i = 0; i < sizeof(a) / sizeof(a[0]); i++)
    a[i] = 0;
  • 有些編譯器會對錶達式i < sizeof(a) / sizeof(a[0])給出一條警告訊息,這稍微有點煩人。
    變數i的型別可能是int (有符號型別),而sizeof返回的值型別為size_t (一種無符號型別)。
    把有符號整數與無符號整數相比較是很危險的。
    儘管在本例中這樣做沒問題(因為i和sizeof(a) / sizeof(a[0])都是非負值)。
    為了避免出現這一警告, 可以把sizeof(a) / sizeof(a[0])強制轉換為有符號整數:
    for(i = 0; i < (int) ( sizeof(a)/sizeof(a[0]) ); i++)
    a[i] = 0;

問與答

  • 為什麼陣列下標從0開始而不是從1開始?
  • 如果希望陣列的下標從1到10而不是從0到9,該怎麼做呢?
  • 使用字元作為陣列的下標是否可行呢?
  • 指定初始化式可能會對同一個陣列元素進行多次初始化操作。考慮下面的陣列宣告:
  • int a[] = {4,9,1,8,[0]=5,7};
    這個宣告是否合法?如果合法,陣列的長度是多少?
  • 如果試圖用賦值運算子把一個數組複製到另一個數組中,編譯器將給出出錯訊息。哪裡錯了?
  • 6.4節提到,C99不允許goto語句繞過變長陣列的宣告。為什麼會有這一限制呢?