順序程式設計舉例
例一
有人用溫度計測量出華氏法表示的溫度(如69℉)現要求把它轉換為以攝氏法表示的溫度(如20℃)
轉換公式:
//有人用溫度計測量出華氏法表示的溫度(69℉)今要求把它轉換為以攝氏法表示的溫度(20℃)
#include <stdio.h>
int main(void)
{
float f, c;
printf("請輸入華氏度f\n");
scanf("%f", &f);
c = 5 * (f - 32) / 9;
printf("f=%f\nc=%f\n", f, c);
return 0;
}
在VS編譯器內會報C4996錯誤,解決見下文:(下同)
C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. - EricsT - 部落格園 (cnblogs.com)
執行結果:
例二
計算存款利息。有1000元,想存一年。有三種方法可選:(1)活期,年利率為r1(2)一年定期,年利率為r2(3)存兩次半年定期,年利率為r3。請分別計算一年後按三種方法所得到的本息和。
//計算存款利息。有1000元,想存一年。有三種方法可選:(1)活期,年利率為r1(2)一年定期,年利率為r2(3)存兩次半年定期,年利率為r3。請分別計算一年後按三種方法所得到的本息和。
//本息和=本金+本金×利率×時間
#include<stdio.h>
int main(void)
{
float p0, r1, r2, r3, p1, p2, p3;
printf("請輸入本金p0\n");
scanf("%f", &p0);
printf("請輸入方法1年利率r1\n");
scanf("%f", &r1);
printf("請輸入方法2年利率r2\n");
scanf("%f", &r2);
printf("請輸入方法3年利率r3\n");
scanf("%f", &r3);
p1 = p0 + p0 * r1 * 1;
printf("方法1本息和%f\n", p1);
p2 = p0 + p0 * r2 * 1;
printf("方法2本息和%f\n", p2);
p3 = p0 + p0 * r3 * 0.5;
p3 = p3 + p3 * r3 * 0.5;
printf("方法3本息和%f\n", p3);
return 0;
}
執行結果:
資料的表現形式及其運算
常量和變數
在計算機高階語言中,資料有兩種表現形式:常量和變數
常量
在程式執行過程中,其值不能被改變的量稱為常量。
數值常量就是數學中的常數。
從字面形式上即可識別的常量稱為“字面常量”或“直接常量”。
字面常量是沒有名字的不變數。
常用的常量有以下幾類:
- 整型常量
- 實型常量。有兩種表現形式:
- 十進位制小數形式,由數字和小數點組成
- 指數形式,由底數和指數以及字母E或字母e組成
- 字元常量。用單撇號括起來的一個字元的常量。有兩種形式的字元常量
- 普通字元
- 跳脫字元
- 字串常量。用雙撇號把若干字元括起來的常量
- 符號常量,用
#define
指令,指定用一個符號名稱代表一個常量
使用符號常量有以下好處:
- 含義清楚
- 在需要改變程式中多處用到的同一個常量時,能做到“一改全改”
要區分符號常量和變數,不要把符號常量誤認為變數。
符號常量不佔記憶體,只是一個臨時符號,在預編譯之後這個符號就不存在了,故不能對符號常量賦予新值。
為與變數名區分,習慣上符號常量用大寫表示。
跳脫字元 | 字元值 | 輸出結果 |
\' | 一個單撇號 | 具有此八進位制碼的字元 |
\" | 一個雙撇號 | 輸出此字元 |
\? | 一個問號 | 輸出此字元 |
\\ | 一個反斜線 | 輸出此字元 |
\a | 警告 | 產生聲音或視覺訊號 |
\b | 退格 | 將當前位置後退一個字元 |
\f | 換頁 | 將當前位置移到下一頁開頭 |
\n | 換行 | 將當前位置移到下一行開頭 |
\r | 回車 | 將當前位置移到本行開頭 |
\t | 水平製表符 | 將當前位置移到下一個tab位置 |
\v | 垂直製表符 | 將當前位置移到下一個垂直製表符對齊點 |
\o、\oo、\ooo 其中o代表一個八進位制數字 |
與該八進位制碼對應的ASCII字元 | 與八進位制碼對應的字元 |
\xh[h...] 其中h代表一個十六進位制數字 |
與該十六進位制碼對應的ASCII字元 | 與十六進位制碼對應的字元 |
變數
變數代表一個有名字的、具有特定屬性的一個儲存單元。
用來存放資料,也就是存放變數的值。
在程式執行期間變數的值是可以改變的。
變數必須先定義後使用。
在定義時指定該變數的名字和型別。
一個變數應該有一個名字以便被引用。
變數名實際上是以一個名字代表的一個儲存地址。
變數值即存放在記憶體單元中的資料。
在對程式編譯連線時由編譯系統給每一個變數名分配對應的記憶體地址。
從變數中取值,實際上是透過變數名找到相應的記憶體地址,從該儲存單元中讀取資料。
常變數
常變數和常量的異同是:常變數具有變數的基本屬性:有型別,佔儲存單元,只是不允許改變其值。可以說,常變數是有名字的不變數,而常量是沒有名字的不變數。有名字就便於在程式中被引用。
定義符號常量是用#define
指令,它是預編譯指令,它只是用符號常量代表一個字串,在編譯時僅是進行字元替換,在預編譯後,符號常量就不存在了,對符號常量的名稱是不分配儲存單元的。而常變數是要佔用儲存單元的,有變數值,只是該值不改變而已。
常變數有符號常量的優點,而且使用起來更方便。
識別符號
在計算機語言中,用來對變數、符號常量名、函式、陣列、型別等命名的有效字元序列統稱為識別符號。
識別符號就是一個物件的名字。
C語言規定識別符號只能由字母、數字和下劃線3種字元組成,且第1個字元必須為字母或下劃線。
編譯系統將大寫字母和小寫字母認為是兩個不同的字元。
一般而言,變數名用小寫字母表示。
資料型別
在計算機中,資料是存放在儲存單元中的,它是具體存在的,儲存單元是由有限的位元組構成的,每一個儲存單元中存放資料的範圍是有限的。
所謂型別,就是對資料分配儲存單元的安排,包括儲存單元的長度(佔多少位元組)以及資料的儲存形式。
不同的型別分配不同的長度和儲存形式。
其中基本型別(包括整型和浮點型)和列舉型別變數的值都是數值,統稱為算術型別。
算術型別和指標型別統稱為純量型別,因為其變數的值以數字來表示。
列舉型別是程式中使用者定義的整數型別。
陣列型別和結構體型別統稱為組合型別,共用體型別不屬於組合型別,因為在同一時間內只有一個成員具有值。
函式型別用來定義函式,描述一個函式的介面,包括函式的返回值的資料型別餓引數的型別。
不同型別的資料在記憶體中佔用的儲存單元長度是不同的。
整型資料
整型資料的分類
基本整型(int)
編譯系統分配給int型資料2個位元組或4個位元組。
在儲存單元中的儲存方式是:整數的補碼
正數的補碼:二進位制
負數的補碼:絕對值的二進位制,每一位都按位取反,再加1
在存放整數的儲存單元中,最左面一位是用來表示符號的,如果該位是0,則為正數,如果該位是1,則為負數
如果給整型變數分配2個位元組,則一個整型變數的值的範圍是【-215,215-1】即【-32768, 32767】
如果給整型變數分配4個位元組,則一個整型變數的值的範圍是【-231,231-1】即【-2147483648, 2147483647】
短整型(short int)
型別名為 short int 或 short
在VC6.0中,編譯系統給 int 資料分配4個位元組,給 short 資料分配2個位元組。
儲存方式同int
一個短整型變數的值的範圍:【-215,215-1】即【-32768, 32767】
長整型(long int)
型別名為 long int 或 long
一個長整型變數的值的範圍:【-231,231-1】即【-2147483648, 2147483647】(VC6.0編譯系統給long資料分配4個位元組)
雙長整型(long long int)
型別名為 long long int 或 long long
一般分配8個位元組
是C99新增的型別
C標準沒有具體規定各種型別的資料所佔儲存單元的長度,這是由編譯系統自行決定的。
C標準只要求long型資料長度不短於int型,short型不長於int型,即:
sizeof(short) <= sizeof(int) <=sizeof(long) <= sizeof(long long)
sizeof是測量資料型別或變數長度的運算子
整型變數的符號屬性
型別 | 位元組數 | 取值範圍 |
int(基本整型) | 2 | 【-215,215-1】即【-32768, 32767】 |
4 | 【-231,231-1】即【-2147483648, 2147483647】 | |
unsigned int(無符號基本整型) | 2 | 【0,216-1】即【0, 65535】 |
4 | 【0,232-1】即【0, 4294967295】 | |
short(短整型) | 2 | 【-215,215-1】即【-32768, 32767】 |
unsigned short(無符號短整型) | 2 | 【0,216-1】即【0, 65535】 |
long(長整型) | 4 | 【-231,231-1】即【-2147483648, 2147483647】 |
unsigned long(無符號長整型) | 4 | 【0,232-1】即【0, 4294967295】 |
long long(雙廠型) | 8 | 【-263, 263-1】即【-9223372036854775808, 9223372036854775807】 |
unsigned long long(無符號雙長整型) | 8 | 【0,264-1】即【0, 18446744073709551615】 |
有符號基本整型 [signed] int
無符號基本整型 unsigned int
有符號短整型 [signed] short [int]
無符號短整型 unsigned short [int]
有符號長整型 [signed] long [int]
無符號長整型 unsigned long [int]
有符號雙長整型 [signed] long long [int]
無符號雙長整型 unsigned long long [int]
如果既未指定為signed也未指定unsigned,則預設為signed
只有整型(包括字元型)資料可以加signed或者unsigned修飾符,實型資料不能加
對無符號整型資料用%u
格式輸出,%u
表示無符號十進位制數的格式輸出
在將一個變數定義為無符號整型後,不能向它賦予一個負值,否則會得到錯誤的結果
字元型資料
由於字元是按其程式碼(整數)形式儲存的,因此C99把字元型資料作為整數型別的一種。
字元與字元程式碼
字元與字元程式碼並不是任意寫一個字元,程式都能識別的
只能使用系統的字符集中的字元,目前大多數系統採用ASCII字符集
各種字符集(包括ASCII字符集)的基本集都包括了127個字元,其中包括:
- 字母:大寫A~Z,小寫a~z
- 數字:0~9
- 專門符號:29個:! " # & ' ( ) * + , - · / : ; < = > ? [ \ ] ^ _ { | } ~
- 空格符:空格、水平製表符、垂直製表符、換行、換頁
- 不能顯示的字元:空(null)字元(以'\0'表示)警告(以'\a'表示)、退格(以'\b'表示)、回車(以'\r'表示)等
所有127個字元都可以用7個二進位制位表示(ASCII為127時,二進位制表現為1111111,7位全1)所以在C中,指定用一個位元組(8位)儲存一個字元(所有的系統都不例外)
字元‘1’和整數1是不同的概念:
字元‘1’只是代表一個形狀為‘1’的符號,在需要時按原樣輸出,在記憶體中以ASCII碼形式儲存,佔1個位元組
而整數1是以整數儲存方式(二進位制補碼方式)儲存的,佔2或4個位元組
字元變數
字元變數是用型別符 char 定義字元變數
例如:char c = '?';
字元變數實際上是一個位元組的整型變數,由於常用來存放字元,所以稱為字元變數
可以把[0, 127]之間的整數賦值給一個字元變數
在輸出字元變數的值時,可以選擇以十進位制整數形式輸出,或以字元形式輸出
例如:printf("%d %c", c, c);//輸出結果63 ?
用%d
格式輸出十進位制
用%c
格式用字元形式輸出字元
型別 | 位元組數 | 取值範圍 |
signed char(有符號字元型) | 1 | 【-27,27-1】即【-128, 127】 |
unsigned char(無符號字元型) | 1 | 【0,28-1】即【0, 255】 |
在使用符號字元變數時,允許儲存的範圍的值是【-128, 127】,但字元的程式碼不可能為負值,所以在儲存字元時實際上只用到了【0, 127】這一部分,其第一位都是0
如果將一個負整數賦給有符號字元型變數是合法的,但它不代表一個字元,而作為一個位元組整型變數儲存負整數
如果在定義變數時既不加signed,又不加unsigned,C標準並未規定是按signed char處理還是按unsigned char處理,由各編譯系統自己決定
浮點型資料
浮點型資料是用來表示具有小數點的實數的
在C語言中,實數是以指數形式存放在儲存單元中的
一個實數表示為指數可以有不止一種形式,小數點的位置是可以浮動的,只要在小數點位置浮動的同時改變指數的值,就可以保證它的值不會發生改變。由於小數點位置可以浮動,所以實數的指數形式稱為浮點數。
在指數形式的多種表示方式中把小數部分中小數點前的數字為0、小數點後第一位數字不為0的表示形式稱為規範化的指數形式,如0.314159*101就是3.14159的規範化指數形式
一個實數只有一個規範化的指數形式,在程式以指數形式輸出一個實數時,必然是以規範化的指數形式輸出,如0.314159e001
浮點數型別包括float(單精度浮點型)、double(雙精度浮點型)、long double(長雙精度浮點型)
float型(單精度浮點型)
編譯系統為每一個float型變數分配4個位元組
數值以規劃範的二進位制指數形式存放在儲存單元中
在儲存時,系統將實型資料分成小數部分和指數部分兩個部分,分別存放。小數部分的小數點前面的數為0。
此為十進位制的示意圖
在4個位元組(32位)中,究竟用多少位來表示小數部分,多少位來表示指數部分,C標準並無具體規定,由各C語言編譯系統自定。
由於用二進位制形式表示一個實數以及儲存單元的長度是有限的,因此不可能得到完全精確的值,只能儲存層有限的精確度。
小數部分佔的位(bit)數愈多,數的有效數字愈多,精度也就愈高。
指數部分佔的位數愈多,則能表示的數字範圍愈大。
float型資料能得到6位有效數字,數值範圍【-3.4*10-38, 3.4*1038】
double型(雙精度浮點型)
為了擴大能表示的數字範圍,用8個位元組儲存一個double型資料,可以得到15位有效數字,數值範圍【-1.7*10308, 1.7*10308】
在C語言進行浮點數的算術運算時,將float型資料都自動轉換為double型,然後進行運算
long double型(長雙精度浮點型)
不同的編譯系統對long double型的處理方法不同
型別 | 位元組數 | 有效數字 | 數字範圍(絕對值) |
float | 4 | 6 | 0以及【1.2*10-38, 3.4*1038】 |
double | 8 | 15 | 0以及【2.3*10-308, 1.7*10308】 |
long double | 8 | 15 | 0以及【2.3*10-308, 1.7*10308】 |
16 | 19 | 0以及【3.4*10-4932, 1.1*104932】 |
由於有限的儲存單元儲存一個實數,不可能完全精度的儲存,例如float型變數能儲存的最小正數為1.2*10-38不能存放絕對值小於此值的數
此為float變數能儲存的範圍
怎樣確定常量的型別
整型常量
不帶小數點的數值是整型常量,但應注意其有效範圍
在一個整數的末尾加大寫字母L或小寫字母l,表示它是長整型(long int)
浮點型常量
凡以小數形式或指數形式出現的實數,是浮點型常量,在記憶體中都以指數形式儲存
C程式中的實型常量都是雙精度浮點型常量
可以在常量的末尾加專用字元,強制指定常量的型別。
在實型常量後面加大寫或者小寫的F,指定此常量為float型別
在實型常量後面加大寫或者小寫的L,指定此常量為long double型別
型別與變數:
每一個變數都屬於一個確定的型別,型別是變數的一個重要屬性。
變數是佔用儲存單元的,是具體存在的實體,而其佔用的儲存單元中可以存放資料。
而型別是變數的共性,是抽象的,不佔用儲存單元,不能用來存放資料。
運算子和表示式
幾乎每一個程式都需要進行運算,對資料進行加工處理,否則程式就沒有意義了。要進行運算,就需要規定可以使用的運算子。
基本的算術運算子
運算子 | 含義 | 舉例 | 結果 |
+ | 正號運算子(單目運算子) | +a | a的值 |
- | 負號運算子(單目運算子) | -a | a的算術負值 |
* | 乘法運算子 | a * b | a 和 b 的乘積 |
/ | 除法運算子 | a / b | a 除 b 的商 |
% | 求餘運算子 | a % b | a 除 b 的餘數 |
+ | 加法運算子 | a + b | a 和 b 的和 |
- | 減法運算子 | a - b | a 和 b 的差 |
兩個實數相除的結果是雙精度實數,兩個整數相除的結果是整數
如果除數或被除數中有一個為負值,則舍入的方向是不固定的[多數系統是向零取整]
%運算子要求參加運算的運算物件(即運算元)為整數,結果也是整數
除%以外的運算子的運算元都可以是任何算術型別
自增、自減運算子
作用是使變數的值加1或減1
++i
或--i
在使用 i 之前,先使 i 的值加(減)1
i++
或i--
在使用 i 之後,使 i 的值加(減)1
如:
j = i++;
此時,若 i 初始值為3,則運算後, j 為3, i 為4(先將 i 賦值給 j ,此時 j 為3,再將 i 的值加1,此時 i 為4)
j = ++i;
此時,若 i 初始值為3,則運算後, j 為4, i 為4(先將 i 加1,此時 i 為4,再將 i 賦值給 j ,此時 j 為4)
printf("%d", i++);
此時,若 i 初始值為3,則輸出3,之後 i 變成4
printf("%d", ++i);
此時,若 i 初始值為3,先 i 加1變成4,再輸出 i ,即最後輸出4
自增運算子(++)和自減運算子(--)只能用於變數,而不能用於常量或表示式。因為常量的值無法改變,所以不能用於常量;因為在表示式內無法提供變數儲存自增或者自減後的資料,所以不能用於表示式。
自增運算子和自減運算子常常用於迴圈語句中,使迴圈變數自動加1;也用於指標變數,使指標指向下一個地址。
算術表示式和運算子的優先順序與結合性
用算術運算子和括號將運算物件(也稱運算元)連線起來、符合C語法規則的式子稱為C算術表示式
運算物件包括常量、變數、函式等
a * b / c - 1.5 + 'a'
此為一個合法的C算術表示式
C語言除了規定了運算子的優先順序外,還規定了運算子的結合性
在表示式求值時,先按運算子的優先順序別順序執行。例如:先乘除再加減
如果在一個運算物件兩側的運算子的優先順序相同,則按規定的“結合方向”處理。
C語言規定了各種運算子的結合方向(結合性)算術運算子的結合方向都是“自左至右”,即先左後右
“自左至右的結合方向”又稱“左結合性”,即運算物件先與左面的運算子結合
“自右向左的結合方向”又稱“右結合性”,即運算物件先與右面的運算子結合
關於“結合性”的概念在其他一些高階語言中是沒有的,是C語言的特點之一
不同型別資料間的混合運算
在程式中經常會遇到不同型別的資料進行運算,如果一個運算子的兩側的資料型別不同,則先自動進行型別轉換,使二者具有同一種型別,然後進行運算。
因此整型、實型、字元型資料間可以進行混合運算
- +、-、*、/運算的兩個數中有一個數為 float 或者 double 型,結果是 double 型,因為系統將所有的 float 型資料都先轉換為 double 型,然後再進行運算
- 如果 int 型與 float 型或者 double 型資料進行運算,先把 int 型和 float 型資料轉換為 double 型,然後進行運算,結果是 double 型
- 字元型(char 型)資料與整型資料進行運算,就是把字元的ASCII程式碼與整型資料進行運算。字元型資料可以直接與整型資料進行運算。如果字元型資料與實型資料進行運算,則將字元的ASCII程式碼轉換為 double 型資料,然後進行運算
例:給定一個大寫字母,要求用小寫字母輸出
//給定一個大寫字母,要求用小寫字母輸出
#include <stdio.h>
int main(void)
{
char ch;
printf("請輸入一個大寫字母\n");
scanf("%c", &ch);
printf("%c\n", ch + 32);
return 0;
}
執行結果:
強制型別轉換運算子
可以利用強制型別轉換運算子將一個表示式轉換成所需型別
(double)a;
將 a 轉換成 double 型
(int)(x + y);
將 x+y 的值轉換為 int 型
(float)(5 % 3);
將 5%3 的值轉換為 float 型
強制轉換的一般形式:
(型別名)(表示式)
注意:表示式應該用括號括起來作為一個整體
int a = (int)x;//float x
x 是 float 型變數, a 是 int 型變數,進行強制型別運算後得到一個 int 型別的臨時值,它的值等於 x 的整數部分,把它賦給 a ,注意 x 的值和型別都沒有發生變化,仍為 float 型,該臨時值在賦值後就不存在了。
C運算子
除了算術運算子外,C還提供其他運算子,共有以下幾類:
- 算術運算子(+ - * / % ++ --)
- 關係運算子(> < == >= <= !=)
- 邏輯運算子(! && ||)
- 位運算子(<< >> ~ | ^ &)
- 賦值運算子(=及其擴充套件賦值運算子)
- 條件運算子(?:)
- 逗號運算子(,)
- 指標運算子(* &)
- 求位元組數運算子(sizeof)
- 強制型別轉換運算子((型別))
- 成員運算子(. ->)
- 下標運算子([ ])
- 其他(如函式呼叫運算子())
C語句
C語句的作用和分類
一個函式包含宣告部分和執行部分,執行部分是由語句組成的,語句的作用是向計算機系統發出操作指令,要求執行相應的操作。一個C語句經過編譯後產生若干條機器指令。宣告部分不是語句,它不產生機器指令,只是對有關資料的宣告。
上圖為C程式結構,即一個C程式可以由若干個源程式檔案(編譯時以檔案模組為單位)組成,一個原始檔可以由若干個函式和預處理指令以及全域性變數宣告部分組成,一個函式由資料宣告部分和執行語句組成。
C語句分為五類:控制語句、函式呼叫語句、表示式語句、空語句、複合語句
控制語句
控制語句用於完成一定的控制功能
C只有9種控制語句:
if()...else...
(條件語句)for()...
(迴圈語句)while()...
(迴圈語句)do...while()...
(迴圈語句)continue
(結束本次迴圈語句)break
(中止執行switch或者迴圈語句)switch
(多分支選擇語句)return
(從函式返回語句)goto
(轉向語句,在結構化程式中基本不用 goto 語句)
上面語句表達形式中的 () 表示括號中是一個“判別條件”,“...”表示內嵌的語句
函式呼叫語句
函式呼叫語句由一個函式呼叫加一個分號構成
例如printf("Hello World");
其中printf("Hello World")
是一個函式呼叫,加一個;
成為一個語句
表示式語句
表示式語句由一個表示式加上一個分號構成
例如a = 3
是一個賦值表示式a = 3;
是一個賦值語句
一個語句必須在最後有一個分號,分號是語句中不可缺少的組層部分,而不是兩個語句間的分隔符號。
任何表示式都可以加上分號構成語句。
表示式能構成語句是C語言的一個重要特色。
其實“函式呼叫語句”也是屬於表示式語句,因為函式呼叫也屬於表示式的一種。
空語句
;
為空語句
語句只有一個分號,它什麼也不做。
作用:用來作為流程的轉向點(流程從程式其他地方轉到此語句處),也可以用來作為迴圈語句中的迴圈體(迴圈體是空語句,表示迴圈體什麼也不做)
複合語句
可以用{ }
把一些語句和宣告括起來成為複合語句(又稱語句塊)
複合語句常用在 if 語句或迴圈中,此時程式需要連續執行一組語句
複合語句中最後一個語句中最後的分號不能忽略不寫
最基本的語句--賦值語句
在C程式中,最常用的語句是:賦值語句和輸入輸出語句。
其中最基本的是賦值語句。
程式中的計算功能大部分是由賦值語句實現的,幾乎每一個有實用價值的程式都包括賦值語句。
有的程式中的大部分語句都是賦值語句。
例:給出三角形的三邊長,求三角形的面積
//給出三角形的三邊長,求三角形的面積
//area = sqrt((s * (s - a) * (s - b) * (s - c)));
//s = (a + b + c) / 2
#include <stdio.h>
#include <math.h>
int main(void)
{
double a, b, c;
printf("請輸入三角形的三邊長:\n");
scanf("%lf %lf %lf", &a, &b, &c);
double s = (a + b + c) / 2;
double area = sqrt(s * (s - a) * (s - b) * (s - c));
printf("a = %lf\nb = %lf\nc = %lf\narea = %lf\n", a, b, c, area);
return 0;
}
執行結果:
賦值運算子
賦值符號=
就是賦值運算子,它的作用是將一個資料賦值給一個變數
也可以將一個表示式的值賦值給一個變數
複合的賦值運算子
在賦值符號=
之前加上其他運算子,可以構成複合的運算子
a += 3
等價於a = a + 3
凡是二元(二目)運算子,都可以與賦值符一起組合成複合賦值符
有關算術運算的複合賦值符有+=
-=
*=
/=
%=
C語言採用這種複合運算子,一是為了簡化程式,使程式更加精煉,二是為了提高編譯效率,能產生質量較高的目的碼
賦值表示式
賦值語句是在賦值表示式的末尾加一個分號構成的
由賦值運算子將一個變數和一個表示式連線起來的式子稱為“賦值表示式”,它的一般形式變數 賦值運算子 表示式
賦值表示式的作用是將一個表示式的值賦給一個變數,因此賦值表示式具有計算和賦值的雙重功能
賦值運算子左側應該是一個可修改的“左值”
“左值”的意思是它可以出現在賦值運算子的左側,它的值是可以改變的
並不是任何形式的資料都可以作為左值的,變數可以作為左值,而算術表示式就不能作為左值,常量也不能作為左值,因為常量不能被賦值。
能出現在賦值運算子右側的表示式稱為“右值”
顯然左值也可以出現在賦值運算子的右側,因而凡是左值都可以作為右值
賦值表示式中的“表示式”,又可以是一個賦值表示式
將賦值表示式作為表示式的一種,使賦值操作不僅可以出現在賦值語句裡面,而且可以以表示式的形式出現在其他語句中printf("%d", a = b);
在一個 printf 函式中完成了賦值和輸出雙重功能,這是C語言靈活性 一種表現
賦值過程中的型別轉換
如果賦值運算子兩側的型別一致,則直接進行賦值
如果賦值運算子兩側的型別不一致,但都是算數型別時,在賦值時要進行型別轉換。
型別轉換是由系統自動進行的,轉換的規則是:
- 將浮點型資料(包括單、雙精度)賦給整型變數時,先對浮點數取整,即捨棄小數部分,然後賦值給整型變數
- 將整型變數賦值給單、雙精度變數時,數值不變,但以浮點數形式儲存到變數中
- 將一個 double 型資料賦給 float 變數時,先將雙精度數轉換為單精度,即只取6~7位有效數字,儲存到 float 變數的4個位元組中,應注意雙精度數值的大小不能超出 float 型變數的數值範圍
- 將一個 float 型資料賦給 double 型變數時,數值不變,在記憶體中以8個位元組儲存,有效位數擴充套件至15位
- 字元型資料賦值給整型變數時,將字元的ASCII程式碼賦給整型變數
- 將一個佔位元組多的整型資料賦給一個佔位元組少的整型變數或字元變數時,只將其低位元組原封不動的送到被賦值的變數(即發生“截斷”)
要避免把佔位元組多的整型資料向佔位元組少的整型變數賦值,因為賦值後數值可能發生失真。如果一定要進行這種賦值,應當保證賦值後數值不會發生變化,即所賦的值在變數的允許數值範圍內
整型資料之間的賦值,按儲存單元中的儲存形式直接傳送
實型資料之間以及整型與實型之間的賦值,是先轉換(型別)後賦值
由於C語言使用靈活,在不同型別資料之間賦值時,常常會出現資料的失真,而且這不屬於語法錯誤,編譯系統並不提示出錯
賦值表示式和賦值語句
在C程式中,賦值語句是用的最多的語句
C語言的賦值語句屬於表示式語句,由一個賦值表示式加一個分號組成
其他一些高階語言有賦值語句,而無“賦值表示式”這一概念。這是C語言的一個特點,使之應用靈活方便
在一個表示式中可以包含另一個表示式。賦值表示式既然是表示式,那麼它就可以出現在其他表示式之中
賦值表示式的末尾是沒有分號的,而賦值語句的末尾必須有分號。
在一個表示式中可以包含一個或多個賦值表示式,但決不能包含賦值語句
變數賦初值
可以用賦值語句對變數賦初值,也可以在定義變數時對變數賦初值,也可以使被定義的變數的一部分賦初值
int a, b, c = 5;
定義a, b, c三個整型變數,並對 c 賦初值為5
int a = 3, b = 3, c = 5;
定義a, b, c三個整型變數,並均賦初值3
一般變數初始化不是在編譯階段完成的(只有在靜態儲存變數和外部變數的初始化是在編譯階段完成的)而是在程式執行時執行本函式時賦初值,相當於執行一個賦值語句。int a = 5;
相當於int a; a = 5;
資料的輸入和輸出
例:求 ax2+bx+c=0 方程的根,a, b, c 由鍵盤輸入,設 b2-4ac>0
//例:求 ax2+bx+c=0 方程的根,a, b, c 由鍵盤輸入,設 b2-4ac>0
//p = - b / (2 * a)
//q = sqrt(b ^ 2 - 4 * a * c) / (2 * a)
//x1 = p + q
//x2 = p - q
#include <stdio.h>
#include <math.h>
int main(void)
{
double a, b, c;
printf("請輸入 a, b, c 的值\n");
scanf("%lf %lf %lf", &a, &b, &c);
double p = 0 - (b / (2 * a));
double q = sqrt(b * b - 4 * a * c) / (2 * a);
printf("%lf\n%\lf\n", p + q, p - q);
return 0;
}
執行結果:
有關資料輸入輸出的概念
幾乎每一個C程式都包含輸入輸出。因為要進行運算,就必須給出資料,而運算的結果當然需要輸出,以便人們應用。沒有輸出的程式是沒有意義的。輸入輸出是程式中最基本的操作之一。
所謂輸入輸出是以計算機主機為主題而言的。從計算機向輸出裝置(如顯示器、印表機等)輸出資料稱為輸出。從輸入裝置(如鍵盤、磁碟、光碟、掃描器等)向計算機輸入資料稱為輸入。
C語言本身不提供輸入輸出語句,輸入輸出操作是由C標準函式庫中的函式來實現的。在C標準函式庫中,提供了一些輸入輸出函式,例如printf
函式和scanf
函式。printf
和scanf
不是C語言的關鍵字,而是庫函式的名字。
C提供的標準函式以庫的形式在C的編譯系統中提供,它們不是C語言文字中的組成部分。
不把輸入輸出作為C語句的目的是使C語言編譯系統簡單精煉,因為將語句翻譯成二進位制的指令是在編譯階段完成的,沒有輸入輸出語句就可以避免在編譯階段處理與硬體有關的問題,可以使編譯系統簡化,而且通用性強,可移植性好,在各種型號的計算機和不同的編譯環境下都能適用,便於各種計算機上實現。
C語言函式庫中有一批“標準輸入輸出函式”,它是以標準的輸入輸出裝置(一般為終端裝置)為輸入輸出物件的。其中有:putchar
(輸出字元)getchar
(輸入字元)printf
(格式輸出)scanf
(格式輸入)puts
(輸出字串)gets
(輸入字串)
在使用系統庫函式,要在程式檔案的開頭用預處理指令#include
把有關標頭檔案放在本程式中。
用預編譯指令#include
的目的是講所需要的“標頭檔案”包括到使用者的原始檔中。在標頭檔案中包含了所需呼叫的函式的有關資訊。
#include
指令都放在程式檔案的開頭,因此這類檔案稱為標頭檔案。
#include<stdio.h>
在程式進行編譯預處理時,系統將 stdio.h 標頭檔案的內容調出來放在此位置,取代本行的#include
指令
#include<file>
在編譯時,編譯系統從存放C編譯系統的子目錄中去找所要包含的檔案(file)這稱為標準方式
#include"file"
在編譯時,編譯系統先在使用者的當前目錄(一般是使用者存放源程式檔案的子目錄)中尋找要包含的檔案,若找不到,再按標準方式查詢
如果用#include
指令是為了使用系統庫函式,因而要包含系統提供的相應標頭檔案,以用標準方式為宜,以提高效率
如果用#include
指令想要包含的標頭檔案不是系統提供的相應標頭檔案,而是使用者自己編寫的檔案(這種檔案一般存放在使用者當前目錄中)這時應當用雙撇號形式,否則會找不到所需的標頭檔案,如果該檔案不在當前目錄中,可以在雙撇號中寫出檔案路徑,以便系統能從中找到所需的檔案。
用 printf 函式輸出資料
在C程式中用來實現輸出和輸入的,主要是printf
函式和scanf
函式。這兩個函式是格式輸入輸出函式。用這兩個函式時,必須指定輸入輸出資料的格式,即根據資料的不同型別指定不同的格式。
printf 函式(格式輸出函式)用來向終端(或系統隱含指定的輸出裝置)輸出若干個任意型別的資料
printf 函式的一般格式
printf(格式控制, 輸出表列);
例如printf("%d, %c", i, c);
- 格式控制:用雙撇號括起來的一個字串,稱“轉換控制字串”,簡稱“格式字串”包括兩個資訊
- 格式宣告:格式宣告由
%
和格式字元(如%d
%f
等)組成。它的作用是將輸出的資料轉換為指定的格式然後輸出。格式宣告總是由%
字元開始 - 普通字元:普通字元即需要在輸出時原樣輸出的字元
- 格式宣告:格式宣告由
- 輸出表列:是程式需要輸出的一些資料,可以是常量、變數或表示式
printf 函式的一般形式可以表示為:
printf(引數1, 引數2, 引數3, ..., 引數n)
引數1是格式控制字串,引數2~引數n是需要輸出的資料。執行 printf 函式時,將引數2~引數n按引數1所指定的格式進行輸出。引數1是必須的,其他引數是可選的。
格式字元
在輸出時,對不同型別的資料要指定不同的格式宣告,而格式宣告中最重要的內容是格式字元。
d 格式符
用來輸出一個有符號的十進位制整數
在輸出時,按十進位制整型資料的實際長度輸出,正數的符號不輸出。
可以在格式宣告中指定輸出資料的域寬(所佔的列數)如%5d
指定輸出資料佔5列,輸出的資料顯示在此5列區域的右側。
若輸出 long(長整型)資料,在格式符 d 前加字母 l (代表 long)即%ld
若輸出 long long(雙長整型)資料,在格式符 d 前加字母 ll (代表 long long)即%lld
c 格式符
用來輸出一個字元
也可以指定域寬,方式同 d 格式符
一個整數,如果在 0~127 範圍中,也可以用%c
使之按字元形式輸出,在輸出前,系統會將該整數作為ASCII碼轉換成相應的字元。如果整數比較大,則把它的最後一個位元組的資訊以字元形式輸出
s 格式符
用來輸出一個字串
printf("%s", "CHINA");
輸出 CHINA
f 格式符
用來輸出實數(包括單、雙精度、長雙精度)以小數形式輸出
基本型,用%f
不指定輸出資料的長度,由系統根據資料的實際情況決定資料所佔的列數。
系統處理的方法一般是:實數中的整數部分全部輸出,小數部分輸出6位
例:用 %f 輸出實數,只能得到6位小數
//用 %f 輸出實數,只能得到6位小數
#include <stdio.h>
int main(void)
{
double a = 1.1;
printf("%f\n", a / 3);
return 0;
}
執行結果:
指定資料寬度和小數位數,用%m.nf
m是列數,n是小數位數
對最後一位採取四捨五入方法處理,即向上或向下取近似值
如果把小數部分指定為0,則不僅不輸出小數,而且小數點也不輸出
在用%f
輸出資料時要注意資料本身能提供的有效數字,如 float 型資料的儲存單元只能保證6位有效數字。double 型資料能保證15位有效數字
例:float 型資料的有效位數
//float 型資料的有效位數
#include <stdio.h>
int main(void)
{
double a = 1100;
printf("%f\n", a / 3);
return 0;
}
執行結果:
輸出的資料向左對齊,用%-m.nf
m是列數,n是小數位數,當資料長度不超過m時,資料向左靠,右端補空格
e 格式符
指定以指數形式輸出實數。
如果不指定輸出資料所佔的寬度和數字部分的小數位數,許多C編譯系統(如 Visual C++)會自動給出數字部分的小數位數為6位,指數部分佔5列(如e+002,其中"e"佔1列,指數符號佔1列,指數佔3列)數值按標準化指數形式輸出(即小數點前必須有且僅有1位非零數字)
%m.ne
形式指定寬度以及小數位數
e 也可以是 E,效果一致
i 格式符
作用同 d 格式符,按十進位制整型資料的實際長度輸出
一般習慣用%d
少用%i
o 格式符
以八進位制整數形式輸出
將記憶體單元中的各位的值(0或1)按八進位制形式輸出,因此輸出的數值不帶符號,即將符號位也一起作為八進位制數的一部分輸出
例如int a = -1; printf("%d\t%o\n", a, a);
輸出為-1 37777777777
八進位制整數是不會帶負號的
用%o
格式宣告可以得到儲存單元中的實際儲存情況
x 格式符
以十六進位制數形式輸出整數
例如int a = -1; printf("%d\t%o\t%x\n", a, a, a);
輸出為-1 37777777777 ffffffff
同樣可以用%lx
輸出長整型數,也可以指定輸出欄位的寬度,如%l2x
u 格式符
輸出無符號型資料,以十進位制整數形式輸出
g 格式符
輸出浮點數,系統自動選 f 格式或者 e 格式輸出,選擇其中長度較短的格式,不輸出無意義的0
格式宣告的一般形式可以表示為:% 附加字元 格式字元
l
m
n
就是“附加字元”,又稱為“修飾字元”,起補充宣告的作用
格式字元 | 說明 |
d\i | 以帶符號的十進位制輸出整數(正數不輸出符號) |
o | 以八進位制無符號形式輸出整數(不輸出前導符0) |
x,X | 以十六進位制無符號形式輸出整數(不輸出前導符),x 是小寫,X 是大寫 |
u | 以無符號十進位制形式輸出整數 |
c | 以字元形式輸出,只輸出一個字元 |
s | 輸出字串 |
f | 以小數形式輸出單、雙精度,隱含輸出6位小數 |
e,E | 以指數形式輸出實數,用 e 時指數以"e"表示(如1.2e+02)用 E 時指數以"E"表示(如1.2E+02) |
g,G | 選用 %f 或 %e 格式中輸出寬度較短的一種格式,不輸出無意義的0,用 G 時,若以指數形式輸出,則指數以大寫表示 |
l | 用於長整型整數,可加在格式符 d\o\x\u 前面 |
m(代表一個正整數) | 資料最小寬度 |
n(代表一個正整數) | 對實數,表示輸出 n 位小數,對字串,表示擷取的字元個數 |
- | 輸出的數字或者字元在域內向左靠 |
printf 函式輸出時,需要注意輸出物件的型別應與格式說明符匹配,否則將會出現錯誤
除了 X\E\G 外,其他格式字元必須用小寫字母
可以在 printf 函式中的“格式控制字串”內包含跳脫字元
用 scanf 函式輸入資料
scanf 函式的一般形式
scanf(格式控制, 地址列表)
“格式控制”同 printf 函式。“地址列表”是由若干個地址組成的表列,可以是變數的地址,或字串的首地址
scanf 函式中的格式宣告
與 printf 函式中的格式宣告類似,以 % 開始,以一個格式字元結束,中間可以插入附加的字元
格式字元 | 說明 |
d\i | 用來輸入有符號的十進位制整數 |
u | 用來輸入無符號的十進位制整數 |
o | 用來輸入無符號的八進位制整數 |
x,X | 用來輸入無符號的十六進位制整數(大小寫作用相同) |
c | 用來輸入單個字元 |
s | 用來輸入字串,將字串送到一個字元陣列中,在輸入時以非空白字元開始,以第一個空白字元結束,字串以串結束標誌 '\0' 作為其最後一個字元 |
f | 用來輸入實數,可以用小寫形式或者指數形式輸入 |
e,E,g,G | 與 f 作用相同,e 與 f\g可以互相替換(大小寫作用相同) |
字元 | 說明 |
l | 用於輸入長整型資料(可用 %ld %lo %lx %lu )以及 double 型資料(用 %lf %le ) |
h | 用於輸入短整型資料(可用 %hd %ho %hx ) |
域寬 | 指定輸入資料所佔寬度(列數)域寬應為正整數 |
* | 表示輸入項在讀入後不賦給相應的變數 |
使用 scanf 函式時應注意的問題
scanf 函式中的“格式控制”後面應當是變數地址,而不是變數名
如果在“格式控制字串”中除了控制宣告以外還有其他字元,則在輸入資料時在對應的位置上應輸入與這些字元相同的字元
在用 %c
格式宣告輸入字元時,空格字元和“跳脫字元”中的字元都作為有效字元輸入
輸入數字時,在兩個數字之間需要插入空格(或其他分隔符)以使系統能區分兩個數值
在連續輸入字元時,在兩個字元之間不要插入空格或其他分隔符(除非在 scanf 函式中的格式字串中有普通字元,這時在輸入資料時要在原位置插入這些字元)系統能區分兩個字元
在輸入數值資料時,如輸入空格、回車、Tab鍵或遇非法字元(不屬於數值的字元)認為該資料結束
字元資料的輸入輸出
除了可以用 printf 函式和 scanf 函式輸出和輸入字元外,C函式還提供了一些專門用遇輸入和輸出字元的函式
用 putchar 函式輸出一個字元
想從計算機向顯示器輸入一個字元,可以呼叫系統函式庫中的 putchar 函式(字元輸入函式)
putchar 函式的一般形式:putchar(c)
輸出字元變數 c 的值,顯然它是一個字元
putchar 函式既可以輸出能在顯示器螢幕上顯示的字元,也可以輸出螢幕控制字元
putchar(c)
中的c可以是字元常量、整型常量、字元變數或整型變數(其值在字元中的ASCII程式碼範圍內)
例:先後輸出 BOY 三個字元
//先後輸出 BOY 三個字元
#include <stdio.h>
int main(void)
{
char a = 'B', b = 'O', c = 'Y';
putchar(a);
putchar(b);
putchar(c);
putchar('\n');
return 0;
}
執行結果:
用 getchar 函式輸入一個字元
為了向計算機輸入一個字元,可以呼叫系統函式庫中的 getchar 函式(字元輸入函式)
getchar 函式的一般形式:getchar()
作用:從計算機終端(一般是顯示器的鍵盤)輸入一個字元,即計算機獲得一個字元
getchar 函式的值就是從輸入裝置得到的字元
getchar 函式只能接收一個字元。如果想輸入多個字元就要用多個 getchar 函式
在用鍵盤輸入資訊時,並不是在鍵盤上敲一個字元,該字元就立即送到計算機中去的。這些字元先暫存在鍵盤的緩衝器中,只有按了 Enter 鍵才把這些字元一起輸入到計算機中,然後按先後順序分別賦給相應的變數
執行 getchar 函式不僅可以從輸入裝置獲得一個可顯示的字元,而且可以獲得在螢幕上無法顯示的字元,如控制字元
用 getchar 函式得到的字元可以賦給一個字元變數或整型變數,也可以不賦給任何變數,而作為表示式的一部分,在表示式中利用它的值。
例:先用鍵盤輸入 BOY 然後再輸出到螢幕
//先後輸出 BOY 三個字元
#include <stdio.h>
int main(void)
{
char a = getchar();
char b = getchar();
char c = getchar();
putchar(a);
putchar(b);
putchar(c);
putchar('\n');
return 0;
}
執行結果: