1. 程式人生 > >現代C語言程式設計之C語言概述

現代C語言程式設計之C語言概述

1.1 資訊科技發展趨勢

目前資訊科技主要經歷了網際網路、移動網際網路以及以大資料、雲端計算、物聯網、人工智慧、區塊鏈為代表的新興技術三個階段。

  • 網際網路
    網際網路從20世紀90年代逐漸興起,主要是通過網路連線了世界各地的筆記本、桌上型電腦以及背後提供後臺資料服務的伺服器叢集,其中絕大多數筆記本和桌上型電腦都執行著Windows,macOS系統,而伺服器主要是以類Unix(CentOS,Ubuntu)佔據主要市場優勢,依靠網際網路成長起來的公司有微軟、谷歌、蘋果、亞馬遜、百度、阿里巴巴、騰訊等等。
  • 移動網際網路
    移動網際網路主要是通過網路連線了世界各地的移動裝置(最典型的就是手機),它們絕大多數都執行著Android,IOS系統,依靠移動網際網路公司成長起來的有美團、滴滴、小米、螞蟻金服。
  • 雲端計算、大資料
    當然隨著使用者資料的爆發式增長,以海量資料為基礎的大資料、雲端計算技術在BAT,Apple,Microsoft,Amazon,Google級別的超大型網際網路公司有廣泛的應用場景。
  • 物聯網
    物聯網會以手機為中樞,通過網路連線所有智慧裝置,包括智慧家居、汽車、電視等嵌入式裝置。
  • 人工智慧
    人工智慧(AI)作為當前最火爆的技術之一,國內的BAT紛紛開始根據自身核心業務佈局,阿里巴巴最早將人工智慧應用在電商和物流領域,而百度開發出了對話時人工智慧作業系統Dueros和自動駕駛平臺Apollo,而騰訊則是在遊戲領域應用人工智慧。
  • 區塊鏈
    而區塊鏈經歷了數字貨幣、智慧合約、和超級賬本三個發展階段,區塊鏈技術可以廣泛使用在金融、供應鏈、物流、公共服務領域,解決網際網路的信任問題。
    目前螞蟻金服已經有大量的區塊鏈應用落地。

1.2 淺談計算機系統架構

1.2.1 計算機硬體系統

現代計算機是由運算器、控制器、儲存器、輸入裝置、輸出裝置五大部分組成,它們各司其職,完成了資料的計算、儲存、傳輸任務,下面是它們各個元件的功能介紹:

  • CPU
    也被稱為中央處理器,由運算器和控制器組成,其主要作用是資料計算(從記憶體中獲取指令並執行後將結果返回給記憶體或者寫入到磁碟)和控制其他裝置(音效卡顯示卡,滑鼠鍵盤)協同工作。目前主流的CPU架構有基於Intel的複雜指令集的X86架構(32位和64位)和手機(ARM指令集),伺服器(SPARC指令集)的精簡指令集。CPU通過匯流排(資料匯流排、地址匯流排、控制匯流排)和外部進行互動。
  • 記憶體
    採用編址儲存,其主要作用是用來作為程式的工作區,程式執行時其資料和指令會被載入到記憶體,斷電後資料會丟失。
  • 硬碟
    其主要作用是永久性儲存海量資料,分為機械式硬碟和固態硬碟兩大類。
  • IO裝置
    其主要作用是用來資料的輸入輸出,常見的輸入裝置包括滑鼠鍵盤,常見的輸出裝置包含音效卡,顯示卡,印表機等等。網絡卡主要是負責資料在網路上的傳輸。

在後期程式排錯時除了考慮程式本身的錯誤之外還要考慮計算機硬體故障(例如磁碟被寫滿,網路不通)等問題。

每個計算機元件的IO效能也各不相同,核心元件(CPU,記憶體,磁碟)都遵循容量越大,IO效能越差,如下圖所示,彙總了它們的IO效能。
IO效能彙總

在後期程式優化時,通常需要考慮時間複雜度和空間複雜度的問題。

1.2.2 計算機軟體系統

軟體出現的作用是實現了人和計算機更好的互動,它是由開發人員採用某種程式語言來編寫一系列的指令以及根據不同的業務邏輯產生的資料組成。

