《C語言程序設計》第三章 基本算術運算


目錄:

3.1  C運算符和表達式

  • 3.1.1  算術運算符和表達式
  • 3.1.2  復合的賦值運算符
  • 3.1.3  增1和減1運算符

3.2  宏常量與宏替換

3.3  const常量

3.4  自動類型轉換與強制類型轉換運算符

3.5  常用的標准數學函數

3.6  本章知識點小結

3.7  本章常見錯誤小結


3.1.1  算術運算符和表達式

  •  算術運算符的優先級與結合性
運算符 含義

需要的操作

數個數

運算實例

運算

結果

優先級 結合性
-

取相反數

(Opposite Number)

1個(一元)

-1

-(-1)

-1

1

最高 從右向左

*

/

%

乘法(Multiplication)

除法(Division)

求余(Modulus)

2個(二元)

12/5

12.0/5

11%5

11.0%(-5)

(-11)%5

2

2.4

1

1

-1

較低 從左向右

+

-

加法(Addition)

減法(Subtraction)

2個(二元)

5+1

5-1

6

4

最低 從左向右
  • 算術表達式:由算術運算符及其操作數組成的表達式;操作數也稱為運算對象,它可以是常量、變量、函數。
  • 只需一個操作數的運算符稱為一元運算符(或單目運算符),需要兩個操作數的運算符稱為二元運算符(或雙目運算符),需要三個操作數的運算符稱為三元運算符(或三目運算符)。條件運算符是C語言提供的唯一一個三元運算符。
  • 不同於數學中的算術運算,C語言中的算術運算的結果與參與運算的操作數類型相關。以除法運算為例,兩個整數相除后的商仍為整數。例如,1/2與1.0/2運算 的結果值是不同的,前者是整數除法,后者則是浮點數除法。eg.12/5=2, 12.0/5.0(或者12/5.0,或者12.0/5)=2.4。
  • 在C語言中,求余運算限定參與運算的兩個操作數必須為整型,不能對兩個實型數據進行求余運算。
  • 注意,C語言中沒有冪運算符。
//計算並輸出一個三位整數的個位、十位和百位數字之和。
#include<stdio.h>
int main(void)
{
    int x=153,b0,b1,b2,b3,sum;
    b2=x/100;            //百位
    b1=(x-b2*100)/10;    //十位
    b0=x%10;             //個位
    sum=b0+b1+b2;
    printf("b2=%d,b1=%d,b0=%d,sum=%d",b2,b1,b0,sum);
    return 0;
 } 

輸出:
b2=1,b1=5,b0=3,sum=9

3.1.2  復合的賦值運算符

  • 涉及算術運算的復合賦值運算符有5個:+=,-=,*=,/=,%=

例如:n*=m+1等價於n=n*(m+1),但不等價於n=n*m+1.

#include<stdio.h>
int main(void)
{
    int a=3;
    a+=a-=a*a;
    printf("a=%d",a);
    return 0;
 } 

輸出:a=-12


#include<stdio.h>
int main(void)
{
    int a=3;
    a+=a-=a*=a;
    printf("a=%d",a);
    return 0;
 } 

輸出:a=0

 

 

  • 增1和減1運算的例子(初始n=3)
    語句 等價的語句 執行該語句后m的值 執行該語句后n的值
    m=n++;

    m=n;

    n=n+1;

    3 4
    m=n--;

    m=n;

    n=n-1;

    3 2

    m=++n;

    n=n+1;

    m=n;

    4 4
    m=--n;

    n=n-1;

    m=n;

    2 2

 3.1.3  增1和減1運算符

語句         m=-n++;

等價於      m=-(n++);

進一步,等價於     m=-n;    n=n+1;

假使 int n=3,則m=-3,n=4.

  • 后綴形式與前綴形式的區別在於:后綴是先使用變量的值,然后再增1(減1);前綴是先增1(減1),然后再使用變量的值,並且后綴增1(減1)運算符的優先級高於前綴增1(減1)運算符,前者是左結合的,而后者是右結合的。

3.2  宏常量與宏替換

//計算並輸出半徑r=5.3的圓的周長和面積。
#include<stdio.h>
int main(void)
{
    double r=5.3;
    printf("circumference=%f\n",2*3.14159*r);
    printf("area=%f\n",3.14159*r*r);
    return 0;
 } 

輸出:
circumference=33.300854
area=88.247263

若要做到一次編譯,多次運行計算不同半徑的圓的周長和面積,則每次運行時可以讓用戶從鍵盤輸入圓的半徑r的值,這就要用到C標准函數庫中的函數scanf()。

