iT邦幫忙

1

二、三天學一點點 C:來! 從Hello World到資料轉換(1)

c
  • 分享至 

  • xImage
  •  

🧱 從Hello World到資料型態

在學習 C 語言時,理解其基本語法結構是非常重要的一步。以下這段範例程式碼提供了清楚的入門示範,其中包含了資料型態、輸出格式控制符號(format specifier)、ASCII 編碼的運用、與型別所占記憶體大小的基本介紹。

第一部分:C 語言程式的基本骨架

讓我們從一個經典的 "Hello, World!" 程式開始,解析其組成:

#include<stdio.h>

int main() {
    printf("Hello, World!");
    return 0;
}
  1. #include<stdio.h>:引入標準函式庫

    • #include 是一個前置處理器指令 (Preprocessor Directive)。前置處理器是 C 編譯過程的第一個階段,它會在實際編譯原始碼之前處理這些指令。

    • <stdio.h>:這是 C 語言的標準輸入輸出標頭檔 (Standard Input/Output Header File)。它包含了我們常用函式的宣告,例如 printf() (用於螢幕輸出) 和 scanf() (用於鍵盤輸入)。

    • 為何需要引入? C 語言本身的核心功能非常精簡。許多常用的功能,如螢幕印出文字、讀取使用者輸入等,都是以函式庫的形式提供的。#include <stdio.h> 的作用就像是告訴編譯器:「我接下來的程式碼中,可能會用到 stdio.h 裡面定義好的功能,請幫我把這些功能的宣告資訊準備好。」如果沒有引入這個標頭檔,編譯器在遇到 printf() 這類函式時,就會因為找不到其定義而產生錯誤。

  2. int main() { ... }:程式的入口——主函式

    • 在 C 語言中,main() 函式是一個非常特殊的存在,它是程式執行的起點。作業系統在執行您的 C 程式時,會首先尋找並呼叫這個 main() 函式。

    • int:這是 main() 函式的回傳型態 (Return Type),代表 main() 函式執行完畢後,會回傳一個整數值給作業系統。這個回傳值通常用來表示程式是否正常結束。依照慣例,回傳 0 代表程式執行成功,非零值則代表發生了某些錯誤。

    • main:這是函式的名稱,固定寫為 main。

    • ():函式名稱後面的括號是用來放置參數 (Parameters) 的地方。在這個範例中,main() 函式沒有接收任何參數,所以括號是空的。

    • { ... }:大括號定義了函式主體 (Function Body) 的範圍,也就是 main() 函式實際執行的程式碼都寫在這對大括號之間。

    • 標準 C 語言規範中,int main() 是最被推薦且廣泛接受的寫法。有些舊的或非標準的編譯器可能允許 void main(),表示 main 函式不回傳任何值。然而,這並不符合 C 語言標準,可能會導致在某些編譯器或作業系統上出現警告或非預期的行為。因此,強烈建議始終使用 int main()

    • main 函式也可以接收參數,常見的寫法是 int main(int argc, char *argv[]),這允許程式在執行時從命令列接收參數,但這是更進階的主題。

  3. printf("Hello, World!");:在螢幕上顯示訊息

    • printf()stdio.h 中定義的一個函式,其名稱是 "print formatted" 的縮寫,意思是「格式化輸出」。

    • "Hello, World!":這是一個字串字面量 (String Literal),也就是您想要在螢幕上顯示的文字內容。在 C 語言中,字串必須用雙引號 " 包起來。

    • ; (分號):在 C 語言中,分號代表一個陳述 (Statement) 的結束。大部分的 C 語言程式碼行都需要以分號結尾。

  4. return 0;:程式的結束與回傳值
    這行程式碼代表 main() 函式執行結束,並回傳一個值 0 給作業系統。
    return:這是一個關鍵字,用於結束目前函式的執行,並將一個值回傳給呼叫者。在 main() 函式中,呼叫者就是作業系統。
    0:這是回傳給作業系統的整數值。如前所述,0 通常表示程式成功執行。

第二部分:資料型態與 printf 的進階應用

現在,我們來看一段更複雜的程式碼,它展示了 C 語言中不同的資料型態以及 printf 函式的更多用法:

#include<stdio.h>

int main() {
    int age = 35; // 整數變數
    printf("年齡是:%d\n", age);
    printf("age 變數的大小是 %d 位元組 (bytes)。\n", sizeof(age));

    float salary = 56.5; // 浮點數變數
    printf("薪水是:%.1f\n", salary);
    //這表示輸出浮點數時,只顯示到小數點後第一位。. 後面的數字指定了小數點後的位數。

    char unit = 'A'; // 字元變數
    printf("unit 字元的十進制 ASCII 碼是:%d\n", unit);

    unit = 98; // 賦予字元變數新的 ASCII 值
    printf("ASCII 碼 98 對應的字元是:%c\n", unit);

    printf("這是一段直接輸出的文字:abcdef\n");

    return 0;
}
  1. 變數 (Variables) 與資料型態 (Data Types)
    在程式設計中,變數就像是帶有名字的容器,可以用來儲存資料。每種變數都有一個資料型態,它決定了變數可以儲存哪種類型的資料,以及可以對這些資料進行哪些操作。
  • int age = 35;

    • int:這是整數 (Integer) 資料型態,用於儲存沒有小數點的數字,例如 -1, 0, 100。
    • age:這是我們宣告的變數名稱。
    • =:這是賦值運算子 (Assignment Operator),用於將右邊的值存入左邊的變數中。
    • 35:這是賦予給 age 變數的初始值。
    • printf("年齡是:%d\n", age);
      • %d:這是 printf 函式中的格式控制符號 (Format Specifier),用於指示 printf 在這個位置輸出一 個十進制整數。printf 會取用逗號後面的第一個參數 (此處為 age) 的值,並以整數形式印出。
      • \n:這是一個跳脫序列 (Escape Sequence),代表換行符 (Newline Character)。它會使游標移到下一行的開頭。
  • printf("age 變數的大小是 %d 位元組 (bytes)。\n", sizeof(age));

    • sizeof():這是一個運算子 (Operator),它會回傳其運算元 (可以是變數或資料型態) 在記憶體中所佔用的空間大小,單位是位元組 (bytes)。int 型態的大小在不同的系統和編譯器上可能不同,但通常是 4 個位元組。
  • char unit = 'A';

    • char:這是字元 (Character) 資料型態,用於儲存單一字元,例如 'A', 'b', '!', '7'。注意,字元值必須用單引號 ' 包起來。
    • printf("unit 字元的十進制 ASCII 碼是:%d\n", unit);
      • 當我們使用 %d (整數格式) 來輸出一個 char 型態的變數時,printf 會印出該字元對應的 ASCII (美國資訊交換標準碼) 值的十進制表示。字元 'A' 的 ASCII 十進制值是 65,所以這行會印出 unit 字元的十進制 ASCII 碼是:65。
  • unit = 98;

    • 這裡我們將整數 98 賦值給 char 型態的變數 unit。C 語言允許這樣做,因為字元在內部實際上是以其 ASCII (或其他字元集) 的數值來儲存的。數字 98 對應的 ASCII 字元是 'b'。

    • printf("ASCII 碼 98 對應的字元是:%c\n", unit);

      • %c:這是用於輸出單一字元的格式控制符號。printf 會將 unit 變數中儲存的數值 (98) 解釋為其對應的 ASCII 字元,並印出該字元。所以這行會印出 ASCII 碼 98 對應的字元是:b。
  1. printf 函數的格式控制符號
    • printf 函式使用格式控制符號來指定輸出的格式。這些符號通常以 % 開頭。

    • 常見的控制符號:

      • %d 或 %i:用於輸出十進制整數 (int)。
      • %f:用於輸出浮點數 (float 或 double)。
      • %c:用於輸出單一字元 (char)。
      • %s:用於輸出字串 (字元陣列)。
      • %p:用於輸出指標位址。
      • %%:用於輸出一個 % 符號本身。
      • \n:換行符。
      • \t:水平定位字元 (Tab)。
  2. ASCII 與 char 的關係
    電腦內部儲存和處理字元時,並不是直接儲存字元的圖形,而是儲存代表該字元的數字編碼。ASCII (American Standard Code for Information Interchange) 是最早期且廣泛使用的字元編碼標準之一。
  • ASCII 為每個常用的英文字母 (大小寫)、數字、標點符號以及一些控制字元 (如換行符、Tab鍵) 都分配了一個唯一的數字,範圍通常是 0 到 127。

  • char 型態的變數在記憶體中儲存的就是這些數字編碼。

  • 當你寫 char c = 'A'; 時,實際上是將 'A' 對應的 ASCII 值 (即 65) 存入了變數 c。

  • 當你使用 printf("%c", c); 時,printf 會查找 c 中儲存的數字 (65) 在 ASCII 表中對應的字元 ('A') 並顯示出來。

  • 當你使用 printf("%d", c); 時,printf 則直接將 c 中儲存的數字 (65) 以十進制整數的形式顯示出來。


常見資料型態比較表

每種資料型態都有其特定的屬性:

  • 是否有號 (Signed / Unsigned):

    • signed (有號):可以表示正數、負數和零。例如 int 預設就是有號的,可以寫成 signed int。
    • unsigned (無號):只能表示非負數 (零和正數)。如果一個整數變數確定不會儲存負值,可以將其宣告為 unsigned,這樣它可以表示更大的正數範圍 (因為不需要用一位元來表示正負號)。例如 unsigned int。
    • char 型態比較特殊:它究竟是 signed char 還是 unsigned char 取決於編譯器的實作。如果需要明確,應直接寫出 signed char 或 unsigned char。
  • 大小 (Size):
    指該資料型態在記憶體中所佔用的位元組數。可以使用 sizeof() 運算子來獲取。

  • 數值範圍 (Range):
    指該資料型態可以表示的最小和最大數值。範圍取決於其大小和是否有號。


常見資料型態總覽表

類別 資料型態 有號/無號 記憶體大小 (byte) 數值範圍 (概略)
整數 short 有號 2 -32,768 ~ 32,767
整數 int 有號 4 -2,147,483,648 ~ 2,147,483,647
整數 long 有號 4 或 8(視系統而定) 約 -2^31 ~ 2^31-1 或更大
整數 long long 有號 8 約 -9.2×10^18 ~ 9.2×10^18
整數 unsigned short 無號 2 0 ~ 65,535
整數 unsigned int 無號 4 0 ~ 4,294,967,295
整數 unsigned long 無號 4 或 8 約 0 ~ 4,294,967,295 或更大
整數 unsigned long long 無號 8 約 0 ~ 1.8×10^19
字元 char 有號/無號 1 -128 ~ 127 / 0 ~ 255
浮點數 float 有號 4 約 ±3.4E±38(約 7 位有效數字)
浮點數 double 有號 8 約 ±1.7E±308(約 15~16 位有效數字)

C 語言中的型別轉換

在 C 語言中,型別轉換(type casting)是程式設計中一個非常重要的概念,尤其當我們處理不同資料型態之間的轉換時,可能會產生預期內或意料外的結果。以下的範例程式碼展示了各種不同的型別轉換情況,並說明其背後的轉換規則與潛在風險。

#include<stdio.h>

int main() {
    int a = 15;
    short b = (short)a;
    printf("%d\n", b);

    short c = 200;
    int d = (int)c;
    printf("%d\n", d);

    int e = 32769;
    short f = (short)e;
    printf("%d\n", f); // 溢出

    int g = -55;
    unsigned short h = (unsigned short)g;
    printf("%u\n", h); // 溢出

    float f_1 = 15.5;
    double f_2 = (double)f_1;
    printf("%.3f\n", f_2);

    double f_3 = 3.5e38;
    float f_4 = (float)f_3;
    printf("%f\n", f_4);
}

型別轉換概念

C 語言支援兩種型別轉換:

  1. 隱式轉換(implicit conversion):當兩種不同型別的值在運算中被使用時,編譯器會自動進行型別提升(promotion)。例如:int 轉為 float
  2. 顯式轉換(explicit conversion):又稱為「強制轉型」(type casting),語法為 (目標型別)變數名稱。例如:(short)a 表示將整數 a 強制轉換成 short 型態。

整數型別之間的轉換

int a = 15;
short b = (short)a;

這裡將 int 轉為 short,由於值 15 在 short 可表示的範圍內(-32768 ~ 32767),所以轉換後數值保持不變。

short c = 200;
int d = (int)c;

這是小型資料型態轉為大型型別的安全轉換,short 轉成 int,值仍為 200,這是沒有資訊損失的升階(promotion)。

int e = 32769;
short f = (short)e;

這一行展示了**溢出(overflow)**的情況。32769 超出了 short 所能表示的最大值(32767),因此強制轉型時會導致值「環繞」回負數,結果會是一個看似亂數的負整數(通常為 -32767)。這也說明了型別轉換若發生於超出目標型別表示範圍,將會發生資料損失。

int g = -55;
unsigned short h = (unsigned short)g;

這裡是將負整數轉成無號整數,也是一種典型的溢出情況。因為 unsigned short 不能表示負數,結果會以二進位補數方式解讀,輸出為一個大的正整數,例如 65536 - 55 = 65481。這是「位元模式不變,但詮釋方式不同」的情形。

浮點數型別的轉換

float f_1 = 15.5;
double f_2 = (double)f_1;

這是從 float 轉為 double 的情況,由於 double 精度較高,這是一種安全轉型(promotion),原本 float 的值可以完整儲存在 double 中。

double f_3 = 3.5e38;
float f_4 = (float)f_3;

這行使用了科學記號 3.5e38,等同於 3.5 × 10^38。這超過了 float 可表現的最大數值(約 3.4 × 10^38),因此發生了溢出或近似誤差,可能顯示為 inf 或近似值,這取決於平台與編譯器的實作。

總結:型別轉換須知

  • 若轉換後的型別能夠完全容納原本的數值,則不會出現資料損失。
  • 將大型型別轉為小型型別時,必須小心溢出與誤差。
  • 無號與有號型別之間的轉換,應特別注意負值的行為。
  • 浮點數轉換需關注精度與範圍。

了解這些規則能幫助我們寫出更安全與可預測的 C 程式。

結語

透過這個範例程式碼,我們學會了 C 語言中變數宣告、資料型態、格式控制符、ASCII 編碼與記憶體大小的基礎概念、型別轉換。掌握這些內容,對未來學習更進階的運算、邏輯控制與函式撰寫有重要幫助。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言