而軟體通常被分為系統軟體和應用軟體

  • 系統軟體:
    系統軟體有執行在伺服器端的Unix,Linux,執行在PC桌面的macOS,Windows;執行在移動裝置(手機、電視)的Android,ios;系統軟體通常是負責管理硬體資源,同時給應用軟體提供執行平臺。
  • 應用軟體:
    應用軟體有執行在PC桌面、手機端的淘寶、京東、微信、支付寶等等。

不同平臺的軟體有不同的互動方式:

  • 伺服器端:
    運維開發人員基於命令列的字元介面實現人機互動。
  • PC桌面端:
    開發人員、設計人員、產品經理、普通使用者通常是基於圖形化介面實現人機互動。
  • 移動端:
    普通使用者通常是通過語音,手勢觸控實現人機互動。

1.2.3 常用應用的軟硬體協作實現

計算機程式執行流程如下圖所示
計算機程式執行流程

  • 聊天:應用程式監聽鍵盤輸入的資料,放到記憶體,然後傳給網絡卡,通過網路傳遞給另外一個網絡卡,再從網絡卡傳到記憶體,顯示在顯示器上。
  • 聽音樂:應用程式將音樂資料載入到記憶體之後,然後寫到音效卡上。
  • 看視訊:應用程式將視訊資料載入到記憶體,然後寫到顯示卡上。
  • 讀文件: 應用程式將磁碟中的文件資料載入到記憶體後顯示到螢幕上。
  • 寫文件: 應用程式將記憶體中的資料寫入到磁碟上。

1.3 程式和指令

  • 程式:
    程式是為了完成某項特定任務(例如聊天,聽音樂等等)而使用某種程式語言編寫的一組指令序列
  • 指令:
    令是對計算機進行程式控制的最小單位,由操作碼和運算元組成,操作碼指的是機器要執行什麼操作(例如加減乘除),而運算元就是具體執行的物件(具體的資料以及存放資料的位置),所有指令的集合稱為計算機的指令系統,常見的電腦指令系統有Intel X86指令集,常見的手機指令系統有ARM。因此手機上的應用程式不加修改是不能在電腦上直接執行,因為不同的指令集是不相容的。

1.4 程式語言發展史及其應用場景

1.4.1 編譯器與高階語言

首先明確一點,計算機最底層只能識別二進位制(010101)的機器指令,那些由組合語言或者是高階程式設計語言編寫的應用程式只是為了方便開發人員理解和維護,這就需要將組合語言和高階語言翻譯成計算機能夠理解的機器語言,而編譯器或者直譯器就是做這個工作的。它的出現讓開發人員在編寫程式時不用考慮底層硬體的差異性,只需要專注業務邏輯的實現即可。

1.4.2 程式語言發展史

任何事物都是從無到有,逐步發展壯大起來的,程式語言也是一樣。

計算機程式設計語言經歷了機器語言到組合語言和高階程式設計語言三個階段,其特點是使得程式設計師用程式語言開發、測試、部署應用程式越來越方便、高效。但是是以犧牲效率為代價,但是隨著計算機硬體的發展,絕大多數應用場景的效率損失可以忽略不計。

  • 機器語言
    計算機發展的最早期,程式設計師編寫程式採用二進位制的指令(010010101)來實現的,而每種CPU都有各自不同的指令系統(SPARC/Intel X86/ARM),因此在不同的機器上使用不同的機器語言實現。其特點是效能特別高效,而面向機器程式設計也就意味著不能移植,需要手動處理底層硬體的差異性,而且二進位制的指令難以理解和維護。
  • 組合語言
    隨著時代和計算機技術的發展,組合語言和編譯器的出現解決了機器語言需要記住非常多的二進位制機器指令的難題,但是還是沒有從根本上解決移植性的問題,只是將機器指令轉換為易懂的英文單詞,然後由編譯器編譯成機器指令,因為計算機終歸揭底只能識別0001110100110機器指令,而且組合語言是面向機器的,不同機器(SPARC/Intel X86/ARM)的彙編指令是不相同的。
  • 高階程式設計語言
    高階程式設計語言的高階之處體現在開發人員在編寫程式時無需關心計算機底層硬體差異而只需要專注於業務模組實現即可。甚至是可以實現 一次編譯,到處執行,這裡以Java為例子:通過實現不同平臺的JVM,編譯生成的位元組碼檔案可以在任意的JVM上執行。
    高階語言通常都需要編譯器或者是直譯器將原始碼編譯或者解釋後執行。