//從鍵盤輸入圓的半徑r,計算並輸出圓的周長和面積。
#include<stdio.h>
int main(void)
{
    double r;
    printf("Input r:");   //提示用戶輸入半徑的值     scanf("%lf",&r);      //以雙精度實型從鍵盤輸入半徑的值
    printf("circumference=%f\n",2*3.14159*r);
    printf("area=%f\n",3.14159*r*r);
    return 0;
 } 

程序會在屏幕上顯示:
Input r:
假使輸入5.3並回車,則輸出
Input r:5.3
circumference=33.300854
area=88.247263
  • scanf()函數用於從鍵盤輸入一個數,%lf指定輸入的數據類型應為雙精度實型。第六行語句中r前面的&是必要的,&稱為取地址運算符,&r指定了用戶輸入數據存放的變量的地址。
  • 幻數:在程序中直接使用的常數,如π,但幻數存在影響程序的可讀性和可維護性的問題,常把幻數定義為宏常量或const常量。
#include<stdio.h>
#define PI 3.14159    //定義宏常量PI
int main(void)
{
    double r;
    printf("Input r:");
    scanf("%lf",&r); 
    printf("circumference=%f\n",2*PI*r);   /*編譯時PI被替換成3.14159*/
    printf("area=%f\n",PI*r*r);
    return 0;
 } 
  • 宏常量:也稱符號常量,是指用一個標識符號來表示的常量,這時該標識符號與此常量等價。宏常量是由宏定義編譯預處理命令來定義的。
  • 宏定義的一般形式為:#define 標識符   字符串,其作用是用#define編譯預處理指令定義一個標識符和一個字符串,凡在源程序中發現該標識符時,都由其后指定的字符串來替換。
  • 宏名:宏定義中的標識符,習慣用字母全部大寫的單詞來命名;宏替換:將程序中出現的宏名替換成字符串的過程。
  • 注意:宏定義中的宏名與字符串之間可有多個空白符,但無需加等號,且字符串后一般不以分號結尾,因為宏定義不是C語句,而是一種編譯預處理命令。

3.3  const常量

宏常量的缺陷:宏常量沒有數據類型,字符串替換時極易產生錯誤。

  • const常量:可以聲明具有某種數據類型的常量。在聲明語句中,形式為:const 類型  常量名 = 初始值;    例如:const  double PI = 3.14159;
//使用const常量定義π,編程從鍵盤輸入圓的半徑r,計算並輸出圓的周長和面積。
#include<stdio.h>
int main(void)
{
    const double PI=3.14159;   //定義實型的const常量PI 
    double r;
    printf("Input r:");
    scanf("%lf",&r);
    printf("circumference=%f\n",2*PI*r);
    printf("area=%f\n",PI*r*r);
    return 0;
 } 

3.4  自動類型轉換與強制類型轉換運算符

  1.  表達式中的自動類型轉換
  • 類型提升:C編譯器在對操作數進行運算之前將所有操作數都轉換成取值范圍較大的操作數類型,可以避免數據信息丟失情況的發生。
  • 整數提升:類型提升的規則如下圖所示,縱向箭頭表示必然的轉換,即將所有的char和short都提升為int的步驟稱為整數提升。

                            float                                                                           char,short

                              ↓                                                                                     ↓

long double  ←  double  ←  unsigned long  ←  long  ←  unsigned int  ←  int

高 ←—————————————————————————————— 低

  • 上圖橫向箭頭表示不同類型的操作數進行混合運算時由高到低的類型轉換方向,但不代表轉換的中間過程。
  • 例如,一個int型操作數與一個 float型操作數進行算術運算,則在對其進行運算之前要先將 float型操作數自動轉換為 double型,並將int型操作數轉換成 double型(注意,無須經過int型先轉換為 unsigned int再轉換成long型,再轉換為 unsignedlong型,再轉換為 double型的過程)。一個特例是:如果一個操作數是long型,另一個是unsigned型,同時 unsigned型操作數的值又不能用long型表示,則兩個操作數都轉換成 unsigned long型。

        2.賦值中的自動類型轉換

  • 在一個賦值語句中,若賦值運算符左側(目標側)變量的類型和右側表達式的類型不一致,則賦值時將發生自動類型轉換自動類型轉換。類型轉換的規則是:將右側表達式的值轉換成左側變量的類型。
  • 自動類型轉換雖然給取整等某些特殊運算帶來方便,但在某些情況下有可能會發生數據信息丟失、類型溢出等問題。

        3.強制類型轉換運算符

  • 強制類型轉換運算符簡稱強轉運算符或轉型運算符,它的主要作用是將一個表達式值的類型強制轉換為用戶指定的類型,它是一個一元運算符,與其他一元運算符具有相同的優先級。通過下面方式可以把表達式的值轉為任意類型:(類型)  表達式
  • 強轉與指針,可並稱為C語言的兩大神器,必須恰當使用。
