C++科學計算的入門教室

您將學習一些有關 C++ 語言特性的基本概念,這些概念可能是您曾經聽過的常見術語,以及 C++ 的優勢和劣勢。

按照電腦作業系統的不同,您將學習如何設定 C++ 的開發環境。

您還將學習如何編輯、編譯和運行第一個 C++ 程式。本章節還包含有關變數以及將資料輸入和輸出程式的簡單方法的。

最後,開始熟悉 C++ 語言常用的基本資料型態,雖然種類繁多,但卻是相關重要的基礎觀念喔。

C++ 簡介

  • C++ 是由 AT&T Bell 實驗室的 Bjarne Stroustrup 博士及其同事於80年代在 C 語言的基礎上開發成功而誕生。

  • C++ 語言是一門經典、靈活、功能強大、野心勃勃的計算機程式語言,但也是公認具有一定學習難度的電腦程式語言。

  • 即便是那些不使用 C++ 語言進行開發的職業,很多也要求求職者具備 C++ 程式功力,究其原因,主要就是因為凡是對 C++ 語言開發有良好駕馭能力的人,整體開發實力明顯要比從未接觸過 C++ 語言編程的開發者強出許多。

  • C 語言為 C++ 的子集合:可視為 C 語言為 C++ 語言的一部分。

  • 具低階與高階程式語言特性。

    • 可直接存取記憶體位址,進行位元操作:位元運算子(bitwise operator)。

    • 也可以用來開發系統軟體。

  • 執行速度快。

  • C++ 在眾多產業領域運用廣泛,也是最歷久不衰的程式語言。

C++ 起源與特性

  • C++(物件導向)為編譯式語言,其為 C 語言(過程導向)的增強版。

    • 加入「類別(class)」、「虛函數(virtual function)」、「運算子重載(operator overloadding)」、「模版(template)」等特性。

    • C++ 是一種『物件導向』語言。

      • 物件導向語言與非物件導向語言有什麼不同呢?根本上,這是因為語言的基本單位是物件或類別:

        • 將相關功能和資料結合在一起的實體。
  • 1998年,C++ 標準委員會正式發佈第一個C++標準,此版本被認為「標準 C++」,又稱「C++ 98」(1.0)。

  • 2003年發布 C++ 標準第二版,也叫「C++ 03」。

  • 2011年,新的 C++ 標準正式發佈,稱「C++ 11」(2.0)。

  • C++98 版本以及之前的版本,一般稱為『傳統 C++』

  • C++11 版本之後,一般稱為『現代 C++』

電腦開發環境建議

Windows

  1. Visual Studio 2022

    • 因需要 Visual Studio C++ 編譯器(Microsoft Visual C++,簡稱 MSVC),故建議安裝。否則需安裝其他 C++編譯器(如 MinGW-w64,乃 Windows 版本的 GNU Compiler Collection(GCC)。其提供一個在Windows上使用的 GNU工具鏈,包括C++編譯器)。

    • Visual Studio 是 Microsoft 官方提供的整合開發環境(IDE),適合在Windows電腦上進行 C++ 程式開發。

    • Visual Studio 2022 是最新版本,支援 Windows 11。

    • 提供豐富的功能,包括程式碼編輯、調試、自動完成、視覺化設計和內建的 CMake 支援。

    • Visual Studio 2022 還支援許多擴展,可擴展其功能,且社區版是免費的,適用於大多數開發者。

    • 安裝過程中,記得勾選 C++ 工作負載所需的核心功能,以確保安裝 Visual Studio C++ 編譯器(MSVC)。

  2. Visual Studio Code(課程採用)

    • Visual Studio Code(VS Code)是一個輕量級的代碼編輯器。

    • 可透過安裝 C/C++ 與 CMake 相關延伸模組,可以使 VS Code 成為一個強大的 C++ 開發工具。

    • VS Code 是免費、開源的,且社群與延伸模組生態相當活躍。

  3. CMake

    • CMake 是一個用於自動生成跨平台應用程式的建構(Build)工具。

    • 可管理 C++ 或其他程式語言專案的構建過程。

    • 使用 CMake,可在不同的作業系統上產生相對應的構建文件,例如 Makefile(用於 Linux 和 macOS)或 Visual Studio 專案建構文件(用於 Windows)。

    • 在不同作業系統平台上的專案能夠保持一致性且易於管理。

    • 安裝 CMake:

      • 下載 CMake 安裝程式:

      • 執行安裝程式:

        • 雙擊下載的安裝執行檔,接著按照安裝步驟進行操作。

        • 在安裝過程中,可選擇安裝路徑、加入快捷方式等選項。通常,預設選項是最合適的。

      • 設定環境變數以完成安裝:

        • 安裝完成後,確保將 CMake 的安裝路徑添加到系統的 PATH 環境變數中。

        • 如果需要手動添加到 PATH,請按照以下步驟:

          1. 打開「設定」。

          2. 選擇「系統」。

          3. 下拉到畫面最後,選擇「系統資訊」。

          4. 在「系統資訊」畫面尋找「進階系統設定」後並點擊之。

          5. 進入「系統內容」視窗後,點擊「環境變數」按鈕。

          6. 在「系統變數」的區域中,下拉尋找名為 Path 變數。

          7. 在「編輯環境變數」對話框中,按一下「新建」,然後加入 CMake 的安裝路徑(一般都是放在 C:\Program Files\CMake\bin,請確認 CMake 在你電腦的位置)。

          8. 點擊「確定」儲存變更。

        • 打開命令提示列(cmd)或 PowerShell。

        • 在命令提示列輸入下列指令檢查 CMake 是否成功安裝,並顯示版本資訊,若成功安裝,則會看到 cmake 版本:

          cmake --version