高階語言主要分為面向過程和麵向物件兩種,其中典型的面向過程語言就是C,面向物件的程式語言有Java,C++等等。

1.4.3 程式語言應用場景

如果想知道目前主流的程式語言有哪些,可以訪問tiobe 首頁獲取程式語言排行榜,如下圖所示,從Tiobe官網獲取最新(2018年12月)的程式語言排行榜的前20名,
程式語言排行榜
根據Tiobe排行榜得知,Java/C/C++分別排在前三名, 隨後緊跟著Python,C#,PHP,JavaScript等等,每種語言都有不同的應用場景和擅長的領域,如下表格所示。

程式語言 應用場景
C 硬體驅動、作業系統、系統軟體
C++ 系統軟體、網路通訊、科學計算 、遊戲
C# Windows應用,Web應用、遊戲
Java 大型網際網路應用(淘寶、天貓),Android,大資料
Python 人工智慧、機器學習、自動化運維、資料分析 、圖形處理
PHP 中小型網站開發
Objective-C/Swift macOS,iPhone,iPad應用開發
JavaScript 瀏覽器端、服務端、PC桌面
Go 高併發、區塊鏈

那麼如果你作為一個野生程式設計師的初學者,面對如此之多的程式語言,到底應該先從哪門語言上車呢?如果你想深入的學習其他語言和架構相關的知識之前建議熟練掌握C語言。因為C++/Java/C#等程式語言都模仿了C語言。無論哪種語言,都是實現目標的工具,而不是目標本身。

1.5 C語言概述

C語言憑藉其高效率、良好的移植性、功能強大的特性在作業系統、硬體驅動以及系統應用開發佔據廣闊的市場。

1.5.1 C語言發展簡史

  • 起源
    1972年,貝爾實驗室的Dennis Ritch和Ken Thompson在開發Unix作業系統時設計了C語言,該作業系統的90%以上的程式碼都是由C語言實現,後期的Linux,MacOS,Android,IOS都是基於Unix發展而來的。
  • 標準
    1987年Dennis Ritch和Brian Kernighan編寫了The C Programming Language第一版是公認的C標準實現,而沒有定義C庫。
    而後期ANSI/ISO先後於1990年、1999年和2011年釋出了C90標準、C99標準和C11標準,該標準定義了C語言和C標準庫。

1.5.2 C語言特性

C語言作為面向過程的高階程式設計語言,能夠輕鬆的實現自頂向下的規劃結構化程式設計模組化設計,這樣使得程式結構更加簡潔,可擴充套件性強以及更加容易維護。

而且C語言有著高效、功能強大(嵌套匯編)以及可移植性(標準庫可移植)等優點,而且也存在著對系統平臺庫依賴嚴重,由於程式設計風格自由,經驗不足也會容易導致出錯,編寫程式碼實現週期長,同樣的程式碼在不同的作業系統(或者編譯器)下可能會有不同的表現等缺點。

1.5.3 C語言應用場景

C語言偏向作業系統、硬體驅動、底層應用、嵌入式應用開發,硬體驅動的絕大部分實現是由C語言和組合語言實現的。
目前主流作業系統(Unix,Linxu,MacOS,Windows,Android,iOS)的底層實現都是由C語言和部分彙編實現的。
C++,Java,Python,Swift的編譯器或者直譯器都是由C語言實現的。
Git,Nginx,Redis,MySQL都是使用C語言實現的,而且都是開放原始碼的,可以通過閱讀原始碼提升自己的設計和編碼能力。

1.6 C語言開發環境搭建

1.6.1 C語言開發環境概述

目前主流作業系統(Windows,Linux,MacOS)都有完善的C語言整合開發環境,用於編輯、編譯、除錯、打包部署C程式,下面表格是各個作業系統對應的整合開發環境說明。

作業系統 開發工具
Windows10 Visual Studio2017
macOS10.14 XCode10
Ubuntu18.04 QT5.10

