第四章 運算子 表示式和語句

2022-10-09 13:33:06 字數 4729 閱讀 4463

c使用運算子來表示算術運算。基本的算術運算子:=、+、-、*,以及/(c沒有指數運算子。標準c的數學庫為此提供了乙個pow()函式。例如,pow(3.5,2.2)返回3.5的2.2次冪)。

=號左邊必須是乙個變數的名字。賦值運算子左邊必須指向乙個儲存位置。最簡單的方法是使用變數的名字,但是以後您會看到,「指標」也可以用於指向乙個儲存位置。更普遍地,c使用術語「可修改的左值」來標誌那些我們可以為之賦值的實體。

幾個術語資料物件、左值、右值和運算元

「資料物件」是泛指資料儲存區的術語,資料儲存區能用於儲存值。c的術語左值指用於標識乙個特定的資料物件的名字或表示式。

因為不是所有的物件都是可以更改的,所以c使用術語「可修改的左值」來表示那些可以被更改的物件。所以,賦值運算子的左邊應該是乙個可修改的左值。術語「右值」指的是能賦值給可修改的左值的量。右值可以是常量、變數或者任何乙個可以產生乙個值的表示式。

我們稱之為「專案」的東西(比如在「符號=左邊的專案」中的「專案」)的正確術語是「運算元」。運算元是運算子操作的物件。

+和-運算子被稱為二元運算子或者雙值運算子,這表示它們需要兩個運算元。

除法運算子/,在c中,整數除法結果的小數部分都被丟棄。這個過程被稱為截尾。

注意,沒有把整數除法運算子運算的結果四捨五入到最近的整數,而是進行截尾,即捨棄整個小數部分。當您對整數與浮點數進行混合運算時,結果是浮點數。實際上,計算機不能真正用整數去除浮點數,所以編譯器將兩個運算元轉變成一致的型別。c99要求使用「趨零截尾」,所以應該把-3.8轉換成-3。

當兩個運算子共享乙個運算元時,優先順序規定了求值的順序。兩個乘法運算6*2和5*20在加法運算之前進行。優先順序沒有確定的是這兩個乘法運算中到底哪個先進行。c將這個選擇權留給實現者,這是因為可能有一種選擇在一種硬體上效率更高,而另一種選擇在另乙個硬體上效率更高。

sizeof運算子以位元組為單位返回其運算元的大小(在c中,1個位元組被定義為char型別所占用的空間的大小。在過去乙個位元組通常是8位,但是一些字符集可能使用更大的位元組)。運算元可以是乙個具體的資料物件(例如乙個變數名),或者乙個型別。如果它是乙個型別(如float),運算元必須被括在括號裡。

//2023年4月6日07:29:26

//使用c99的%z修飾符。如果不能使用%zd,請用%u或%lu

#include int main(void)

結果

n = 0,n has 4 bytes; all ints h**e 4 bytes.

c:\users\51670\desktop\c program\sizeof\x64\debug\sizeof.exe (程序 13928)已退出,**為 0。

要在除錯停止時自動關閉控制台,請啟用「工具」->「選項」->「除錯」->「除錯停止時自動關閉控制台」。

按任意鍵關閉此視窗. . .

c規定sizeof返回size_t型別的值。這是乙個無符號整數型別,但它不是乙個新的型別。相反,與可移植型別(如int32_t等)相同,它是根據標準型別定義的。c有乙個typedef機制,它允許您為乙個已有的型別建立乙個別名。例如:

typedef double real;
使real成為double的別名。您現在可以宣告乙個real型別的變數:

real deal;
編譯器看到單詞real,回想起typedef語句把real定義為double的別名,於是它把deal建立為乙個double型別的變數。與此相似,c的頭檔案系統可以使用typedef來使size_t在系統中作為unsigned int或unsigned long的同義詞。這樣當您使用size_t時,編譯器會用適合您的系統的標準型別代替之。c99更進一步,把%zd作為用來顯示size_t型別值得printf()說明符。如果您的系統沒有實現%zd,您可以進一步試著使用%u或者%lu代提它。

在c99為整數除法規定「趨零截尾」,如果第乙個運算元為負數,那麼得到的模也為負數;如果第乙個運算元為正數,那麼得到的模也為正數:

11/5 is 2 and 11%5 is 1

11/-5 is -2 and 11%-2 is 1

-11/-5 is 2 and -11%-5 is -1

-11/5 is -2 and -11%5 is -1

優點:通常產生更高效的機器語言**,因為它與實際的機器語言指令相似。然而,隨著商家推出更好的c編譯器,這個好處可能會消失。乙個智慧型編譯器能識別出x=x+1,並把它與++x相同對待。

①優先順序

增量運算子和減量運算子有很高的結合優先順序;只有圓括號比它們的優先順序高。所以,x*y++代表(x)*(y++)而不是(x*y)++。幸虧後者無效,增量運算子和減量運算子只能影響乙個變數(或者更一般地講,乙個可修改的左值);而組合x*y不是乙個變數。

使用原則:

●如果乙個變數出現在同乙個函式的多個引數中時,不要將增量或者減量運算子用於它上面。

●當乙個變數多次出現在乙個表示式裡時,不要將增量或減量運算子運用到它的上面。

***和順序點

***是對資料物件或檔案的修改。如果是乙個表示式的話,不僅算出乙個值,還修改了環境。跟賦值運算子一樣,增量運算子和減量運算子也有***,它們主要由於***而被使用。

乙個順序點是程式執行中的乙個點;在該點處,所有的***都在進入下一步前被計算。在c中,語句裡的分號標誌了乙個順序點。它意味著在乙個語句中賦值運算子、增量運算子及減量運算子所做的全部改變必須在程式進入下乙個語句前發生。

乙個完整的表示式是這樣乙個表示式-------它不是乙個更大的表示式的子表示式。完整表示式的例子包括乙個表示式語句裡的表示式和在乙個while迴圈裡作為判斷條件的表示式。

順序點幫助闡明字尾增量動作何時發生。

總結:表示式和語句

表示式:

表示式是運算子和運算元的組合。最簡單的表示式只有乙個常量或乙個變數而沒有運算子。

語句:語句是對計算機的命令。有簡單語句和復合語句。簡單語句以乙個分號結束。

復合語句或**塊由乙個或多個括在花括號裡的語句(這些語句本身也可能是復合語句)構成。

基本規則

1.當出現在表示式裡時,有符號和無符號的char和short型別都將自動轉換為int,在需要的情況下,將自動被轉換為unsigned int(如果short和int有相同的大小),那麼unsigned short比int大;在那種情況下,將把unsigned short轉換為unsigned int)。在k&r c下,但不是當前的c下,float將自動被轉換為double。因為是轉換成較大的型別,所以這些轉換被稱為提公升。

2.在包含兩種資料型別的運算裡,兩個值都被轉換成兩種型別裡較高的級別。

3.型別級別從高到低的順序是long double、double、float、unsigned long long、longlong、unsigned long、long、unsigned int、int。乙個可能的例外是當long和int具有相同大小時,此時unsigned int比long的級別更高。之所以short和char型別沒有出現在此清單裡,是因為它們已經被提公升到int或也可能被提公升到unsigned int。

4.在賦值語句裡,計算的最後結果都被轉換成將要被賦予值的那個變數型別。像規則1中一樣,這個過程可能導致提公升;但也可能導致降級,降級是乙個更低階的型別。

5.當作為函式的引數被傳遞時,char和short會被轉換成int,float會=被轉換成double。可以通過函式原型來阻止自動提公升的發生。

提公升是乙個平滑的無損害的過程,但是降級可能導致真正的問題。

指派運算子

通常您應該避免自動型別轉換,尤其是避免降級。但是倘若您小心使用,有時候它對做型別轉換很方便。然而,您也有可能需要準確的型別轉換,或者需要在程式中表明您是知道您正在做型別轉換的。完成這一任務的方法被稱為指派。

引數與參量

儘管術語引數和參量可以互換地使用,但c99文件已經規定:對實際引數或實際參量使用術語引數,對形式引數或者形式參量使用術語參量。遵循這個約定,我們可以說參量是變數,而引數是由函式呼叫提供的值,並且將它賦給相對應的參量。

假設您漏掉了型別指派,如果使用現代c,程式將為您自動完成型別指派。

void pound(int n);
原型是乙個函式宣告,它描述了函式的返回值和它的引數。這個函式原型說明了關於pound()函式的兩件事情:

●函式沒有返回值

●函式接收乙個int型別的引數

表示式是運算子和運算元的組合。在c裡,每乙個表示式都有乙個值,其中包括賦值表示式和比較表示式。運算子優先順序的規則幫助決定當對表示式進行求值時,如何組合表示式裡的各項。當兩個運算子共共享乙個運算元時,具有較高優先順序的運算子先被運算。如果運算子有相同的優先順序,結合性(從左到右或從右到左)決定了那個運算子先被應用。

語句是對計算機的完整指示,在c中通過乙個分號來標識。到目前,您已經使用了宣告語句、賦值語句、函式呼叫語句和控制語句。包含在一對花括號裡的語句構成了乙個復合語句或**塊。

在c裡,許多態別轉換會自動發生。當char和short型別出現在表示式裡或者作為函式的引數時,它們都將被提公升為int型別。當float型別作為乙個函式引數時被提公升為double型別。在k&r c(而不是ansi c)下,當float用於表示式裡時也被提公升為double型別。當把一種型別的值賦值給另一種型別的變數時,該值被轉換成和那個變數相同的型別。當較大型別的值被轉換成較小型別的值時,它們可能會丟失資料。在混合型別的算術運算的情況下,較小的型別被轉換成較大的型別。

第四章 表示式 4 2 算術運算子

上圖中按照運算子的優先順序將其分組。一元運算子的優先順序最高,接下來是乘法和除法,優先順序最低的是加法和減法。上述所有運算子都滿足做左結合律,意味著當優先順序相同時按照從左向右的順序進行組合。算術運算子能作用於任意算術型別以及任意能轉換為算術型別的型別。算術運算子的運算物件和求值結果都是右值。一元運...

第四章 表示式 4 4 賦值運算子

賦值運算子的左側運算物件必須是乙個可修改的左值。賦值運算的結果是它的左側運算物件,並且是乙個左值。結果的型別就是左側運算物件的型別,如果賦值運算子的左右兩個運算物件型別不同,則右側運算物件將轉換成左側運算物件的型別。賦值運算子滿足右結合律 對於多重賦值語句中的每乙個物件,她的型別或者與右邊物件的型別...

第四章 表示式 4 5 遞增和遞減運算子

遞增運算子 遞減運算子 為物件的加 1 和減 1 操作提供了一種簡潔的書寫形式。遞增和遞減運算子有兩種形式 int i 0,j j i i 的值是 1,j 的值是 1 j i i 的值是 2,j 的值是 1前置版本得到遞增之後的值,後置版本得到遞增之前的值。這兩種運算子都必須作用於左值運算的物件。前...