C語言-資料型態與變數運算

資料型態

程式在執行的過程中需要許多的資訊,而這些資訊都儲存在記憶體空間中

而根據資訊的用途與所需空間的不同,所以訂定了資料型態的規範

資料型態分為

  • 整數:用來表示整數,其所佔的記憶體空間有可能因為編譯器而有所不同,可以使用unsigned修飾字讓有號整數變成無號整數

    • short (短整數,佔2位元組)
    • int (整數,佔4位元組)
    • unsigned (無號整數,佔4位元組)
    • long (長整數,佔4位元組)
    • long long int (長長整數,佔8位元組)
  • 浮點數:可以用來表示小數

    • float (單精度浮點數,佔4位元組,精度只到小數點以下7位)
    • double (雙精度浮點數,佔8位元組,精度只到小數點以下15位)
    • long double (長雙精度浮點數,佔16位元組)
  • 字元:字元編碼依ASCII表編成,因為所佔有空間小,也可以表達小範圍的整數

    • char (字元,佔1位元組)

以下為示範程式,用TDM-GCC 4.9.2編譯的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>

int main(void) {

printf("型態\t\t大小(bytes)\n");
printf("short\t\t%d\n", sizeof(short));
printf("int\t\t%d\n", sizeof(int));
printf("unsigned\t\t%d\n", sizeof(int));
printf("long\t\t%d\n", sizeof(long));
printf("long long\t%d\n", sizeof(long long));
printf("float\t\t%d\n", sizeof(float));
printf("double\t\t%d\n", sizeof(double));
printf("long double\t%d\n", sizeof(long double));
printf("char\t\t%d\n", sizeof(char));
return 0;

}

\t為跳脫字元,用來對齊下一個顯示位置

%d為格式指定碼,表示這個位置要放入整數,然後被後面sizeof的運算結果取代

sizeof的功能是取得該型態所佔的記憶體大小

以下為執行結果

型態            大小(bytes)
short           2
int             4
unsigned        4
long            4
long long       8
float           4
double          8
long double     16
char            1

以下為型別的範圍大小

型別 最大值 最小值
char 127 -128
short 32767 -32768
int 2147483647 -2147483648
unsigned 4294967296 0
long 2147483647 -2147483648
long long 9223372036854775807 -9223372036854775808
float $3.40282*10^{38}$ $1.17549*10^{-38}$
double $1.79769*10^{308}$ $2.22507*10^{-308}$
long double $1.18973*10^{4932}$ $3.3621*10^{-4932}$

變數

有了資料型態之後要怎麼把資料存在記憶體呢?答案是變數

變數簡單說就是一個代表某種資料型態且有名稱的記憶體空間

要使用變數之前,必須先宣告變數名稱跟資料型態,以下是變數宣告的範例

1
int num; // 宣告一個整數變數

‘=’是指定符號,也就是將某個變數代入某個值

1
2
score = 100;
level = 'A';

有些名稱是不能拿來當變數名稱的,稱為保留字,以下為保留字

保留字
char short int unsigned
long float double struct
union void enum signed
const volatile typedef auto
register static extern break
case continue default do
else for goto if
return switch while sizeof

通常變數命名都建議使用有意義的文字表明變數作用

例如age_of_student、price_of_goods,而不是a、b、c這種無意義的變數名稱

以下是變數宣告的示範程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <stdlib.h>

int main(){

int NT_dollar;
float discount;
char member_level;

printf("價錢\t\t折扣\t\t會員等級\n");
printf("%d\t\t%f\t%c\n",NT_dollar,discount,member_level);

NT_dollar = 1000;
discount = 0.2;
member_level = 'A';

printf("價錢\t\t折扣\t\t會員等級\n");
printf("%d\t\t%f\t%c\n",NT_dollar,discount,member_level);

return 0;

}

執行結果

價錢            折扣            會員等級
0               0.000000                
價錢            折扣            會員等級
1000            0.200000       A

現在的編譯器會很好心的在你宣告變數的時候指定初始值為0

就像上面的例子一樣,在變數剛宣告卻未指定內容的情況下,NT_dollar的內容為0