Windows作為世界上最流行的桌面作業系統,最新版本為Windows10 1809,VisualStudio作為Windows上最強大的整合開發環境,可以開發Windows軟體,遊戲,Web應用等等,最新版本為VisualStudio2017 15.8.9。

Ubuntu作為最受歡迎的桌面版Linux系統之一,推薦採用跨平臺的整合開發環境QT來編寫C/C++程式。

MacOS平臺推薦使用XCode來編寫C/C++程式。

除此以外還有些跨平臺的C/C++ 開發工具,例如來自Jetbrains公司的CLion以及CodeBlocks也可以用來編寫C/C++程式。

1.6.2 Windows10 安裝Visual Studio 2017

  1. 官網下載Visual Studio 2017 企業版的線上安裝程式,如下圖所示
    下載Visual Studio 2017企業版

  2. 啟動安裝程式
    根據下載的路徑查詢安裝程式並啟動,啟動完成後會看到如下圖所示的程式
    visual studio_installler
    點選繼續之後會自動下載元件列表

  3. 選擇安裝元件
    選擇安裝元件
    這裡選擇通用Windows平臺開發和使用C++桌面開發兩個元件,然後點選右下角的安裝,此時Visual Studio 2017會自動下載和安裝所需元件,只需要耐心等待即可,如下圖所示

    安裝選擇的元件

  4. 首次啟動設定
    安裝完成之後需要設定主題和開發模板,還要登入你的microsoft賬號,如下圖所示
    啟動設定

  5. 啟動介面
    visual studio 啟動介面

  6. 檢視安裝Visual Studio 2017的版本
    點選幫助選單,檢視關於Microsoft Visual Studio的選單
     點選幫助選單,檢視關於Microsoft Visual Studio的選單
    然後會彈出如下版本資訊以及包含元件的視窗
    visual studio 2017 版本資訊

1.6.3 VisualStudio2017整合GitHub

  • GitHub概述
    GitHub是一個免費、基於Git的開源專案託管站點,全世界許多公司的開源專案(例如Spring,Mybatis,阿里巴巴美團點評等等)的原始碼都存放在GitHub,個人也可以上傳自己的專案到GitHub,可以為自己的就業簡歷加分。
    如果想要使用GitHub,首先需要訪問官網,註冊賬號後即可使用。

1.下載GitHub外掛
啟動Visual Studio2017後,通過選單工具->擴充套件和更新->

下載GitHub外掛

然後選擇擴充套件和更新的聯機選單來搜尋GitHub外掛,點選下載。如下圖所示

選擇擴充套件和更新的聯機選單來搜尋GitHub外掛,點選下載

下載介面如下圖所示

下載示意圖

下載成功之後會出現需要重啟Visual Studio的提示
重啟Visual Studio

  1. 安裝GitHub
    在關閉Visual Studio之後,會自動彈出安裝介面,如下圖所示
    安裝介面

    根據提示,選擇修改,如下圖所示
    選擇修改

    安裝GitHub外掛,如下圖所示
    正在安裝GitHub外掛

    安裝成功,如下圖所示
    安裝成功

  2. 登入GitHub
    首先啟動Visual Studio 2017,切換到團隊資源管理器的檢視,然後點選GitHub的連線,如下圖所示
    連線GitHub
    然後會出現登入介面,如下圖所示
    登入GitHub
    輸入你在GitHub上註冊的賬號資訊即可登入GitHub了,登入成功之後的介面如下圖所示
    登入成功之後的介面

  3. 建立程式碼倉庫
    在團隊資源管理器檢視的GitHub下點選建立選單,如下圖所示
    建立專案
    然後設定倉庫名稱、描述、本地路徑以及Git忽略和許可證資訊,如下圖所示
    設定倉庫資訊
    建立完成之後的介面如下圖所示
    倉庫資訊
    GitHub外掛會自動建立倉庫,並推送到GitHub網站,可以通過地址https://github.com/ittimeline/modern-c-programming 訪問到該專案