//演示強制類型轉換運算符的使用。 
#include<stdio.h>
int main(void)
{
    int m =5;
    printf("m/2=%d\n",m/2);
    printf("(float)(m/2)=%f\n",(float)(m/2));
    printf("(float)m/2=%f\n",(float)m/2);
    printf("m=%d\n",m);
    return 0;
 } 

輸出:
m/2=2
(float)(m/2)=2.000000
(float)m/2=2.500000
m=5
分析: 表達式m/2是整數除法,其運算結果仍為整數,因此輸出的第一行結果值是2; 表達式(float)(m/2)是將表達式(m/2)整數相除的結果值(已經舍去了小數位)強轉為實型數(在小數位添加了0),因此輸出的第二行結果值是2.000000,可見這種方法並不能真正獲得m與2相除后的小數部分的值; 表達式(float)m/2是先用(float)m將m的值強轉為實型數據,然后再將這個實型數據與2進行浮點數除法運算,因此輸出的第三行結果值是2.500000; 由於(float)m只是將m的值強轉為實型數據,但是它並不改變變量m的數據類型,因此輸出的最后一行結果值仍然是5.

3.5  常用的標准數學函數

/*已知三角形的三邊長為a、b、c,計算三角形面積的公式為:area=√s(s-a)(s-b)(s-c),其中s=(a+b+c) /2
試編程從鍵盤輸入a、b、c的值(假設a、b、c的值可以保證其構成一個三角形),計算並輸出三角形的面積*/
#include<stdio.h>
#include<math.h>
int main(void)
{
    float a,b,c,s,area;
    printf("Input a,b,c:");
    scanf("%f,%f,%f",&a,&b,&c);
    s=(a+b+c)/2;
    area=(float)sqrt(s*(s-a)*(s-b)*(s-c));
    printf("area=%f\n",area);
    return 0;
 } 

輸出:

Input a,b,c:3,4,5↙
area=6.000000

  • 分析:當a、b、c被定義為整型變量時,將數學公式s=(a+b+c)/2寫成如下各種形式的C語言表達式: s=0.5*(a+b+c)     s=1.0/2*(a+b+c)     s=(a+b+c)/2.0     s=(float)(a+b+c)/2  都是正確的。而如果寫成s=1/2*(a+b+c) 或者 s=(float)((a+b+c)/2) 雖無語法錯誤,但計算結果錯誤。
  • 注意,如果將第5行的變量改為double類型,那么第9行的sqrt()的返回值無需強轉為float,這樣計算的結果會比float計算的結果精度更高,導致輸出結果中的小數后的某些位有可能不一樣。
  • 使用數學函數時,只要在程序開頭加上如下的編譯預處理命令即可:
    #include<math.h>

 

3.6  本章知識點小結


3.7  本章常見錯誤小結

常見錯誤實例 常見錯誤描述 錯誤類型
2*π*r 表達式中使用了非法的標識符 編譯錯誤
4ac 或者 4×a×c 將乘法運算符*省略,或者寫成× 編譯錯誤
1.0/2.0+[a-b]/{a-b}

使用方括號“[”和“]”以及花括號“{”和“}”限定表

達式運算順序

編譯錯誤
sinx

使用數學函數運算時,未將參數用圓括號括起來,且

未注意到其定義域要求和參數的單位

編譯錯誤
3.5%0.5 對浮點數執行求余運算 編譯錯誤
1/2 誤將浮點數除法當做整數除法 運行時錯誤
float(m)/2 強轉表達式中的類型名未用圓括號括起來 運行時錯誤

誤以為(float)m這種強制運算可以改變變量m的

類型和數值

理解錯誤

誤以為用雙括號括起來的字符串中與宏名相同的字

符也被宏替換,誤以為宏替換時可以做語法檢查

理解錯誤
誤以為三角函數中的角的單位是角度 理解錯誤
#define PI = 3.14159;

將宏定義當做C語句來使用,在行末加上了分號,或

者在宏名后加上了“=”

編譯錯誤
+=,-=,*=,/=,%=

將復合的賦值運算符+=,-=,*=,/=,%=的兩個字符

中間加入了空格

編譯錯誤
(a+b)++ 對一個算術運算符使用增1或者減1運算 編譯錯誤


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM