C語言 運算子 表示式和語句

2021-10-09 02:12:48 字數 3941 閱讀 1073

c的基本運算子包括:+、-、*和/,c沒有指數運算子,但是c的標準數學庫中提供了乙個pow()函式用於指數運算,例如pow(3.5,2.2)返回3.5的2.2次冪。

基本運算子這裡講一些注意點

這裡先說幾個術語:資料物件、左值、右值和運算子

除法運算子:/

c語言中,整數除法的小數部分會被捨棄,這一過程稱為截斷

混合整數和浮點數計算的結果是浮點數。計算機不能真正用浮點數處以整數,編譯器會把兩個物件轉換成相同型別,例如printf("7./4 is %1.2f \n",7./4)中,在進行除法運算前,整數會被轉換成浮點數`。

運算子優先順序

優先順序從高到低

運算子結合律

()從左往右

±(一元)

從右往左

* /從左往右

± (二元)

從左往右

=從右往左

考慮以下語句:

y = 6 * 12 + 5 * 20;

當不同運算子共享同乙個運算物件時,優先順序決定了求值順序,即先進行兩個乘法。但優先順序並未規定先進行哪乙個乘法,計算機根據不同的硬體來決定先計算前者還是後者,可能在一種硬體上採用某種方案的效率更高,而在另一種硬體上採用另一種方案效率更高。但無論採用哪種方案,表示式都是簡化成 72 + 100,雖然這並不影響結果,但是讀者可能誤用乘法從左往右的結合律來解釋這一點。 結合律只適用於同樣優先順序運算子共享同一運算物件的時候,例如表示式:12 / 3 * 2中,/ 和 * 的優先順序相同,共享物件為3,因此結合律在這種情況起作用。

siezeof運算子和size_t型別

c頭檔案系統中使用typedef 把 size_t 作為 unsigned int 或 unsigned double 的別名。這樣在使用size_t 型別時,編譯器會根據不同的系統替換標準型別(有的系統sizeof()返回的是unsigned int型別,有的返回的是unsigned long 型別,引用size_t 統一返回值)。c99做了進一步調整,新增%zd 轉換說明用於printf()顯示size_t 型別的值。若系統不支援,可用%u 或 %lu替代 %zd。

求模運算子:%

遞增運算子:++

shoe = 3.0;

while (shoe < 18.5)

//可將復合語句中的自增放到while條件語句中去,

//即while(++shoe<18.5),並改寫shoe的初始值為2.0。

這麼做的好處一是緊湊的**能讓程式更為簡潔,可讀性更高,更重要的是它把控制迴圈的兩個過程集中在乙個地方,這樣就不容易忘記更新迴圈

遞減運算子:- -

優先順序遞增運算子和遞減運算子都有很高的結合優先順序,只有圓括號的優先順序比它們高。因此,x * y++表示的是(x) * (y++),而不是(x * y)++,但是後者無效,因為遞增和遞減運算子只能影響乙個變數(即只能影響乙個可修改的左值),而組合x*y本身是不可修改的左值

不要自作聰明

建議不要一次性複雜地使用太多遞增遞減運算子。

例如在函式中:

printf("%10d,%10d\n",num,num*num++);

c語言中,編譯器可以自行選擇先對函式中的哪個引數求值,如果在函式引數表中使用遞增遞減運算子,可能造成不必要的麻煩,例如以上程式只能在某些系統中正常執行。該程式的問題是,當printf()獲取待列印的值時,可能先對最後乙個引數(num * num++)求值,這樣在獲取其它引數的值前就先遞增了num,得到結果6,25;但是它也有可能從右往左執行,對最右邊的num(++作用的num)使用5,然後遞增num,對第2個num和最左邊的num使用6,結果得到:6,30。

類似這樣的語句也會導致一些麻煩:

ans = num/2 + 5*(1 + num ++);

編譯器可能不會像你所想的先計算第1項(num/2)接著計算第2項(5 * (1 + num ++)),而是先計算第二項,遞增num,然後再num/2中使用num遞增後的新值。

遵循以下規則,可以避免類似的問題。

語句

語句是c程式的基本構建塊。一條語句相當於一條完整的計算機指令,但並不是所有的指令都是語句。

例如: x = 6 + (y = 5)

該語句中子表示式 y = 5 是一條完整的指令,但它只是語句的一部分而不是一條語句。

***和序列點

***是對資料物件或檔案的修改。如語句: states = 50; 它的***是將變數的值設定為50。***?這似乎更像是主要目的!但從c語言的角度看,主要目的是對表示式求值。跟賦值運算子一樣,遞增遞減運算子也有***,但使用它們的主要目的就是使用其***。

序列點是程式的執行點,在該點上,所有的***都在進入下一之前發生。在c語言中,語句中的分號標記了乙個序列點。意思就是,在一條語句中,賦值、自增、自減運算子對運算物件做的改變必須在程式執行下一條語句之前完成。

1.當型別轉換出現在表示式時,無論是unsigned int 還是 signed的 char 和 short 都會被自動轉換成int ,必要時轉換成unsigned int (如果 short 與 int的大小相同時,unsigned short 就比int 大,這種情況下 unsigned short被轉換成unsigned int)。由於都是從較小型別轉換成較大型別,所以這種轉換被稱為公升級

2.涉及兩種運算型別的運算,兩個值會被分別轉換成兩種型別的更高階別。

3.型別的級別從高到低依次是: long double>double>float?unsigned long long>long long>unsigned long >long?unsigned int >int。

4.賦值表示式語句中,計算的最終結果會被轉換成被賦值變數的型別。這個過程可能導致型別公升級降級

5.當作為函式引數傳遞時,char和short被轉換成int,float被轉換成double。

型別公升級通常不會有什麼問題,但是型別降級會導致真正的麻煩。因為較低型別可能放不下較高型別的整個數字。例如乙個8位的char變數儲存101沒問題,但是存不下22334.

如果待轉換的值與目標型別不匹配怎麼辦?

1.目標型別是無符號整形,且待賦的值是整數時,額外的位會被忽略。例如,目標型別是8位的unsigned char,待賦的值是原始值求模256。

2.如果目標型別是乙個有符號的整形,且待賦的值是整數,結果因實現而異。

3.如果目標型別是乙個整型,且待賦的值是浮點數,該行為未定義。

強制型別轉換符

格式:(目標型別)待轉換的量

int mice;

mice = 1.6 + 1.7;

mice = (int)1.6 + (int)1.7;

第一行使用自動型別轉換,首先1.6+1.7得3.3,然後為了匹配int型別的變數,3.3被型別轉換截斷為整數3.

第二行,1.6和1.7在相加之前都被轉換成整數1,所以把1+1的和賦給變數mice。

帶引數的函式

假設自定義乙個函式 void pound(int n),在主函式前宣告函式原型void pound(int n),向函式傳遞乙個char型別的『!』,因為原型的存在,編譯器會把該引數轉換成int型別,在ascii中『!』的數值是33,在系統中,該引數從1位元組的33變成4位元組的33以滿足函式的要求。同樣地,向函式傳遞乙個浮點數也會因為原型的存在而被轉換成合適的型別。

而在ansi c之前,c語言使用的是函式宣告而不是函式原型,函式宣告只指明了函式名和返回型別,沒有指明引數型別。即使缺少函式宣告,char和short型別也會被自動公升級為int型別,但是float會被自動公升級為double型別傳輸給函式,從而導致輸出的內容不正確。

c 表示式運算子和語句

一 表示式是運算子和運算元的字串,可以擔當運算元的結構有 1.字面量 2.常量 3.變數 4.方法呼叫 5.元素訪問器,如陣列訪問器或索引。6.其他表示式 二 字面量 字面量是源 中書寫的數字或字串,用來表示乙個明確型別的明確 固定的值。1.整數字面量 整數字面量被書寫為十進位制數字序列,並且沒有小...

C語言的運算子 表示式和語句

1 表示式 由運算元和操作符共同組成,所有的表示式都有乙個最終執行結果。如 a b x y 20 運算元可以是常量 變數或二者的組合。2 運算子 2.1 算術運算子 編譯器根據運算元決定執行浮點數還是整數運算。2.2 賦值運算 在c語言中,符號 不表示 相等 而是賦值。如a 2 表示的是 將值2賦給...

運算子 表示式和語句

一 表示式分為簡單表示式和複雜表示式 1 簡單表示式 最簡單的表示式只包含單獨的運算元 乙個簡單變數 字面常量和符號常量 pi 程式中定義的符號常量 20 字面常量 rate 變數 1.24 字面常量 2 複雜表示式 由多個更簡單的表示式組成,表示式之間用運算子連線。二 運算子 1 算符運算子 加法...