1.6.4 基於VisualStudio+Github實現C語言helloworld

  1. 建立解決方案
    在團隊資源管理器檢視下建立解決方案
    建立解決方案

    設定解決方案的專案模板,名稱,路徑資訊,如下圖所示
    解決方案配置

    然後再切換到解決方案檢視下檢視解決方案
    解決方案總覽
    解決方案的目錄結構說明

  • 原始檔用於存放c語言的原始碼

  • 標頭檔案用於存放C語言庫函式依賴的標頭檔案

  • 資原始檔用於存放專案相關的資源

  • 使用Visual Studio 2017實現C語言的helloworld
    首先新建篩選器,並命名為Chapter1

    新建篩選器

    Chapter1

    然後在篩選器下新建helloworld.c檔案
    選擇新增->新建項
    新建項

    選擇基於C++的原始檔
    新建helloworld.c
    編輯執行介面如下圖所示
    編輯、執行介面
    應用案例(Chapter1/helloworld.c)如下所示

#include <stdio.h>
#include <stdlib.h>

/*
    基於Visual Studio 2017實現的C語言版helloworld
    @author tony [email protected]
    @version  2018/11/19 15:04:07
*/
void main() {

    printf("hello world with Windows10 & Visual Studio 2017\n");
    //按任意鍵退出程式,如果不加上 程式執行完成後就會退出
    system("pause");

}

程式執行效果如下圖所示
執行效果
如果你想在任何有網路連線的地方使用你的程式碼,只需要將其推送到遠端倉庫即可。
首先切換到團隊資源管理器,然後點選更改,如下圖所示
切換到團隊資源管理器
然後輸入程式碼說明的提交資訊,如下圖所示,再點選全部提交,會將程式碼提交到本地

程式碼說明的提交資訊

再輸入提交資訊,並點選同步和推送後會將程式碼推送到GitHub

同步

推送

推送成功之後會看到如下提示資訊

推送成功

1.7 記事本程式設計實現helloworld

helloworld通常是用來形容學習一門程式語言的入門程式,如果你能夠獨立把helloworld獨立編寫、編譯、執行成功,那麼就算是邁入計算機程式設計的大門了。

1.7.1 helloworld編寫

C語言的原始檔字尾名是以.c結尾的,可以使用任意的文字編輯工具(例如記事本,Notepad++,UltraEdit,Visual Studio Code等等,)來編寫簡單的C程式

這裡通過Windows10自帶的記事本來編寫源程式helloworld.c,源程式如下所示

#include <stdio.h>

void main(){
    printf("歡迎跟光磊一起學習C語言");
}

1.7.2 編譯、執行源程式

之前提到過,計算機底層只能識別二進位制的機器語言,這裡使用C語言編寫的源程式無法試別,因此需要一個編譯器來將其轉換為二進位制的機器指令。
各大作業系統(Windows,Linux,macOS)都有C語言編譯器的實現,這裡以Visual Studio 2017提供的編譯器來編譯C程式。

首先通過Windows10提供的搜尋功能找到 VS 2017的開發人員命令提示符

VS 2017的開發人員命令提示符

然後使用cd命令切換到C語言源程式的所在路徑,接著使用cl命令編譯源程式,並執行編譯、連結生成的可執行檔案helloworld.exe,如下圖所示

編譯執行C程式

1.8 helloworld深入解析

1.8.1 #include預編譯指令

如果想要呼叫函式的某個方法,必須首先包含該方法所在的標頭檔案,例如呼叫printf()函式,就是位於系統目錄C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\ucrt下的標頭檔案stdio.h。如果該檔案在當前目錄下,使用#include "標頭檔案",如果該標頭檔案在系統目錄下,則使用#include <>。編譯器查詢當前目下的標頭檔案時如果未找到,還會去系統目錄下查詢對應的標頭檔案。
#include的作用實際上就是將包含的檔案全部複製到原檔案中,接下來編寫一個C程式來演示#include的作用

首先在c-core-programming專案的標頭檔案資料夾中新建(Ctrl+Shift+A)一個頭檔案guanglei.h,C語言中的標頭檔案通常是以.h結尾,如下圖所示
guanglei.h
標頭檔案(guanglei.h)如下所示

#include <stdio.h>

/*
     #include預編譯指令
    @author tony [email protected]
    @version  2018/11/19 15:46:07

*/
void main() {

    printf("執行guanglei.h標頭檔案中的內容\n"); //這裡的\n表示換行
    getchar(); //等待輸入任意字元退出
}

然後在c-core-programming專案的原始檔資料夾下建立原始檔include.c,該原始檔的
原始碼如下所示

//包含專案路徑下的guanglei.h標頭檔案
#include "guanglei.h"

然後執行專案後,發現如下錯誤
執行錯誤
其原因是Visual Studio 2017中的單個解決方案下的程式只能有一個入口,即main方法,為了解決這個問題,需要把之前的源程式helloworld.c的main方法重新命名為其他函式(例如helloworld_main)即可。
後續章節中給出的程式碼預設都是帶main方法可以獨立執行的,但是GitHub倉庫中的程式碼需要確保只有一個main方法才可執行

再次執行程式,程式執行結果如下圖所示,也再次表明#include的內容會被複制到原始檔中。
程式執行結果

1.8.2 main函式

在Windows下,一個C語言的應用程式如果想獨立執行,必須有main方法作為程式的入口,main方法的宣告格式如下程式碼片段所示,所有的程式程式碼從main方法開始執行。

void main(){

}

其中void表示該函式沒有返回值,而在Linux下,編譯器強制要求main函式返回為int,程式碼片段如下所示

int main(){

}

1.8.3 return語句

return通常用在函式中,表示退出該函式,這也就意味著return之後的程式碼都不會被執行。而C語言的編譯器比較鬆散,即使函式在定義時有返回值,而實現沒有返回值也不會編譯錯誤,但是卻會得到一個錯誤的結果,應用案例(Chapter1/return.c)如下所示

#include <stdio.h>

/*
    定義兩個整數相減的函式,返回兩個整數的差
    @author tony [email protected]
    @version  2018/11/19 15:50:07
*/
int sub(int one, int two) {
    return one - two;
    printf("return之後的語句不會在執行了");
}

/*
    定義兩個整數相加的函式,返回兩個整數的和
    @author tony [email protected]
    @version  2018/11/19 15:50:07
*/
int add(int one, int two) {
    return one + two;
}

/*
    return關鍵字
    @author tony [email protected]
    @version  2018/11/19 15:49:07
*/
void return_main() {
    printf("sub方法呼叫的結果是%d\n", sub(20, 10));
    printf("add方法呼叫的結果是%d\n", add(100, 200));
    getchar();

}

1.8.4 斷點和除錯

在後期程式開發中可能會遇到各種各樣的錯誤,這時我們就需要利用Visual Studio 2017提供的強大的除錯功能來查詢錯誤。

在除錯之前首先得下斷點,如下圖所示
斷點
然後在執行程式時,程式會在下過斷點的地方暫停,然後可以通過點選如下的箭頭,選擇每次執行一行,還是每次執行一個方法。
執行方式
還可以通過Visual Studio 2017的選單 除錯->視窗檢視記憶體、暫存器等資訊
除錯資訊
例如這裡通過變數的記憶體地址檢視對應儲存的資料
記憶體中的資料
應用程式(Chapter1/debug.c)如下所示

/*
    除錯方法
    @author tony [email protected]
    @version  2018/11/19 16:42:07
*/
void debug_method() {

    printf("使用visual studio的逐過程除錯\n");
}

/*
    處理資料函式
    @author tony [email protected]
    @version  2018/11/19 16:42:07
*/
void handle_data_method() {

    printf("處理資料函式\n");
}
/*
    visual studio的除錯功能應用
    通過斷點檢視記憶體,逐語句、逐方法除錯程式
    @author tony [email protected]
    @version  2018/11/19 16:42:07
*/
void main() {

    int age = 29;
    printf("整數變數age的地址是%p\n", &age);
    printf("整數變數age的值是%d\n", age);
    debug_method();
    handle_data_method();
    system("pause");
}

1.8.5 註釋

為了便於程式的後期維護,C語言支援單行註釋//和多行註釋/**/,註釋用於描述程式的功能,編譯器在編譯時會將註釋的內容刪除,需要注意的是多行註釋的內容不能巢狀,否則會發生編譯錯誤,應用案例(Chapter1/comment.c)如下所示

#include <stdio.h>
#include <stdlib.h>

/*
    C語言註釋和單行註釋的使用
    @author tony [email protected]
    @version  2018/11/19 17:15:07
*/