Mac

  1. Xcode:(需安裝)

    • 若尚未安裝 Xcode,首先從 Mac App Store 下載和安裝 Xcode。

    • Xcode 是 macOS 上的整合開發環境(IDE),其包括編譯器(含 C++編譯器 - Clang)和許多開發工具,非常適合 C++ 開發。

  2. Homebrew

    • Homebrew 是 macOS 上的一個套件管理器,可以幫助您輕鬆安裝和管理軟件包。您可以使用以下命令安裝 Homebrew:

      /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
      • 它會自動下載 Homebrew 並安裝到 /opt/homebrew(在 Apple Silicon/M 系列處理器)或 /usr/local(在 Intel 機種)。
    • 執行以下指令:若看到版本號,代表安裝成功!

      brew --version
  3. C++ 編譯器:

    • 使用 Homebrew 安裝最新版本的 GCC 或 Clang(Xcode 安裝後即具備)。您可以選擇其中一個來編譯 C++ 程式。

      • 安裝 GCC(可選):

        brew install gcc

      • 使用 Xcode 內建的 Clang。

  4. Visual Studio Code(課程採用)

    • 下載 macOS 版本: 點擊下載頁面上的「macOS」按鈕,以下載 macOS 版本的 Visual Studio Code。

    • 安裝 VS Code: 下載完成後,您會在下載目錄中找到一個名為「Visual Studio Code.app」的應用程式檔案。將該檔案拖曳至「應用程式」資料夾中,以完成安裝。

    • 啟動 VS Code: 前往「應用程式」資料夾,找到安裝完成的 Visual Studio Code 應用程式,接著雙擊打開。

    • 安裝插件(擴展): 第一次啟動 VS Code 時,將看到歡迎畫面。可在左側的側邊欄中找到插件圖示(方塊和箭頭)。點擊該圖示,然後在搜索欄中輸入欲安裝的插件名稱。例如,想進行 C++ 開發,需安裝「C/C++」擴展。單擊「安裝」按鈕以安裝所選的擴展。另外,請同時安裝 CMake 插件。

  5. CMake

    • 方法一:使用 Homebrew 安裝 CMake(建議使用)

      • 打開終端機應用程式(Terminal)。若未安裝 Homebrew,可在終端機執行以下命令來安裝:

        /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

      • 安裝 CMake,只需在終端機執行以下命令:

        brew install cmake

      • 可在終端機執行以下命令來驗證 CMake 是否安裝成功:

        cmake --version

      • 若安裝成功,終端機將顯示 CMake 的版本訊息。

    • 方法二:從官方網站下載並安裝 CMake

      • 前往 CMake 官方網站的下載頁面

      • 滾動到 “Binary distributions” 部分,找到 macOS 的選項,通常會有一個 .dmg 檔案的下載連結,點擊它下載最新版本的 CMake。

      • 雙擊下載的 .dmg 檔案,它會在 Finder 中打開一個新的視窗。

      • 在打開的視窗中,將 “CMake” 應用程式圖標拖放到 “Applications” 資料夾中,以完成安裝。

      • 可關閉 .dmg 視窗,並在「應用程式」資料夾中找到 CMake 應用程式。第一個 C++ 程式

      • 可在終端機執行以下命令來驗證 CMake 是否安裝成功:

        cmake --version

      • 若安裝成功,終端機將顯示 CMake 的版本訊息。

CMake 與 Ninja 工具

  • CMake 是一個開源跨平台『自動化專案建構』的工具,其不依賴於特定的編譯器或作業系統。

  • CMake 主要任務是生成適用於不同建構系统的『建構文件檔』。依系統不同有以下格式:

    • Makefiles:Make工具上的建構文件檔

    • Visual Studio 專案的建構文件檔

    • Ninja 的建構文件檔等。

  • CMake 的配置文件稱為 CMakeLists.txt,其用來定義專案的各種屬性、依賴關係和建構的規則等。

  • Ninja 是一個跨平台的軟體專案建構系统,其用於『專案的構建』。最初由 Google 團隊開發使用。

  • Ninja 與 Make 或其他建構工具不同,Ninja 的設計目的是快速執行與平行化建構方式。

  • Ninja 以建構文件檔 —— build.ninja 形式使用,而這些文件檔由 CMake 工具所產生。

  • 當使用 CMake 專案時,CMake 工具會根據專案的配置產生適用於 Ninja 的建構文件檔。意指你可以指定使用 Ninja 作為實際建構專案的工具,而非採 Make 或 Visual Studio 等其他建構工具。

