Back
Clang & Wasm 教學

C 語言基礎(include、define、變數與資料型態)


課程目標

  • 理解預處理指令: 學會使用 #include 引入標頭檔案與 #define 定義常數與巨集,並了解其在編譯前的作用。
  • 掌握變數與資料型態: 能夠宣告各種基本資料型態的變數,包括整數、浮點數、字元與字串,並熟悉其使用方式與範圍。
  • 認識基本輸入輸出: 瞭解如何使用 printf()scanf() 進行簡單的資料輸出與輸入(可作為後續課程的鋪墊)。

第1部份

1. 預處理指令

1.1 #include 指令

  • 用途:
    用來引入外部函式庫或自訂標頭檔,讓程式能夠使用已有的函數與定義。
  • 常見用法:
    • #include <stdio.h>:引入標準輸入/輸出函式庫,提供 printf()scanf() 等常用函數。
    • #include "my_header.h":引入專案中自訂的標頭檔,通常包含常數、函式原型或資料結構定義。
  • 附加說明:
    在自訂標頭檔中建議加入標頭防護(Header Guard),例如:
    #ifndef MY_HEADER_H
    #define MY_HEADER_H
    // 內容...
    #endif
    
    這樣可以避免同一個標頭檔被重複引入,減少編譯錯誤。

1.2 #define 指令

  • 用途:
    用來定義常數或建立簡單的巨集(macro),在編譯前將指定符號替換為對應的值或程式碼。

  • 範例:定義常數

    #define MAX_LENGTH 100
    printf("Max length: %d\n", MAX_LENGTH);
    

    這裡 MAX_LENGTH 在編譯時會被替換成 100

  • 範例:定義巨集

    #define add(a, b) ((a) + (b))
    printf("Result: %d\n", add(3, 4));
    

    注意: 使用括號包住參數與整個運算式,可以避免運算順序的錯誤,確保巨集能正確執行。


2. 變數與資料型態

2.1 基本概念

  • 變數:
    在 C 語言中,變數用於儲存資料,每個變數在宣告時必須指定其資料型態。
  • 資料型態:
    決定變數能儲存哪種類型的資料以及其可能的範圍,常用的有整數、浮點數、字元與字串。

2.2 常見資料型態與宣告範例

  • 整數型態:
    int num = 5;               // 整數
    unsigned int amount = 36;  // 無號整數
    
  • 浮點型態:
    float pi = 3.14159;        // 單精度浮點數
    double precisePi = 3.141592653589793; // 雙精度浮點數
    
  • 字元型態:
    char letter = 'A';         // 單一字元
    
  • 字串:
    字串以字元陣列形式儲存:
    char str[] = "Hello, C!";
    

2.3 資料型態範圍(參考 <stdint.h>

資料型態 等效型態 範圍
char int8_t -2^7 ~ 2^7-1
unsigned char uint8_t 0 ~ 2^8-1
short int16_t -2^15 ~ 2^15-1
unsigned short uint16_t 0 ~ 2^16-1
int int32_t -2^31 ~ 2^31-1
unsigned int uint32_t 0 ~ 2^32-1
long int64_t -2^63 ~ 2^63-1
unsigned long uint64_t 0 ~ 2^64-1
float float 約 -3.4E+38 ~ 3.4E+38
double double 約 -1.7E+308 ~ 1.7E+308
  • 附註:
    使用 <stdint.h> 可以讓我們指定固定大小的整數型態,這對於跨平台程式設計尤為重要。

3. 基本輸入與輸出操作簡介

雖然本堂課的重點在於預處理與變數宣告,但了解基本的輸入輸出操作對後續課程非常重要。

3.1 輸出操作— printf

  • 功能:
    用於格式化並輸出資料到螢幕。
  • 範例:
    printf("Hello, World!\n");
    printf("The number is: %d\n", num);
    
  • 注意:
    根據資料型態選用正確的格式符,例如 %d 用於整數,%f 用於浮點數,%c 用於字元,%s 用於字串。

3.2 輸入操作— scanf

  • 功能:
    用於從鍵盤讀取格式化資料,需傳入變數的地址。
  • 範例:
    int num1, num2;
    printf("Enter two integers: ");
    scanf("%d %d", &num1, &num2);
    
  • 提示:
    檢查 scanf() 的回傳值,以確保輸入成功,這是撰寫穩健程式的重要技巧。

4. 範例程式:簡易變數宣告與輸出

以下範例綜合展示了 #include#define、變數宣告與基本輸出:

#include <stdio.h>

// 定義常數
#define MAX_VALUE 100

int main() {
    // 變數宣告
    int num = 42;
    float pi = 3.14159;
    char letter = 'C';
    char greeting[] = "Hello, C Language!";

    // 輸出變數內容
    printf("Number: %d\n", num);
    printf("Pi: %f\n", pi);
    printf("Letter: %c\n", letter);
    printf("Greeting: %s\n", greeting);
    printf("Max value (from define): %d\n", MAX_VALUE);

    return 0;
}
  • 討論重點:
    • 觀察 #define 如何將符號 MAX_VALUE 替換成具體數值。
    • 學習如何依據資料型態正確地使用不同格式符。

第2部份

1. 輸出操作詳解— printf()

1.1 格式化字串與格式符

  • 基本格式符:

    • %d:輸出整數。
    • %f:輸出浮點數(預設輸出小數點後6位)。
    • %c:輸出單一字元。
    • %s:輸出字串。
  • 範例:

    printf("整數:%d\n", 42);
    printf("浮點數:%f\n", 3.14159);
    printf("字元:%c\n", 'A');
    printf("字串:%s\n", "Hello, C!");
    

1.2 格式化細節

  • 可使用修飾符控制輸出寬度與精度,例如 %8.2f 表示輸出總寬度8,且小數點後2位。
  • 學生可嘗試修改格式,觀察輸出效果的不同。

2. 輸入操作詳解— scanf()

2.1 基本語法與使用方式

  • 基本語法:
    scanf("格式化字串", &變數);
    
  • 關鍵點:
    • 必須傳入變數的地址(例如 &num)。
    • 格式化字串必須與變數型態相符。

2.2 輸入錯誤處理

  • 檢查回傳值:
    • scanf() 會回傳成功讀取的變數個數。若回傳值不符預期,代表輸入錯誤。
    • 範例:
      int num;
      printf("請輸入一個整數:");
      if (scanf("%d", &num) != 1) {
          printf("輸入錯誤!\n");
      }
      
  • 練習討論:
    • 學生應討論如何在錯誤輸入後給予適當提示,並可能要求使用者重新輸入。

2.3 注意,windows 下中文可能出現亂碼,請依照以下程式碼修正

#include <stdio.h>

#ifdef _WIN32 //判斷windoes
    #include <windows.h>
#endif

int main(void) {

    #ifdef _WIN32 //判斷windoes 
    // 輸出中文亂碼修正
    SetConsoleOutputCP (65001);
    #endif

    printf("hello clang ㄏㄏ!\n");
    return 0;
}

或者用在終端機數入

chcp 65001

3. 綜合範例:計算橢圓面積

3.1 程式說明

  • 目的:
    利用 scanf() 讀取使用者輸入的兩個浮點數(代表橢圓的長軸與短軸),使用預先定義的巨集計算橢圓面積,再透過 printf() 輸出結果。
  • 關鍵概念:
    • 巨集 calculate_ellipse_area(ra, rb) 使用括號確保運算順序正確。
    • 輸入錯誤處理能提升程式穩定性。

3.2 範例程式

#include <stdio.h>

#define PI 3.14159
#define calculate_ellipse_area(ra, rb) ((ra) * (rb) * (PI))

int main() {
    float axis1, axis2;
    
    printf("請輸入橢圓的長軸與短軸(以空格分隔):");
    if (scanf("%f %f", &axis1, &axis2) != 2) {
        printf("輸入錯誤!\n");
        return 1;
    }
    
    printf("橢圓面積為:%f\n", calculate_ellipse_area(axis1, axis2));
    return 0;
}

3.3 編譯與執行

  • 使用 Clang 編譯器:
    clang -o ellipse ellipse.c
    
  • 執行程式:
    ./ellipse
    
  • 學生可藉由修改程式、重新編譯與執行,加深對輸入輸出及巨集運算的理解。

第3部份


1. 運算子概述

1.1 算術運算子

  • 基本運算子:
    +-*/%(取餘數)
  • 範例:
    int a = 10, b = 3;
    int sum = a + b;         // 加法:13
    int diff = a - b;        // 減法:7
    int prod = a * b;        // 乘法:30
    int quot = a / b;        // 除法:3 (整數除法)
    int rem = a % b;         // 餘數:1
    

1.2 賦值與自增/自減運算子

  • 賦值運算子:
    =+=-=*=/=%=
  • 自增/自減:
    ++--
  • 範例1:
    int x = 5;
    x += 3;      // x 現在為 8 等同 x = x + 3
    x++;         // x 現在為 9 等同 x = x + 1
    
  • 範例2:
    int x = 5;
    int y;
    y = x++;    // x 現在為 6;  y 現在為 5
    y = ++x;    // x 現在為 7;  y 現在為 7
    

1.3 關係與邏輯運算子

  • 關係運算子:
    ==!=><>=<=
  • 邏輯運算子:
    &&(且)、||(或)、!(非)
  • 範例:
    int m = 10, n = 20;
    if ((m < n) && (n != 0)) {
        printf("條件成立\n");
    }
    else {
        printf("條件不成立\n");
    }
    

1.4 位元運算子

  • 常用位元運算子:
    &(位元且)、|(位元或)、^(位元互斥)、~(位元非)、<<(左移)、>>(右移)
  • 範例:
    unsigned int num = 5;             // 二進位:0000 0101
    unsigned int shifted = num << 1;  // 結果:10 (0000 1010)
    

2. 表達式與運算子優先順序

2.1 運算子優先順序

  • 運算子在複雜表達式中有固定的優先順序。例如,乘法與除法的優先順序高於加法與減法。
  • 範例:
    int result = 3 + 4 * 2; // 結果為 11,而非 (3+4)*2 = 14
    
  • 使用括號:
    • 為避免混淆,建議使用括號明確指定計算順序。
    int result = (3 + 4) * 2; // 結果為 14
    

2.2 表達式計算示例

  • 分析以下表達式:
    int a = 5, b = 2, c = 3;
    int result = a + b * c - (a - c) / b;
    
    • 先計算 b * c(a - c),再依據運算子優先順序進行後續運算。

3. 型態轉換(Type Casting)

3.1 隱性與顯性型態轉換

  • 隱性轉換:
    編譯器自動將一種型態轉換為另一種,例如將整數轉換為浮點數進行運算。
  • 顯性轉換:
    使用強制型態轉換符號 (type) 明確指定轉換方式,避免不預期的結果。

3.2 型態轉換範例

  • 整數除法問題:
    int a = 7, b = 2;
    float result = a / b;  // 結果為 3.000000,因為 7/2 為整數除法
    
  • 使用顯性轉換:
    float result = (float)a / b;  // 結果為 3.500000
    

轉換範例表

類型 轉換後類型 範例
int + float float 5 + 2.5 → 5.0 + 2.5 = 7.5
char + int int 'A' + 1 → 65 + 1 = 66
short + int int 1000 + 2000 → 3000
int / int int 10 / 4 → 2
int / float float 10 / 4.0 → 2.5
char 傳遞到函數 int printType('A') → printType(65)

4. 綜合範例:計算圓的面積與周長

4.1 程式說明

  • 目的:
    利用運算子、表達式及型態轉換,計算圓的面積與周長,並正確輸出結果。
  • 公式:
    • 面積:A = PI * r * r
    • 周長:C = 2 * PI * r
    • 其中 r 為半徑。

4.2 範例程式

#include <stdio.h>

#define PI 3.14159

int main() {
    float radius;
    
    printf("請輸入圓的半徑:");
    if (scanf("%f", &radius) != 1) {
        printf("輸入錯誤!\n");
        return 1;
    }
    
    // 計算面積與周長,使用顯性轉換確保運算精確
    float area = PI * radius * radius;
    float circumference = 2 * PI * radius;
    
    printf("圓的面積為:%f\n", area);
    printf("圓的周長為:%f\n", circumference);
    
    return 0;
}

5. 課堂互動與練習

  • 練習題目: 請撰寫一個 C 程式,要求使用者分別輸入圓柱體的半徑與高度,計算表面積與體積。

6. 本堂課小結

  • 運算子與表達式:
    透過本堂課學習了各類運算子及其優先順序,並理解了如何利用括號明確指定計算順序。

  • 型態轉換:
    掌握了隱性與顯性型態轉換的概念,學會在需要時使用 (type) 進行強制轉換,確保運算結果的精確性。

  • 綜合應用:
    通過計算圓的面積與周長的範例,整合了運算子、表達式與型態轉換的知識,並鞏固了基本運算的概念。

SNPQ © 2025