void main() {

    //列印輸出helloworld的兩種方式

    printf("hello world \n"); // \n表示換行
    system("echo hello world\n");
    system("pause"); //程式暫停,按任意鍵退出

}

1.9 Windows常用命令

主流的作業系統(Windows,Linux(Ubuntu),MacOS)及大多數應用程式都提供了基於命令列和圖形化介面兩種互動方式,而移動端是採用手勢觸控、語音等進行互動。作為普通使用者來講,圖形化介面容易上手,而且互動效果更加直觀。

但是作為一個程式設計師來講,應該去熟悉各個作業系統的命令列的使用,因為命令列相對圖形化介面而言,絕大多數場景下使用更加高效。而且圖形化介面本質是對命令列的封裝,能用圖形化介面實現的基本都可以採用命令列實現。而且在伺服器端(CentOS,RedHat)基本上是不會安裝圖形介面。

Windows系統可以使用快捷鍵Windows+r調出執行,如下圖所示

cmd

後輸入cmd,便可以進入Windows下的命令列終端,如下圖所示
dos命令視窗
Windows下常用的檔案目錄和系統應用相關的命令如下所示,只要開啟了終端就可以在終端內通過使用檔案目錄相關和系統應用相關的命令實現快捷操作。

1.9.1 檔案目錄相關

命令名稱 功能描述
dir 列出當前目錄列表
cd 切換目錄(只能在根碟符(例如C盤)內切換)
md 建立目錄
del 刪除檔案
type 顯示文字檔案內容
cls 清除螢幕內容
exit 退出終端

1.9.2 系統應用相關

命令名稱 功能描述
notepad 記事本
calc 計算器
mspaint 畫圖
explore 檔案資源管理器
timedate.cpl 日期和時間
cleanmgr 磁碟清理
desk.cpl 解析度設定
powercfg.cpl 電源設定
regedit 登錄檔編輯器
msconfig 系統配置
mstsc 遠端連線
firewall.cpl 防火牆
appwiz.cpl 新增或修改程式
tasklist 檢視程序列表
taskkill /f /im process.exe 關閉指定程序
msinfo 系統資訊
sticky notes 便籤
ipconfig 檢視ip
winver 檢視windows版本
echo 顯示文字內容 例如echo %path% 檢視系統環境變數
dxdiag DirectX診斷工具

1.10 system函式的使用

system函式是位於系統路徑下的stdlib.h標頭檔案中,用於呼叫各大作業系統的應用程式,如下應用案例所示(Chapter1/system.c)展示了讀取使用者輸入的命令後通過system函式執行呼叫應用程式。

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <stdlib.h>

/*
    使用system函式執行使用者輸入的命令
    @author tony [email protected]
    @version  2018/11/19 17:19:07
*/
void main() {

    printf("請輸入你要執行的命令\n");
    //定義陣列儲存使用者輸入的指令
    char str[100] = { 0 };
    //使用scanf函式讀取使用者輸入的指令
    scanf("%s", str);
    //執行命令
    system(str);

}

在使用scanf()函式時,需要定義常量#define _CRT_SECURE_NO_WARNINGS來關閉編譯器檢查。

因為system函式是位於系統路徑下的stdlib.h標頭檔案中,因此是可以實現跨平臺呼叫系統下的命令。
如下應用案例所示,是在Ubuntu下實現的系統命令呼叫。

#include <stdio.h>
#include <stdlib.h>
int main(){

    printf("請輸入你要執行的命令\n");
    //定義陣列儲存使用者輸入的指令
    char str[100] = { 0 };
    //使用scanf函式讀取使用者輸入的指令
    scanf("%s", str);
    //執行命令
    system(str);
    return 0;
}

當使用system呼叫多個應用應用程式時會產生同步的效果,如下應用案例(Chapter1/system_sync.c)所示

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>

/*
    system函式的同步特性
    @author tony [email protected]
    @version  2018/11/19 17:21:07
*/
void main() {
    //system函式的同步特性
    system("notepad"); //當開啟記事本之後
    Sleep(5000);//等待5秒鐘
    system("tasklist"); //只有自己手動關閉記事本後才會執行檢視任務列表
    system("taskkill /f /im notepad.exe");//並沒有關閉記事本
}