若使用老舊的編譯器有可能會出現以下結果

價錢            折扣            會員等級
2147315712        2293592        4199430
價錢            折扣            會員等級
1000            0.200000       A

可以看到未指定初始值的變數內容是不可預測的

初始值的設定就是在變數宣告的時候指定一個值給變數,例如:

1
2
int score = 100;
char level = 'A';

有時候你希望變數宣告之後就再不會變更內容,這時候就要在前面加關鍵字const,例如:

1
const float PI = 3.14159;

如果你試圖修改PI的值

1
PI = 3.14; 

你就會得到以下錯誤訊息

assignment of read-only variable ‘PI’

運算

算術運算

C語言除了提供加(+)、減(-)、乘(*)、除(/)以外,還提供餘除運算子(%)或者稱為模數運算子

這五個以數學運算為主的運算子稱為算術運算子

運算順序基本上是由左而右,先乘除後加減,可以加上括號表示運算的先後順序,例如:

1
printf("%d\n",1+2-3*4);

這樣結果是-9

而%這個運算子的功能是取出計算除法之後的餘數,例如:

1
printf("%d\n",9%6);

這樣結果是3

雖然數學運算簡單,但有一個情況要注意

就是計算結果會產生不同型態的時候,例如:

1
printf("%d\n", 10/3);

這樣結果並不是3.333333,而是3,因為10跟3都是整數,小數會被捨去

而為了顯示正確結果,還要使用%f格式(表示浮點數)以外,這是C的隱式型態轉換(Implicit type conversion)

在型態混雜算式中,長度較長的型態會變成目標型態,其他型態都會轉為目標型態,轉換過程稱為算術轉換(Arithmetic conversion)

也就是說,只要改成下列例子,結果就可以變成3.333333

1
printf("%f\n", 10.0/3);

而在指定動作中,左邊的數值會成為目標型態

也就是說,如果右邊的資料型態比目標型態的長度來得小,轉換過程不會有問題,例如:

1
2
int num = 10;
double number = num;

但是如果右邊的資料型態長度比較大,超出範圍的部分就會被捨去,例如:

1
2
double pi = 3.14;
int PI = pi; // 小數點會被捨去,只留下3

另外你也可以將變數轉換為指定型態,稱為強制轉型,例如

1
2
int number = 10;
printf("%f\n", (float)number / 3);

關係運算

數學中有比較的觀念,在C語言裡面則稱為關係運算子

有大於(>)、不小於(>=)、小於(<)、不大於(<=)、等於(==)以及不等於(!=)

以下是關係運算子的範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>

int main(){

printf("10 > 5\t\t%d\n", 10 > 5);
printf("10 >= 5\t\t%d\n", 10 >= 5);
printf("10 < 5\t\t%d\n", 10 < 5);
printf("10 <= 5\t\t%d\n", 10 <= 5);
printf("10 == 5\t\t%d\n", 10 == 5);
printf("10 != 5\t\t%d\n", 10 != 5);
return 0;

}

以下是執行結果,0表示False,1表示True

10 > 5          1
10 >= 5         1
10 < 5          0
10 <= 5         0
10 == 5         0
10 != 5         1

邏輯運算

在邏輯上有AND,OR、NOT運算

C也有提供邏輯運算子分別為AND(&&)、OR(||)及NOT(!)三個運算子

以下是邏輯運算的範例程式

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main(void) {

int num = 75;
printf("%d\n", (num > 70 && num < 80));
printf("%d\n", (num > 80 || num < 75));
printf("%d\n", !(num > 80 || num < 75));

return 0;

}

執行結果分別為1、0、1

值得注意的是在&&運算中,如果左邊的式子被判斷為False,即可判斷整個式子為False

||運算中,如果左邊的式子被判斷為True,即可判斷整個式子為True,則不判斷右邊的式子

位元與位移運算

在數位邏輯設計中,有AND、OR、NOT、XOR等運算,在C語言裡面稱為位元運算子

C語言提供AND(&)、OR(|)、NOT(!)、XOR(^)與一補數(~)等運算

以下為位元運算子範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>