CMake指令

  • 在 macOS 上使用 CMake 工具一般不需要額外安裝 Ninja。

  • macOS 內建 make 建構工具,一般情況下足以完成大部分 CMake 專案的構建。

    • 因 macOS 預設安裝 make 工具(GNU Make)。故可在終端機中執行 “make” 命令。

    • 為確認已經正確安裝。請執行下列指令:

      make --version
  • 補充:安裝Ninja(可選):

    • Windows:

      1. 安裝 Chocolatey(可選)

        • 以『系統管理員身分執行』打開 PowerShell 。

        • 執行以下指令安装 Chocolatey:

          Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
      2. 安裝 Ninja(可選)

        • 當 Chocolatey 安装完成,可使用 Chocolatey 來安裝 Ninja。

        • 同樣以『系統管理員身分執行』打開的 PowerShell 或命令提示列視窗執行以下指令:

          choco install ninja
      3. 驗證安裝:

        • 在命令提示列或 PowerShell 執行以下指令:

          ninja --version
    • macOS:

      • 可使用套件管理器進行安裝,如 Homebrew。以下是使用 Homebrew 安裝 Ninja 的步驟:

        brew install ninja
      • 驗證安裝:

        ninja --version
  • 要在 CMake 中配置使用 make 或 ninja 作為建構工具,或是在 Windows 系統下使用 Visual Studio 2022 的生成器,可透過執行 CMake 指令時指定生成器(Generator)來達成。

  • 生成器決定了 CMake 將使用哪種建構工具。

    • 指定使用 Make 建構工具:cmake -S . -B build -G "Unix Makefiles"(Mac 可用)

    • 指定使用 Ninja 建構工具:cmake -S . -B build -G "Ninja"(Mac、Windows 可用,建構速度較快,建議 Mac 使用

    • 指定使用 Visual Studio 2022 建構工具:cmake -S . -B build -G "Visual Studio 17 2022”建議 Windows 使用

    • 上述指令用於配置和生成 CMake 專案的配置文件:

      • cmake:這是 CMake 的命令行工具,用於執行各種 CMake 相關的操作。

      • -S .:這部分指定了 CMake 的來源目錄(Source Directory)。. 表示當前目錄,也就是執行該命令的目錄。這個目錄應包含 CMakeLists.txt 文件,因為它告訴 CMake 哪裡可以找到專案的配置相關設定。

      • -B build:這部分指定 CMake 的建構目錄(Build Directory)。在上述範例中,將建構文件存儲在名為 “build” 的子目錄中。建構目錄是用於儲存產生的中間檔案和建構檔案的位置。您可以選擇不同的目錄名稱,但通常建議將生成文件存儲在專門的子目錄中,以保持專案的整潔與一致性。

      • -G "Unix Makefiles":這部分指定了生成器(Generator)。在上述範例中,若使用的生成器為 “Unix Makefiles”,此生成器用於產生可由 Unix 系統上的 Make 指令使用的建構文件。這表示希望使用 “make” 作為建構工具來編譯和構建你的 C++ 專案。

  • CMake 建構指令:

    cmake --build build
    • 此指令使用 CMake 設定的建構工具來進行建構的命令。

    • CMake 會根據之前指定的生成器來選擇適用的建構工具。

    • 以下為該指令各部分的解釋:

      • cmake:這是 CMake 的命令行工具,用於執行各種 CMake 相關的操作。

      • --build:這是 CMake 的一個子命令,用於執行實際的建構操作。

      • build:這是之前使用 -B 選項指定的生成目錄的名稱。建構目錄是 CMake 用來儲存生成的中間檔案和建構檔案的位置。

    • 當執行 cmake --build build 時,CMake 將使用預設的生成工具(例如 make 或 ninja,取決於之前配置的生成器)來自動編譯和連結 C++ 專案。

    • 該指令會在建構目錄中查找 CMake 已經生成的建構指令,接著執行這些指令以完成建構過程。

執行第一個 C++ 程式

  • 程式語言實際上就是一套規範的集合,主要包含該語言使用的字元集合、直接或間接支援的資料型態集合、運算子集合、關鍵字集合、指令集合、語法規則,以及特定構造的支援,例如:函數的定義,抽象資料型態的定義、繼承、模板、例外處理等。

  • main 函數(主函數)為C++程式的「入口點」。

  • main 函數為使用者運行程式時所執行的函數。

  • C++程式常用的副檔名:

    • .cppcxxcc:原始檔(source file)。

    • .h.hpp:標頭檔(header file)

  • 『函數(function)』可以接收輸入、執行某些指令並回傳結果的程式碼區塊。

    // test.cpp,放入src資料夾
    // 這是單行註解
    
    /*
     * 這是多行註解
     * 這是多行註解
     * 這是多行註解
     */
    
    #include <iostream>                                       // 包含iostream標頭檔。
    
    int main(int argc, char* argcv[])
    {
      std::cout << "Hello Quant World" << std::endl;         // std為C++標準程式庫的命名空間(namesapce)名稱。
      return 0;
    }

使用 VS Code

  • 可令專案名為: MyProj,資料夾內建立子資料夾:

    • src:存放c++原始檔(source file, ex: 副檔名為 .cpp.cxx.cc)。

    • include:存放標頭檔(header file, ex: 副檔名為 .h.hpp)。

    • external:存放外部程式庫原始檔,例如:QuantLib-1.33

    • data:存放外部資料檔,例如 .txt, .json檔案。

    • bin:執行檔放置的位置。

    • CMakeLists.txt

      • 在專案資料夾 MyProj 建立名稱為 CMakeLists.txt 的檔案(CMake設定檔),用於描述專案的結構和如何構建該專案。

      • 定義原始檔、編譯選項、連結庫、目標(target)和其他構建相關的設置。

      • CMakeLists.txt 使用 CMake 語法,其包含一系列命令和變數設置。

        cmake_minimum_required(VERSION 3.10)
        
        project(CppProject
          VERSION 1.0.0
          DESCRIPTION "Study C++"
          LANGUAGES CXX
        )
        
        # 指定 C++ 的版本
        set(CMAKE_CXX_STANDARD 17)
        set(CMAKE_CXX_STANDARD_REQUIRED ON)
        
        
        # 設定專案的目錄結構
        set(SRC_DIR ${CMAKE_SOURCE_DIR}/src)
        set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include)
        set(EXTERNAL_DIR ${CMAKE_SOURCE_DIR}/external)
        set(DATA_DIR ${CMAKE_SOURCE_DIR}/data)
        set(BIN_DIR ${CMAKE_SOURCE_DIR}/bin)
        
        
        # 設定執行檔名稱與原始檔名稱 #################################
        # set(SOURCE_FILES ${SRC_DIR}/main.cpp)          #    原始檔名稱
        set(EXECUTABLE_NAME MyApp)                       #    執行檔名稱
        ##############################################################
        
        
        # 使用 GLOB 收集原始檔案
        file(GLOB SOURCE_FILES "${SRC_DIR}/*.cpp")
        
        
        # 設定可執行檔案的輸出目錄
        set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR})
        
        
        # 設定執行檔名稱和源文件
        add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES})
        # MyApp 是要創建的執行檔名稱(目標target),main.cpp 是該執行檔所依賴的源文件。
        # 這個指令告訴 CMake 創建一個名為 MyApp 的執行檔,該執行檔的源文件是 main.cpp。
        
        
        # 將 include 目錄添加到編譯器的包含路徑中
        target_include_directories(${EXECUTABLE_NAME} PRIVATE ${INCLUDE_DIR})
        
        
        message(STATUS "Binary output directory: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
        
        
        # 最後將測試資料複製一份到輸出目錄(bin資料夾)
        file(COPY ${DATA_DIR} DESTINATION ${BIN_DIR})
  • 每個 C++ 程式包含一個或多個函數(function)。其中一個必須命名為 main

  • main 函數為程式的入口點(entry point),作業系統是透過 main 函數來執行 C++ 程式。

  • 一個函數的定義包含四個部分:

    • 回傳型態(return type)

    • 函數名(function name)

    • (形式)參數列表(parameter list,可為空)

    • 函數體(function body)

  • main 函數回傳值必須為 int,即為整數型態;其為一種內建型態(built-in type)。

  • 函數體由左大括弧({)開始,以右大括弧結束(})。

  • #include <iostream> 告訴編譯器我們想要使用 iostream 程式庫。< >內指定標頭檔(header file)名稱。而#include指令與標頭檔名稱必須寫在同一行,且一般出現在所有函數之外(含main函數)。

    • 標準 C 並沒有提供對 I/O 的直接支援,只有定義標準 I/O 的函數接口,故 I/O 工作都是透過函數庫來完成。標準 C++則繼承了 C 的 I/O 函數庫接口,並重新定義自己的物件導向的 I/O 系統。
  • return 語句(statememt)結束函數的執行。

  • 請注意 return 語句末尾的分號(;)。大多數 C++的語句以分號(;)表示該語句的結束。

  • 在大部分系統中,main 函數的回傳值表示『執行狀態』。回傳 0 代表執行成功,非 0 的回傳值則由系統定義,通常代表錯誤的類型。

C++ 程式的建構過程

  • C++程式由資料數據(常數、變數,含物件等)與函數組成。

  • 因 C++ 為編譯程式語言,故編寫程式之後則需進行編譯。

  • 如何編譯端看使用的作業系統與編譯器。例如使用整合開發環境(如 VS code 與 Visual Studio 2022 等),則是將編譯器與其他程式創建和分析工具整合為一。

  • 亦可透過命令提示列進行。

  • 建構過程:

    1. 編輯器(editor):將程式的設計想法轉換為程式碼。

      • 如果是語法方面的錯誤,則會在程式編譯過程中出錯,且編譯器會出現錯誤提示。

      • 若是邏輯方面的錯誤(例如程式輸出結果不如預期),或是執行效率低落,則不會有明顯的錯誤提示。

    2. 預處理器(preprocesser)

      1. 編譯器在正式編譯之前,遍歷整個原始程式檔,處理 C/C++ 檔案中預處理命令,即#開頭的指令。

      2. 預處理的含義將後面提及的檔案(標頭檔)複製至當前原始碼檔案中。並進行下列處理:

        • 刪除所有的 #define 並展開所有 macro

        • 處理所有的預編譯條件,例如 #ifdef , #include (展開引用文件)

        • 刪除所有 註解

        • 增加 行號以及 文件識別名,讓編譯器在編譯失敗時可以顯示錯誤的行號。

        • 常見預處理指令:

          • #include

          • #ifndef … #else …#endif

          • #define

          • #pragma

    3. 編譯器(compiler)

      • 雖然 C++ 標準是唯一的,但各編譯器的實現未必完全一致。

      • 因不同電腦的硬體平台未必相同,故一種編譯器一般是針對一種或某些平台所設計。

      • 為某種平台編譯的程式,一般無法在另一個平台運行。

      • 此階段編譯器會將展開後的程式碼轉換成組合語言。

      • 預編譯之後,編譯器會編譯每個原始檔(.cpp.cxx.cc.c),如果編譯成功,會生成對應的目標檔(object file),Linux平台為 .o 檔,Windows平台下為 .obj 檔。

      • 編譯完成的目標檔還不可執行。還需要連結器進一步處理。

    4. 連結器(linker):連結器將多個目標檔與多個靜態程式庫處理成『執行檔』的過程。

      • 執行檔:包含指令、位址與數據(實際上位址也是一種特殊的數據)。
    5. 執行程式:

      1. 連結任務完成後即可產生執行檔。但仍需檢驗程式能否正常運行,並符合設計的要求。

      2. 很少有程式能一次執行成功,總會有一些意想不到的錯誤發生。

      3. 錯誤發生後則需回頭檢查原始碼、重新編譯、連結,試執行。

C++基本語法

常用資料型態簡介與分類

  • 物件的型態(type)是描述該物件的行為和狀態所成的集合。

  • C++ 是一種『強型別語言(strong typed language)』,意思是每個物件的資料型態都必須預先定義。

  • 基本型態(內建型態):

    • 數值型態:

      • 整數

        • short (short int)

        • int

        • long (long int)

      • 浮點數

        • float

        • double

    • 字元型態(char

    • void空型態

    • bool型態:truefalse

  • 陣列(array)

  • 字串(string

  • 複合型態

    • 指標(pointer)

    • 參考(reference)

  • 使用者定義型態

    • 結構(struct

    • 聯合(union

    • 列舉(enum

常用資料型態佔記憶體大小

資料型態 32位元系統(位元組 byte) 64位元系統(位元組 byte)
char 1 1
short 2 2
int 4 4
float 4 4
double 8 8
long 4 8
long long(C++ 11) 8 8
  • 若無法確認某個變數或資料型態所佔用的記憶體大小,可使用sizeof運算子求得:

    int a;
    printf("a變數佔用的記憶體大小為:%d 位元組(byte)\n", sizeof(a));
    /*
     * a變數佔用的記憶體大小為: 4 位元組(byte)
     */
    
    char x = 'H';
    printf("x變數佔用的記憶體大小為:%d 位元組(byte)\n", sizeof x);      // C 寫法
    std::cout << "x變數佔用的記憶體大小為:" << sizeof(x) << " 位元組(byte)" << std::endl;   //  C++ 寫法

常用資料型態數值範圍

資料型態 最小值 最大值 所佔位元組(byte)
char -128 127 1
short -32767 32768 2
unsigned short 0 65536 2
int -2147483648 2147483647 4
unsigned int 0 4294967295 4
long -2147483648 2147483647 4
long long -9223372036854775807 9223372036854775808 8
unsigned long long 0 18446744073709551615 8
  • 同一條表達式切勿混用 signed 與 unsigned 型態:因為 signed 型態會自動轉換為 unsigned 型態。

  • 試試看下列練習:

    unsigned u = 10, u2 = 42;
    std::cout << u2 - u << std::endl;
    std::cout << u - u2 << std::endl;
    int i = 10, i2 = 42;
    std::cout << i2 - i << std::endl;
    std::cout << i - i2 << std::endl;
    std::cout << i - u << std::endl;
    std::cout << u - i << std::endl;
    int firstNumber;
    std::cout << "Please enter your number:" << std::endl;
    std::cin >> firstNumber;          // std::cin為 stream extraction operator,從鍵盤輸入獲得某值。
    std::cout << "Your number is " << firstNumber << "." << std::endl;
    int r = std::pow(2, 10);        // 計算2的10次方
    std::cout << "2的10次方為:" << r << std::endl;
    std::cout << "圓周率pi為:" << M_PI << std::endl;
    std::cout << "自然常數e為:" << M_E << std::endl;

C++程式結構

  • 一個典型的C++程式包含以下部分:

    • 標頭檔區: 包含程式所需的標準庫。

    • 主函數: 程式的入口點。

#include <iostream>
using namespace std;

int main() {
    cout << "Hello World" << endl;
    return 0;
}
#include <iostream>
using namespace std;

int main() {
    int a = 10;
    float b = 5.5;
    char c = 'A';
    bool d = true;

    cout << "Integer: " << a << endl;
    cout << "Float: " << b << endl;
    cout << "Character: " << c << endl;
    cout << "Boolean: " << d << endl;

    return 0;
}

變數與基本資料類型

常數

常數
  • 常數又稱常量。常數(constant)的值是無法被更改的。

  • 而 C++ 的常數多為字面值(literal)。在程式中字面值常數的功能是用來初始化變數、給變數賦值、參與表達式計算等。

常用的常數有:

  • 整數常數:如 100

    • 十進位:如123

      int abc = 100;    // 定義 abc 為型態 int 的變數並初始化,值為100。
      short def = 200;  // 定義 def 為型態 short 的變數並初始化,值為200。
      def = 300;        // 為賦值語句。此行作用為把新值300賦值給def變數。
      
      // C++ 14允許使用單引號作為數字的分隔符:
      long d = 6'546'1000;
      std::cout << d << std::endl;
    • 二進位:C++ 14 開始,可以使用 0b0B 開頭表示二進位字面值。

      int b = 0b11111010;  // int b = 250;
    • 八進位:以0開頭的數字。

      int abc;
      abc = 012;
      printf("012的十進位數字為:%d\n", abc);
      /*
       * 012的十進位數字為:10
       */
    • 十六進位:以0x開頭的數字。

      int abc;
      abc = 0x12;
      printf("0x12的十進位數字為:%d\n", abc);
      /*
       * 0x12的十進位數字為:18
       */
    • 特殊用法:

      • 整數常數加一個字母 Uu,表示該常數以unsigned無符號整數儲存,相當於 unsigned int

      • 整數常數加一個字母 Ll,表示該常數以長整數儲存,相當於 long

      • 整數常數加一個字母 Ff,表示該常數以浮點數儲存,相當於 float

  • 浮點數(數值)常數:如 1.23

    • 十進位表示形式:0.1233.14159

    • 指數表示形式:如 168E5,等價於 168×100000。E 也可以為小寫 e

    • float:一般佔 4 byte,取值範圍 1.17549e-038 ~ 3.40282e038,單精度變數:提供7為有效數字,隨機器而定。

    • double:佔 8 byte,取值範圍 2.22507e-308 ~ 1.79769e308,雙精度變數:提供15 ~ 16位有效數字,隨機器而定。

      float af = 12.34567291234987654321;
      double ad = 12.34567291234987654321;
      printf("af的值是%f\n", af);
      printf("ad的值是%f\n", af);         // %f 格式符:專門用來顯示浮點數
      printf("af的值是%.20f\n", af);      // %.20f顯示小數點後20位有效數字
      std::cout.setf(std::ios_base::showpos);
          double pi = M_PI;
          std::cout << "pi is " << std::right << std::setw(20) << std::setprecision(16) << 10 * pi << std::endl;
          std::cout << "pi is " << std::setw(20) << std::right << std::setprecision(16) << 100.0 << std::endl;
          std::cout << std::boolalpha << (1 < 2) << std::endl;
  • 字元常數:用一對單引號('')包含起來,如 'A''$'

    char c1, c2, c3;   // 定義字元變數
    c1 = 'a';
    c2 = 'b';
    c3 = '\'';          // 末尾不是雙引號,是兩個單引號。\' 是跳脫字元(escape character),為單個字元。
    • 將一個字元常數放到字元變數中,實際上並非將字元本身放到字元變數所屬的記憶體當中,而是把字元對應的ASCII碼(範圍處於 0 ~ 127之間的整數數字,如字元 a 對應的數字為 97)存放到記憶體中。

      char c1, c2;
      c1 = 97;                                 // 相當於 c1 = 'a';
      c2 = 98;                                 // 相當於 c2 = 'b';
      printf("c1 = %c, c2 = %c\n", c1, c2);    // c1 = a, c2 = b
      printf("c1 = %d, c2 = %d\n", c1, c2);    // c1 = 97, c2 = 98;
      c2 = c2 + 4;
      printf("c1 = %c, c2 = %c\n", c1, c2);    // c1 = a, c2 = f
      printf("c1 = %d, c2 = %d\n", c1, c2);    // c1 = 97, c2 = 102;
      • ASCII 的發音通常是 “ask-ee”,由英文字母A、S、C、I和I組成的縮寫,代表美國信息交換標準碼(American Standard Code for Information Interchange)。

      • ASCII 是一種字元編碼標準,用於電子通信中表達文字資料。包括數字、大寫字母、小寫字母和一些常用符號。

      • 大多數鍵盤上的字符都是ASCII字符。它定義了128個字元,包括英文字母、數字、標點符號和一些控制字符(https://zh.wikipedia.org/zh-tw/ASCII)。

    #include <iostream>
    using namespace std;
    
    int main() {
        char upper = 'A'; // 大寫字母
        char lower = upper + 32; // 轉換為小寫字母
        cout << "Upper case: " << upper << endl;
        cout << "Lower case: " << lower << endl;
        return 0;
    }
    #include <iostream>
    using namespace std;
    
    int main() {
        for (int i = 32; i < 128; i++) {
            cout << "ASCII value: " << i << " Character: " << static_cast<char>(i) << endl;
        }
        return 0;
    }
  • 字串常數:

    • 字串常數是用一對雙引號("")包含起來的一串字元(可以是一個字元或多個字元)。如 "Hello World"

    • 'a' 是字元常數、"a" 是字串常數。

    • 'a' 在記憶體中佔1個byte,"a" 則在記憶體佔2個byte。而 "a" 最後一個字元為 '\0',由系統自動加上去的。

    • '\0' 是 C 和 C++ 中的『空字元』(Null字元或零字元),又稱『結束字元』。它表示一 ASCII碼為 0 的字元,通常用来表示字串的结束,特别是在以空字元结尾的 C 字串(字元陣列)中。

    • 『空格(space)字元』(' ')與上述『空字元』不一樣,『空格(space)字元』的 ASCII碼為32的字元。(又與『空字串』不同:""

  • 布林(boolean)常數:

    • 布林型態資料其字面值只有兩個:truefalse。分別代表邏輯為真與邏輯為假。

    • 當其他型態的數據轉換為布林型態:

      bool b;              // 定義bool變數
      b = true;            // 對變數賦值
      bool c = false;      // 定義並初始化一個變數
      bool b = -123;       // true
      b = 0;               // false
      b = '\0';            // false
      b = 'a';             // true
      b = 0;               // false
      b = 1.2;             // true        

變數

  • 又稱『變量』,顧名思義,變數(variable)的值是可以被修改的。

  • 變數就是擁有名稱(name)的一塊記憶體空間(又稱『內存』,用來儲存資料)。

  • 含下列資訊:

    • 資料型態。

    • 記憶體位址。

    • 儲存值。

變數宣告(declaration)
  • 宣告是告訴編譯器某個名稱的存在,但不會分配記憶體或初始化變數。

  • 變數宣告可以在程式的任何位置,但必須在該變數使用前進行宣告。

  • 它僅僅是為了讓編譯器知道某個標識符(如函數名稱、變數名稱或類別名稱)的存在,以便在稍後的程式碼中使用它。

  • 變數宣告規定了變數型態與名稱。這一點與變數定義相同。

  • 除此之外,『變數定義還多要求儲存空間,也會為此變數設定初始值』。

  • 任何顯式初始化的宣告即為定義。

  • 任何想宣告一個變數而非定義它,就在變數名字前面添加關鍵字 extern

  • C++ 支援『分離編譯(separate compilation)』機制,允許將程式分割為多個原始檔(以利程式碼的組織架構整理),故每個原始檔可被獨立編譯。故:需要有再多個原始檔之間共享程式碼的機制。

  • 為了支援分離編譯,C++ 將『宣告』與『定義』區分出來。

  • 『宣告』使得『名稱』被程式所知:知道型態與名稱。

  • 『定義』則創建出與『名稱』產生關聯的物件實體,且發生初始化,故會佔用記憶體空間。

extern int i;     // 宣告i,而非定義i
int j;            // 宣告並定義j,雖然沒有顯性初始化,但發生『預設初始化』。
標識符(identifier)
  • 在程式語言中用來識別變數、函數、類別、物件、模組等各種程式實體的名稱。

  • 標識符通常是由字母、數字和下劃線組成,並且需要遵循特定的語法和命名規則,以確保它們在程式碼中能夠被正確地識別和使用。

  • 標識符的命名規則如下:

    1. 標識符可以包含字母(區分大小寫)、數字和下劃線(_)。

    2. 標識符的第一個字元必須是字母或下劃線。

    3. 標識符不能包含空格或特殊字元(如 !@#$ 等)。

    4. C++ 語言對變數名稱長度沒有限制,但名稱不應過長,以易記、意義明確為原則。

變數定義(definition)
  • 型態指定符(type specifier),後面接著一個或多個變數名所組成的列表,其中變數名以逗號(,)分隔,最後以分號(;)結束。

  • 定義不僅宣告了名稱的存在,還為它分配了記憶體並初始化變數。

  • 當你定義一個變數或函數時,它會佔用實際的記憶體空間,並賦予它初值。

  • 無論開發者是否指定初始值,變數在定義後都會有一個初始值。

  • 若未指定初值,而變數之值為未定值,此值由編譯器自行決定,且多為無意義之值,容易產生錯誤。

  • 變數必須遵循『先定義後使用』的原則。

  • 變數只能被定義一次,但可被多次宣告。

  • 故在程式碼中,宣告通常出現在標頭檔中,而定義則出現在原始檔中。這種區別在 C++ 中很重要,特別是在避免重複定義的情況下。

int sum = 0, value,            // sum、value 與 number都是 int  
    number = 0;                // 其中,sum 和 number 設定初值為 0
std::string book("西遊記");    // book透過 string 字面值初始化。
std::string name = "NCCU";
物件(object)
  • 物件是指一塊能儲存資料數據並具有某種型態的記憶體空間。

  • 具有名字的物件則為變數(故物件不一定有名稱)。

初始化(initialization)
  • 當物件在建立時獲得一個特定值,則稱該物件被初始化(initialized)。

  • 初始化『非』賦值。

  • 變數可使用已存在的變數進行初始化(放在初始化時等號( =)的右邊)。

  • 賦值的含義是指將物件當前的值給移除,而以新值來做替代。故賦值可用來修改變數值。

  • 初始化只會發生一次,即發生在變數定義時,而賦值則可以發生很多次。
int a = 100;      // 初始化。
int b = a;        // 初始化:拿已存在的變數a來初始化變數b
列表初始化(list initialization)
  • C++ 語言定義初始化好幾種方式。

  • C++ 11 新標準定義了『列表初始化』:{}

  • 可避免數值發生部分值遺失的狀況

int x = 0;
int x = {0};
int x{0}
int x(0);
/*
 * 
 */
double pi = 3.1415926;
int a{pi}, b{pi};       // 錯誤,型態轉換未執行
int c(pi), d(pi);       // 正確,發生型態轉換,且遺失部分值。
預設初始化
  • 若定義變數時沒有指定初始值,則該變數發生預設初始化

  • 定義於任何函數體之外的內建型態變數被預設初始化為 0。

  • 定義於任何函數體之內的內建型態變數將不被初始化(uninitialized)

  • 而未初始化之變數的值為『未定義』。若試圖複製或存取該變數將引發錯誤。

  • 建議初始化每一個內建型態的變數。

變數與記憶體(內存)的關係

  • 變數本質上就是一塊記憶體空間(內存)。

  • 記憶體:記憶體位址(address)、記憶體大小屬性。

變數的位址

  • 電腦的內存是按照『位元組(byte)』進行編碼。

  • 內存中的位元組的編碼就是這個位元組的位址。

  • 系統可按照記憶體位址對記憶體進行存取操作(&運算子)。

  • C++ 程式定義一個變數即是佔用一塊記憶體空間,而變數名為指向這塊記憶體空間的『首位址』,變數型態則是決定這塊記憶體空間的長度(大小)。

計算資料所佔位元組大小

  • sizeof 運算子回傳型態或數據的位元組大小。

  • sizeof 關鍵字後面可帶括號(()),也可以不帶括號。

  • 括號中可以是『型態名稱』,也可以是『變數名稱』。

    #include <iostream>
    using namespace std;
    
    int main() {
        cout << "int的大小:" << sizeof(int) << " 位元組" << endl;
        cout << "double的大小:" << sizeof(double) << " 位元組" << endl;
        cout << "char的大小:" << sizeof(char) << " 位元組" << endl;
        return 0;
    }
    #include <iostream>
    using namespace std;
    
    int main() {
        int num = 42;
        double pi = 3.14159;
    
        cout << "num的大小:" << sizeof(num) << " 位元組" << endl;
        cout << "pi的大小:" << sizeof(pi) << " 位元組" << endl;
    
        return 0;
    }

const 變數

  • 可使用關鍵字 -const 限定符(qualifier)-定義一個不能被修改的變數。

  • const 物件一但創建後其值就不能被修改,const 物件必須『初始化』

    const int i = 42;
    // const int k;              // 錯誤,k是一個未初始化的常數。
    const int ci = i;             // 正確,i的值被複製並賦值給ci。
    int j = ci;                  // 正確,ci的值被複製並賦值給j。
  • 上例,儘管 ci 是整數常數,但無論如何 ci 中的值還是一個整數。

  • ciconst 的特性只有在執行改變 ci 的操作時才會產生作用。

  • 當進行編譯時,編譯器會在編譯過程中把用該變數之處替換為對應值。故需要對 const 變數進行初始化。

  • 預設情況下,const 物件只有在它所在的原始檔案有效。故可在不同原始檔案定義相同名稱的 const 變數。

  • 若想在不同原始碼檔案間共享 const 物件,必須在變數的定義之前加入 extern 關鍵字。

表達式

  • 表達式(expression):對各種物件(或數值)進行運算的過程。

  • 運算後即產生結果。故表達式所表達的就是一個結果。

  • 例如:

    • 3 + 2 就是一個表達式。其結果為 5

    • "Hello World" 此為『字串常數表達式』,此表達式的結果為字串物件(也是最簡單表達式的一種)。

  • 參與運算的物件(數值)被稱為『運算元(operand)』,又稱『運算對象』。

    • 3 + 2 的運算元就是 32
  • 進行運算操作的符號則為『運算子(operator)』,又稱『運算符』。

    • 3 + 2 的運算子就是 +
  • 一般情況,表達式會有一個或多個運算子。

    • 若表達式的運算元也是一個表達式,則稱為『複合表達式』。

      1.2 * (basicSalary + bonus - penalty)              // 計算薪水的表達式
    • 子表達式的計算順序是由運算子的優先級(precedence)與結合律(associativity)共同決定。

    • 若優先級相同,則由結合律來決定。以四則運算為例:

      • 例如乘法與除法優先級相同,乘法與除法的運算元會優先進行運算,接著結果才能為加法或減法的運算元。

      • 而算術運算子滿足『左結合律』,意指當運算子優先級相同時,將按照由左至右的順率組合運算元。

    • 表達式中的括號(())可無視上述規則,程式設計師可使用括號將表達式的某個部分括起來使其得到優先運算。

  • 表達式的結果不一定有 ;

  • 若帶有 ;,則成為一個語句(statement)

常見運算子分類

  • 一元運算子:作用於一個運算元的運算子,如取址運算子(&)與解參考運算字(*)。

  • 二元運算子:作用於兩個運算元的運算子,如相等運算子(==)與乘法運算子(*)。

  • 三元運算子:C++中只有一個三元運算子:條件運算子 ? :

  • 函數呼叫運算子:()

  • 運算子有時可做為一元運算子,也可能做為二元運算子,如 *。端看該段程式碼上下文來決定。

  • 也可以按照運算子操作結果,可分為:

    • 算術運算子

    • 邏輯與關係運算子

    • 賦值運算子:=

    • 條件運算子:? :

    • sizeof 運算子

    • 位元運算子

基本的數學運算

  • 以下是用於在變數上執行各種數學運算的範例 C++程式碼。請注意,包含了cmath 標頭檔。

  • 該標頭檔對於一些數學運算是必需的,並且還包括一些有用的常數值,例如 M_PI,它包含了精確到約20位小數的 π值。

#include <iostream>
#include <cmath> // 包含cmath標頭檔

using namespace std;

int main() {
    double x = 3.0;
    double y = 4.0;
    
    // 基本運算
    cout << "x + y = " << x + y << endl;
    cout << "x - y = " << x - y << endl;
    cout << "x * y = " << x * y << endl;
    cout << "x / y = " << x / y << endl;
    
    // 使用cmath進行進階運算
    cout << "pow(x, y) = " << pow(x, y) << endl; // x的y次方
    cout << "sqrt(x) = " << sqrt(x) << endl; // x的平方根
    cout << "exp(x) = " << exp(x) << endl; // e的x次方
    cout << "log(x) = " << log(x) << endl; // x的自然對數
    cout << "log10(x) = " << log10(x) << endl; // x的10為底的對數
    cout << "fabs(x) = " << fabs(x) << endl; // x的絕對值
    cout << "cos(x) = " << cos(x) << endl;  
    cout << "sin(x) = " << sin(x) << endl;  
    cout << "tan(x) = " << tan(x) << endl;

    // 使用常數M_PI
    cout << "M_PI = " << M_PI << endl; // π的值
    
    return 0;
}

其他數學函數

  • C++ 提供了許多其他數學函數。以下是一些常見的數學函數及其使用方法,這些函數的用法與 sqrtexp 相同,即接受一個參數並回傳一個值:

    • cos(x) - 計算 x 的餘弦值

    • sin(x) - 計算 x 的正弦值

    • tan(x) - 計算 x 的正切值

    • acos(x) - 計算 x 的反餘弦值

    • asin(x) - 計算 x 的反正弦值

    • atan(x) - 計算 x 的反正切值

    • cosh(x) - 計算 x 的雙曲餘弦值

    • sinh(x) - 計算 x 的雙曲正弦值

    • acos(x) 計算 x 的反餘弦值,返回值的範圍為 [0, π]。

    • asin(x) 計算 x 的反正弦值,返回值的範圍為 [-π/2, π/2]。

    • atan(x) 計算 x 的反正切值,返回值的範圍為 [-π/2, π/2]。

    • log(x) 計算 x 的自然對數(以 e 為底)。

    • log10(x) 計算 x 的以 10 為底的對數。

    • ceil(x) 將 x 向上取整。

    • floor(x) 將 x 向下取整。

    #include <iostream>
    #include <cmath> // 包含cmath標頭檔
    
    using namespace std;
    
    int main() {
        double x = 0.5;
        double y = 2.0;
    
        // 三角函數
        cout << "cos(" << x << ") = " << cos(x) << endl;
        cout << "sin(" << x << ") = " << sin(x) << endl;
        cout << "tan(" << x << ") = " << tan(x) << endl;
    
        // 反三角函數
        cout << "acos(" << x << ") = " << acos(x) << endl;
        cout << "asin(" << x << ") = " << asin(x) << endl;
        cout << "atan(" << x << ") = " << atan(x) << endl;
    
        // 雙曲函數
        cout << "cosh(" << x << ") = " << cosh(x) << endl;
        cout << "sinh(" << x << ") = " << sinh(x) << endl;
        cout << "tanh(" << x << ") = " << tanh(x) << endl;
    
        // 對數函數
        cout << "log(" << y << ") = " << log(y) << endl;
        cout << "log10(" << y << ") = " << log10(y) << endl;
    
        // 取整函數
        double z = 5.7;
        cout << "ceil(" << z << ") = " << ceil(z) << endl;
        cout << "floor(" << z << ") = " << floor(z) << endl;
    
        return 0;
    }

算術運算子

  • 算術運算子的運算元與回傳結果都是『右值』。
算術運算子(左結合律) 功能 語法

+

-

一元正號

一元負號

+ expr

- expr

*

/

%

乘法

除法

餘數除法

expr * expr

expr / expr

expr % expr

+

-

加法

減法

expr + expr

expr - expr

  • 一元運算子優先級最高。接下是乘法、除法與餘數除法,優先級最低是加法與減法。

  • % 餘數除法要求兩側都須為『整數型態』,如 7 % 4 = 3

    int ival = 42;
    double dval = 3.14;
    ival % 12;               // 正確,結果為 6。
    ival % dval;             // 錯誤。運算元是 double 型態。
  • 一元正(負)號運算子對運算元取正(負)號後,其回傳的是『副本』。

    bool b = true;
    bool b2 = -b;              // b2 也是 true!。
    
    std::cout << b2 << std::endl;
    std::cout << std::boolalpha << b2 << std::endl;  // std::boolalpha 是 I/O 運算子,可使 std::cout 將 true 和 false 打印出字串而不是整数。
    • 不應該對布林值進行運算。上述 -b 就是一個典型的例子。

    • 對大多數運算子而言,布林型態的運算元將會被提升至 int 型態。故上述例子,參與運算後將被提升為整數值 1 ,對他取負號後為 -1。接著再將其轉換為布林型態,並作為 b2 的初始值,而此初始值並非為 0。故轉換為布林值後其值為 1,故 b2 值為 true

    • std::boolalpha 是 C++ 標準程式庫中的一個 I/O 操縱器(manipulator),其使得 std::ostream(如 std::cout)和 std::istream(如 std::cin)可以用來顯示和讀取 bool 型態值為 truefalse 而不是 10。可在輸出和輸入時,更加直觀地顯示和處理布林值。

    • 補充:

      • 在 C 和 C++ 中,printf 函數有一組『格式(format)字元』,用於將不同型態的變數格式化並打印。以下是常用的 printf 格式字元:

        • %d%i:輸出整數。

        • %u:輸出無符號整數。

        • %f:輸出浮點數。

        • %e%E:輸出科學計數法表示的浮點數。

        • %g%G:輸出最適合的格式(%f 或 %e)。

        • %x%X:輸出十六進位整數。

        • %o:輸出八進位整數。

        • %c:輸出字元。

        • %s:輸出字串。

        • %p:輸出指標。

        • %%:輸出百分比字元(%)。

        這些格式字元還可以與其他標誌、寬度、精度等結合使用,以控制輸出格式。例如:

        • %5d:輸出一個至少5個字符寬的整數。

        • %05d:輸出一個至少5個字符寬,並且前導位置使用0填充的整數。

        • %.2f:輸出一個保留2位小數的浮點數。

基本的控制台輸入/輸出

  • 輸出的重要性:

    • 如果沒有辦法將程式的結果展示給使用者或傳遞給其他應用程式,那麼編寫程式碼就沒有意義。因此,學會如何輸出資料是所有程式員都必須掌握的基本技能。
  • 輸入的重要性:

    • 使用者希望能夠通過軟體輸入數據,這些數據將被軟體用來生成結果。因此,學會如何從使用者那裡接收輸入也是程式設計中非常重要的一部分。
  • C++的基本輸入/輸出命令:

    • 本節介紹了一些基本的C++命令,用於將資料輸出到螢幕和從鍵盤接收資料輸入。這是學習C++程式設計的第一步,掌握這些基本命令是後續學習和應用的基礎。
    #include <iostream>
    using namespace std;
    
    int main() {
        int num;
        cout << "Enter a number: ";
        cin >> num;
        cout << "The number you entered is " << num << endl;
        return 0;
    }
    • 這個程式碼展示如何使用cin從鍵盤接受輸入,並將輸入的資料輸出到螢幕。

assert 語句

  • assert語句是一種用於進行程式內部錯誤檢查的工具。它允許開發者在程式中插入檢查點,確保某些條件在程式運行過程中始終為真。如果條件為假,assert語句將觸發錯誤,並通常會使程式崩潰。這在開發和調試階段非常有用,因為它可以幫助快速定位程式中的邏輯錯誤和不一致性。

    #include <iostream>
    #include <cassert> // 包含<cassert>頭文件
    
    using namespace std;
    
    int main() {
        int a = 5;
        int b = 0;
    
        // 使用 assert 語句檢查 b 是否為 0
        assert(b != 0); // 這行會導致程式崩潰,因為 b 確實是 0
    
        int c = a / b; // 這行程式不會被執行
        cout << "a / b = " << c << endl;
    
        return 0;
    }
    • 在這個範例中,我們用assert語句檢查變數b是否為0。由於b的值確實是0,所以assert(b != 0)會失敗,並且程式會終止執行並顯示錯誤信息。
  • assert語句中的條件為假時,標準錯誤輸出(通常是控制台)會顯示一條錯誤信息,其中包括失敗的條件、原始檔案檔名和發生錯誤的行號。這些訊息對於調試非常有幫助,因為它們可以幫助開發者迅速定位問題的來源。

    #include <iostream>
    #include <cassert>
    #include <cmath>
    
    using namespace std;
    
    int main() {
        double a;
        cout << "Enter a nonnegative number: ";
        cin >> a;
    
        assert(a >= 0); // 檢查 a 是否為非負數
    
        double result = sqrt(a); // 計算 a 的平方根
        cout << "The square root of " << a << " is " << result << endl;
    
        return 0;
    }

使用建議

  • 開發階段使用: assert語句主要在開發和調試階段使用,以檢查程式中的假設和前提條件。

  • 避免在生產環境使用: 在生產環境中,應該避免使用assert語句,因為它會使程式崩潰。相反,應該使用適當的錯誤處理機制來處理可能的錯誤狀況。

  • 檢查前提條件: 使用assert語句來檢查函數參數的有效性、數據的一致性和不變性。