而如果想要system函式非同步執行,只需要傳遞start引數即可,如下應用案例(Chapter1/system_async.c)所示

#include <stdlib.h>
/*

    如果想非同步執行呼叫多個應用程式,可以加上start引數實現 但是這隻針對系統路徑下的應用程式有效
    @author tony [email protected]
    @version  2018/11/19 17:23:07

*/
void main() {
    //加上start引數之後會發現記事本和計算器同時開啟,此時非同步執行
    system("start notepad");
    system("calc");
}

1.11 C語言程式設計流程

1.11.1 實現開啟windows下的記事本,並在5秒之後關閉

實現思路:

  1. 首先使用sytem函式加上start引數非同步開啟記事本
  2. 然後藉助Windows.h標頭檔案的Sleep函式實現程式等待5秒
  3. 最後藉助taskkill /f /im notepad.exe 命令關閉記事本。

完整應用案例(Chapter1/open_and_close_notepad.c)實現如下所示

#include <stdlib.h>
#include <Windows.h>
/*
    開啟記事本並在5秒之後就關閉
*/
void main() {

    //非同步執行
    system("start notepad");

    Sleep(5000);

    system("taskkill /f /im notepad.exe");

}

1.11.2 實現開啟windows下的QQ,並根據使用者輸入的時間關閉QQ

完整的應用案例位於Chapter1/open_and_close_qq.c原始檔中。

首先引入相關函式的標頭檔案

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>

然後定義一個開啟QQ的函式openQQ,如下所示
,使用ShellExecuteA()函式可以避免system函式的同步問題,因為system函式的start引數只能作用於不帶路徑的程式。

/*
    開啟QQ
    @author tony [email protected]
    @version  2018/11/19 17:27:07
*/
void openQQ() {
    ShellExecuteA(0, "Open", "\"C:/Program Files (x86)/Tencent/QQ/Bin/QQScLauncher.exe\"", 0, 0, 1);
}

然後定義sleep函式,如下所示:使用printf函式給予使用者提示輸入指定的秒數,使用scanf函式讀取使用者輸入的資料,使用Sleep()函式暫停

/*
    暫停
    @author tony [email protected]
    @version  2018/11/19 17:27:07
*/
void sleep() {
    int second = 0;
    printf("請輸入多久後關閉QQ\n");
    scanf("%d", &second);
    printf("QQ將在%d秒後關閉\n", second);
    int i = 1;
    while (i <= second) {

        Sleep(1000);
        printf("睡了%d秒\n", i);
        i++;
    }
}

最後定義關閉QQ的函式closeQQ,如下所示,只需要使用命令taskkill /f /im QQ.exe,即可關閉QQ。

/*
    關閉QQ
    @author tony [email protected]
    @version  2018/11/19 17:27:07
*/
void closeQQ() {
    system("start taskkill /f /im QQ.exe");
}

然後main函式中分別引用上述函式即可實現功能

/*
    開啟並根據使用者輸入的時間關閉QQ
    @author tony [email protected]
    @version  2018/11/19 17:27:07
*/
void main() {
    openQQ();
    sleep();
    closeQQ();

}

通過以上兩個案例總結下C語言的程式設計流程:

  1. 需求分析:分析程式要實現哪些功能
  2. 概要設計:分解步驟,一步一步實現
  3. 編寫程式碼:使用C語言相關特性詳細實現
  4. 編譯程式:使用編譯器將原始碼編譯連結成作業系統上的可執行檔案
  5. 執行程式:載入到記憶體後執行
  6. 測試和除錯程式:觀察程式的執行過程,是否符合預期,如果不符合,需要更改。
  7. 維護和修改程式:根據不同的業務邏輯來調整程式

1.12 C語言的執行流程

C語言編寫的程式如果沒有使用特定平臺的庫,那麼便可以執行在各大作業系統之上,這裡以Ubuntu上的gcc編譯器為例,瞭解C程式的執行流程。

首先編寫源程式,推薦使用Ubuntu上的VisualStudio Code編寫。

#include <stdio.h>
int  main(){

    printf("hello world with ubuntu18.04&visual studio code\n");

    <