int main(void) {

printf("AND運算:\n");
printf("0 AND 0\t\t%d\n", 0 & 0);
printf("0 AND 1\t\t%d\n", 0 & 1);
printf("1 AND 0\t\t%d\n", 1 & 0);
printf("1 AND 1\t\t%d\n\n", 1 & 1);

printf("OR運算:\n");
printf("0 OR 0\t\t%d\n", 0 | 0);
printf("0 OR 1\t\t%d\n", 0 | 1);
printf("1 OR 0\t\t%d\n", 1 | 0);
printf("1 OR 1\t\t%d\n\n", 1 | 1);

printf("XOR運算:\n");
printf("0 XOR 0\t\t%d\n", 0 ^ 0);
printf("0 XOR 1\t\t%d\n", 0 ^ 1);
printf("1 XOR 0\t\t%d\n", 1 ^ 0);
printf("1 XOR 1\t\t%d\n\n", 1 ^ 1);

printf("NOT運算:\n");
printf("NOT 0\t\t%d\n", !0);
printf("NOT 1\t\t%d\n", !1);

printf("一補數運算:\n");
printf("~0\t\t%d\n", ~0);

return 0;

}

以下為執行結果

AND運算:
0 AND 0         0
0 AND 1         0
1 AND 0         0
1 AND 1         1

OR運算:
0 OR 0          0
0 OR 1          1
1 OR 0          1
1 OR 1          1

XOR運算:
0 XOR 0         0
0 XOR 1         1
1 XOR 0         1
1 XOR 1         0

NOT運算:
NOT 0           1
NOT 1           0

一補數運算:
~0              -1

另外位移運算在計算機概論的邏輯運算中有提到

C語言提供的語法為<<(左移)、>>(右移),採算術位移

以下為位移運算子的範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

int main(void) {

printf("10>>1\t%d\n",10>>1);
printf("10<<1\t%d\n",10<<1);

printf("-20>>1\t%d\n",-20>>1);
printf("-20<<1\t%d\n",-20<<1);

return 0;

}

以下為執行結果

10>>1   5
10<<1   20
-20>>1  -10
-20<<1  -40

遞增、遞減運算

程式在運算裡面最常做的事情是+1或-1,例如數東西

而C語言提供了遞增(++)跟遞減(–)運算子方便撰寫程式

1
2
3
int i = 0;
printf("%d\n", ++i);// ++i 等同於 i = i + 1
printf("%d\n", --i);// --i 等同於 i = i - 1

以上三行的執行結果是1與0

但是這兩個運算子有個特性要注意,變數放在前後會影響運算順序

1
2
3
4
5
6
int i = 0;
int num = 0;
num = ++i; // 相當於i = i + 1; num = i;
printf("%d\n" ,num);
num = --i; // 相當於i = i - 1; num = i;
printf("%d\n" ,num);

上面這段程式碼的執行結果是1與0

1
2
3
4
5
6
int i = 0;
int num = 0;
num = i++; // 相當於num = i; i = i + 1;
printf("%d\n", num);
num = i--; // 相當於 num = i; i = i - 1;
printf("%d\n", num);

上面這段程式碼的執行結果是0與1

也就是說如果變數在左邊,遞增的運算順序會小於指定

變數如果在右邊,遞增的運算順序會大於指定

指定運算

除了我們看過的’=’以外,還有下列幾個運算子,都是為了方便撰寫程式而產生的

運算子 例子 說明
+= a += b a = a + b
-= a -= b a = a - b
*= a *= b a = a * b
/= a /= b a = a / b
%= a %= b a = a % b
&= a &= b a = a & b
|= a |= b a = a | b
^= a ^= b a = a ^ b
<<= a <<= b a = a << b

= | a >>= b | a = a >> b

參考

  1. C語言
  2. 資料型態(Data type
  3. 字面常量(Literal Constant)
  4. 變數(Variable)
  5. 算術(Arithmetic)運算、型態轉換(Type conversion)
  6. 關係(Relational)運算、條件(Conditional)運算
  7. 邏輯(Logical)運算、位元(Bitwise)運算
  8. 遞增(Increment)、遞減(Decrement)、指定(Assignment)運算