C语言概述

1. C 语言概述

欢迎来到程序员的世界,学习编程和学习武林秘籍其实是一个道理,在最初选择的时候需要慎之又慎,一旦选错再想回头就难了。

1.1 一些基本概念

1.1.1 编程语言

作为一个程序猿,想要学习程序编写,就必须搞清楚一个概念:何为编程语言?语言是人与人之间用于沟通交流的工具,由此进行推导就能知道编程语言是计算机与程序员之间进行沟通和交互的工具。它是一种用于编写计算机程序的形式化语言,可以指导计算机执行特定的操作和任务。

编程语言通过定义语法语义规则来规定程序员如何组织、写入和表达他们的程序。程序员可以使用编程语言来编写代码,这些代码会被翻译或解释成可执行的计算机指令,从而实现特定的功能、控制计算机硬件,或处理数据。

基于编程语言的执行方式,大致可以分为以下三类:

  1. 编译型语言:需要在运行之前通过编译器转换为机器代码,例如C、C++。
  2. 解释型语言:在运行时逐行解释和执行程序代码,例如Python、Ruby、JavaScript。
  3. 半编译型语言:结合编译和解释执行的特点,例如Java、C#。

一些常见的编程语言包括:

  • C/C++:通用的编程语言,广泛用于系统开发和底层编程。
  • Java:面向对象的编程语言,用于开发跨平台的应用程序。
  • Python:通用的解释型脚本语言,易于学习和使用。
  • JavaScript:用于前端和后端web开发的脚本语言。
  • Ruby:简洁易读的脚本语言,适用于快速开发。
  • Swift:用于iOS和macOS应用程序开发的编程语言。
  • Go:由Google开发的高性能编程语言,用于并发和网络编程。
  • Rust:注重内存安全和并发的系统编程语言。

每种编程语言都有其优势和特定的用途。选择适合你项目需求和个人喜好的编程语言,可以帮助你更高效地实现你的编程目标。

1.1.2 源文件和头文件

在C语言中,通常将程序分为源文件头文件

  • 源文件(source file)包含了实际的可执行代码,它们是编译器直接编译和生成目标文件的文件。源文件的扩展名通常为.c

  • 头文件(header file)包含了函数、变量和类型的声明,用于在源文件中引用这些声明的内容。头文件通常包含在源文件中,以便在编译过程中可以验证函数调用、变量声明等的正确性,并且在连接过程中可以正确地解析符号引用。头文件的扩展名通常为.h

下面是一个示例,展示了一个简单的C语言源文件(main.c)和头文件(mylib.h)的结构:

  • 头文件示例

    1
    2
    3
    4
    5
    6
    7
    // mylib.h 头文件
    #ifndef MYLIB_H
    #define MYLIB_H

    // 函数声明
    int add(int a, int b);
    #endif
  • 源文件示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // main.c 源文件
    #include <stdio.h>
    // 包含自定义头文件
    #include "mylib.h"

    int main()
    {
    int result = add(3, 5);
    printf("Result: %d\n", result);
    return 0;
    }

对于初学者,上面的代码我们是不需要看明白的,只需要知道有C程序中的文件分为两类:头文件(xxx.c)和源文件(xxx.h),并且知道它们对应的文件后缀是什么即可。

1.1.3 标准库

程序需要用到的功能,不一定需要自己编写,C 语言可能已经自带了。程序员只要去调用这些自带的功能,就省得自己编写代码了。举例来说,printf()这个函数就是 C 语言自带的,只要去调用它,就能实现在屏幕上输出内容。

C 语言自带的所有这些功能,统称为“标准库”(standard library),因为它们是写入标准的,到底包括哪些功能,应该怎么使用的,都是规定好的,这样才能保证代码的规范和可移植。

不同的功能定义在不同的文件里面,这些文件统称为“头文件”(header file)。如果系统自带某一个功能,就一定还会自带描述这个功能的头文件,比如printf()的头文件就是系统自带的stdio.h。头文件的后缀通常是.h

如果要使用某个功能,就必须先加载对应的头文件,加载使用的是#include命令。这就是为什么使用printf()之前,必须先加载stdio.h的原因。

1
#include <stdio.h>

注意,加载头文件的#include语句不需要分号结尾。

1.1.4 编译器

对于C/C++程序员来说,程序编写完毕之后,还需要通过编译器进行编译,这样才能得到我们需要的可执行程序。C语言有多个编译器可供选择,每个编译器有自己的特点和用途。以下是一些常用的C语言编译器:

  1. GCC (GNU Compiler Collection):GCC是一个开源的编译器套件,支持多种编程语言,包括C语言。它是许多操作系统和开发环境的默认编译器,具有广泛的平台支持和强大的优化能力。
  2. Clang:Clang也是一个开源的编译器套件,与GCC类似,具有良好的兼容性和优化能力。Clang的设计注重可读性和易于扩展,提供了丰富的错误和警告信息。
  3. Visual C++:Visual C++是微软公司提供的一个C语言编译器,包括在Visual Studio集成开发环境中。它提供了丰富的调试工具和Windows平台的特定功能,并与其他Microsoft技术和工具紧密集成。
  4. Intel C++ Compiler:Intel C++ Compiler是由Intel开发的高度优化的C语言编译器,专用于Intel处理器架构。它提供了针对Intel处理器的专用优化选项,可以生成高性能的代码。
  5. MinGW(Minimalist GNU for Windows):MinGW 是基于 GNU 的工具链,包括 GCC (GNU Compiler Collection)、GNU Binutils 和 GNU Debugger。它提供了一套用于在 Windows 上开发和编译 C 和 C++ 程序的工具集。

以上只是一些常见的C语言编译器,还有其他编译器可供选择。在选择编译器时,需考虑平台兼容性、性能优化、调试工具和开发人员的个人偏好等因素。

1.1.5 集成开发环境 (IDE)

程序员编写的程序就是代码,C代码就是成员和计算机之间相互交流的暗号,其实就是一些有特殊含义的文字,我们可以把这些文件直接写到电脑的记事本中,然后通过编译器进行编译就可以生成一个可执行程序,也就是Windows中常见的 xxx.exe文件。

但是对于初学者来说根本就不知道编译器如何使用,所以我们可以使用一些没有门槛的编程工具,这类工具用一个统称叫做IDE。IDE是集成开发环境(Integrated Development Environment)的缩写。它是一种软件应用程序,旨在为开发者提供一个集成的工作环境,方便他们进行软件开发、编码和调试等任务。一个IDE通常包含以下主要组件:

  1. 代码编辑器:提供代码编写和编辑功能,具有语法高亮、自动完成、缩进等特性,以提高编码效率和准确性。
  2. 编译器/解释器:将编写的源代码转换为可执行文件或解释执行的代码。IDE通常会集成相应的编译器或解释器,方便开发者进行代码编译和执行。
  3. 调试器:提供调试功能,如断点设置、单步执行、变量查看等,用于定位和修复代码中的错误或问题。
  4. 项目管理:用于创建、管理和组织项目文件和目录结构,方便开发者管理和查看项目。
  5. 版本控制集成:支持与版本控制系统(如Git、SVN等)集成,方便开发者进行代码版本管理、协作开发和版本回退等操作。
  6. 其他辅助工具:IDE可能还包含其他辅助工具,如代码模板、自动化构建工具、性能分析器等,以提供更全面的开发支持。

流行的IDE有很多种,常见的包括Eclipse、IntelliJ IDEA、Visual Studio、Xcode、PyCharm等。开发者可以根据自己的编程语言和需求选择适合自己的IDE,它可以大大提高开发效率和代码质量。

C/C++ 程序猿常用的IDE有以下三种:

  • Visual Studio:由微软公司开发的集成开发环境(IDE),用于软件开发、应用程序的编码、调试和部署等任务。它支持多种编程语言,包括C/C++、C#、VB.NET、F#、Java、JavaScript、Python等。
  • CLion:由JetBrains公司开发的集成开发环境(IDE),专门用于 C 和C++ 语言的开发。它被设计为为 C 和 C++ 开发者提供强大的功能和工具,以提高他们的生产力和代码质量。
  • Qt Creator:由Qt开发团队开发的集成开发环境(IDE),专门用于跨平台的应用程序开发。它是 Qt 框架的官方集成开发环境,为开发者提供了丰富的工具和功能,用于快速创建、调试和部署 Qt 应用程序。程序员也可以使用它用于 C/C++ 程序的开发。

1.1.6 终端

在计算机领域中,控制终端是指用户与计算机系统进行交互的设备或接口。它允许用户输入命令和数据,以及接收计算机系统的输出信息。

控制终端可以是以下几种形式之一:

  1. 终端窗口:在图形用户界面(GUI)环境中,终端窗口通常是一个模拟的字符终端,提供一个命令行界面(CLI)用于输入命令和查看输出。常见的终端窗口如 Windows 的命令提示符窗口(Command Prompt),以及在 Linux 和 macOS 下的终端窗口,如 GNOME 终端、Konsole、iTerm2 等。
  2. 终端仿真器:终端仿真器是一种软件应用程序,可以模拟不同类型的终端,如 VT100、xterm 等。它们通常提供对远程主机的访问,通过网络协议(如 SSH、Telnet)连接到远程计算机,并提供一个虚拟的终端界面。
  3. 控制台:控制台是指计算机本身提供的物理终端设备,通常是一个文本显示屏幕和键盘组合。在早期的计算机系统中,控制台是用户与计算机交互的主要方式,例如使用磁带操作机、打孔卡、操作终端等。

通过控制终端,用户可以输入命令、执行程序、查看文件、管理系统等。终端提供了与计算机系统进行交互的接口,使用户能够控制和管理计算机的各种操作。

需要注意的是,随着图形用户界面的普及,许多用户更喜欢使用图形界面和可视化工具来进行计算机操作。然而,控制终端仍然在系统管理、软件开发、自动化脚本和服务器管理等领域中起着重要的作用。

1.1.7 内存

内存是程序员学习C/C++过程中提及频率非常高的一个概念,在此简单的为大家做一个介绍,如果是初学者从现在开始就必须对它有一个模糊的认识,随着后续的学习会对这个概念的理解慢慢变得清晰,直到深入骨髓。

  • 从宏观上看:
    • 内存是真实存在的,肉眼可见,就是我们计算机上插的内存条
    • 内存属于物理电子设备,需要供电
  • 从微观上看:
    • 内存条由一系列存储单元组成,每个存储单元可存储一定量的数据。每个存储单元都有唯一的地址(相当于家庭住址,门牌号),用于访问和读写数据。
    • 内存就是一块存储数据的区域,肉眼不可见
    • 写入到内存中的数据也不可见,并且数据可以重复写入(覆盖原数据)
    • 断电之后内存数据丢失

C/C++程序猿要做的事情就是从微观层面触发,基于内存存储单元的地址(根据门牌号找房子),对内存进行读(参观房子)或者写操作(装修房子)。

1.1.8 计算机存储单位

对于计算机中的内存大小是可以通过专门的计量单位来衡量的,按照从小到大的顺序排列如下:

单位 大小
位(bit)【比特】 二进制的 0 或 1
字节(Byte) 一个字节等于8个比特位
千字节(kilobyte,KB) 等于 1024 字节
兆字节(megabyte,MB) 等于 1024 千字节
吉字节(gigabyte,GB) 等于 1024 兆字节
太字节(terabyte,TB) 等于 1024 吉字节
拍字节(petabyte,PB) 等于 1024 太字节
艾字节(exabyte,EB) 等于 1024 拍字节
叶字节(zettabyte,ZB) 等于 1024 艾字节
尧字节(yottabyte,YB) 等于 1024 叶字节

这些存储单位都存在于微观世界,无法用肉眼去观测,关于它们之间的换算记住即可。

  • 程序员最常用单位是:bit、byte、MB、GB
  • 内存大小的基准单位是字节(byte),各个单位之间的关系为1024
  • 字节(byte)的组成单位是比特位(bit)1byte = 8bit

存储容量的单位是按照二进制的方式进行增加的,每一级都是1024的倍数。这是因为计算机存储是按照二进制进行处理的。

1.2 为何要学 C 语言

C是一门功能强大的专业化编程语言,深受业余编程爱好者和专业程序员的喜爱。学习C语言有以下几个重要的原因:

  1. 基础语言:C语言是许多其他高级编程语言的基础。学习C语言可以帮助你理解计算机编程的基本概念和原理,如变量、数据类型、控制流、函数等。这些概念在其他语言中也存在,并且很多编程语言的语法都受到C语言的影响。
  2. 系统编程:C语言在系统级编程和底层开发中应用广泛。许多操作系统、嵌入式系统、驱动程序等都是使用C语言编写的。学习C语言可以让你深入了解计算机的底层工作原理和操作系统的实现。
  3. 性能优化:C语言提供了更高的性能和灵活性,并且允许直接操作内存。如果你对性能敏感的应用程序(比如游戏开发、图形处理、算法优化等)有兴趣,学习C语言可以让你更好地控制程序的性能。
  4. 跨平台开发:C语言具有良好的可移植性,可以在多个平台上使用。许多跨平台的开源项目和库都是使用C语言编写的,如MySQL、SQLite、Python等。学习C语言可以使你获得更广阔的开发机会。
  5. 深入理解编程:由于C语言相对较底层,学习C语言可以促使你更深入地理解计算机的工作原理和编程的本质。它可以帮助你在更高级别的语言中更好地解决问题、调试代码,并理解高层抽象背后的实现细节。
  6. 面向程序员:C 语言是为了满足程序员的需求而设计的,程序员利用 C 可以访问硬件、操控内存中的位。C 语言有丰富的运算符,能让程序员简洁地表达自己的意图。

尽管C语言有一些挑战和复杂性,但它仍然是一门非常有价值的编程语言,对于想要深入了解计算机编程和系统级开发的人来说是必学之语言。同时,C语言也是学习其他编程语言的基础,在编程职场中具有广泛的适应性

1.3 C语言的应用领域

C语言具有广泛的应用领域,尤其强调效率、底层控制和跨平台特性。以下是C语言的一些主要应用领域:

  1. 系统编程:C语言在操作系统和底层系统开发中应用广泛。许多操作系统的内核以及设备驱动程序都是使用C语言编写的。通过C语言,可以直接访问底层硬件资源,实现高效的系统级编程。
  2. 嵌入式系统:C语言被广泛用于嵌入式系统的开发,如微控制器、单片机、嵌入式设备等。嵌入式系统通常资源有限,对性能和内存要求较高,而C语言的底层控制和直接访问内存的能力使其成为首选语言。
  3. 游戏开发:许多游戏开发引擎和游戏框架都使用C语言作为底层语言,因为C语言提供了高性能、直接访问硬件的能力。游戏引擎如Unity、Unreal Engine等都使用C语言作为底层编程语言。
  4. 嵌入式图形和图像处理:C语言在图形和图像处理的应用领域也非常广泛。例如,图像处理库OpenCV就是使用C语言编写的,用于进行图像处理、计算机视觉和机器学习等领域的开发。
  5. 网络编程:C语言在网络编程中也非常常见。许多网络库和协议都是使用C语言编写的,例如套接字编程、网络通信、Web服务器等。
  6. 编译器和解析器开发:由于C语言本身的特性使得它非常适用于编写编译器和解析器。因此,许多编译器的前端和解释器都是使用C语言编写的,例如GCC、Python、Perl、Pascal、BASIC解释器等。

需要注意的是,虽然C语言在很多领域中广泛应用,但对于不同的应用,可能会使用不同的高级语言或领域特定语言来实现更高层次的功能。然而,了解和掌握C语言对于理解计算机编程的基本原理和底层工作机制,以及进行底层系统和性能优化方面的开发仍然非常重要。

1.4 学习 C 语言的困惑

很多人认为如果学习C++就不用学习C语言,其实这是不正确的,C++其实包括两部分:

  • C的部分:C++的基础就是C语言,直接学C++也是从C的部分开始学起。
  • ++的部分:这是对C语言的拓展,包括新的语法和和新的编程方式(面向对象编程,C语言是面向过程编程)。

另外,C语言是一门完美的语言吗?非也非也。

  • 金无足赤,人无完人。C语言也是如此。要享受用C语言自由编程的乐趣,就必须承担更多的责任。特别是,C语言使用指针,而涉及指针的编程错误往往难以察觉。

  • C 语言紧凑简洁,结合了大量的运算符。正因如此,我们也可以编写出让人极其费解的代码(国际C语言混乱代码大赛是一项国际编程赛事,每年举办一次,目的是写出最有创意且最让人难以理解的C语言代码)。

2. 第一个C程序 - Helloworld

电脑并不聪明,它的唯一优势是它遵守你的指令。电脑可以连续几天地处理你提供的数据,既不会感到厌烦也不会要加班费。

电脑不能自己决定做什么。电脑不能独立思考,所以程序员(programmer,告诉电脑要做什么的人)必须给电脑极其详细的指令。不发指令,电脑就毫无用处。若没有详细的指令,电脑无法处理你的工资表,正如汽车不能自己发动并在街上行驶一样。为了让电脑执行某项具体任务而提供给它的详细指令集合就是程序(program)。

我们来看一个简单的C程序,该程序演示了用C语言编程的一些基本特性。先试着通读程序,看看自己是否能明白该程序的用途:

1
2
3
4
5
6
7
8
9
10
11
/* 
这是我写的第一个C语言程序,
源文件名字为: hello.c
*/
#include <stdio.h>
int main()
{
// 打印一个字符串
printf("hello world\n");
return 0;
}

接下来让我们逐行剖析一下上面的这段代码。

2.1 注释

在C和C++中,有几种方式可以添加注释来提供代码的解释和说明。注释是程序中的非执行文本,编译器会忽略它们。

在 C 和 C++ 中的注释有两种类型类型:

  1. 单行注释:以双斜杠 // 开头的注释,从//开始一直到行尾都会被视为注释。例如:

    1
    // 这是一个单行注释
  2. 多行注释:以/*开始,以*/结束的注释块。可以跨越多行。例如:

    1
    2
    3
    4
    /* 
    这是一个多行注释
    我不是代码, 我的作用是对代码进行描述, 解释
    */

    示例程序中的 1~4 行就是一个多行注释。

注释的作用是对代码进行解释、说明,方便其他开发人员阅读和理解代码的意图。良好的注释可以提高代码的可读性和可维护性。

2.2 include 头文件包含

#include 是 C/C++ 中的预处理指令,用于包含头文件(header file)到当前源代码文件中。头文件通常包含了函数、变量和类的声明,以便在当前文件中可以使用这些声明的内容。

示例程序第 5 行,#include <stdio.h> 代表包含stdio.h这个头文件,这个头文件是 C标准库给我们提供的,可以直接使用。

关于头文件的包含有两种方式,初学者一定要牢记于心:

  • #include <>:< > 表示系统直接按系统指定的目录检索
  • #include "":”” 表示系统先在 “” 指定的路径(没写路径代表当前路径)查找头文件,如果找不到,再按系统指定的目录检索

对上面的描述进行归纳,在使用的时候可以遵循以下两个规则:

  1. 如果包含的头文件是标准库头文件,在包含的时候就将其写入到 <> 中
  2. 如果包含的头文件是自定义头文件,在包含的时候就将其写入到 “” 中

温馨提示: 此处的 “” 是英文字符,写错之后会出现语法错误,切记!!!

2.3 main() 函数

main() 函数(又称主函数)是在 C 和 C++ 程序中的一个特殊函数,在一个完整的 C/C++ 程序中该函数有且只能有一个。它是程序的起点和入口,也就是说程序是从 main 函数开始执行的。

C语言中的函数分为四部分:

  • 函数名:函数的名字,一般都是根据函数功能起名
  • 参数列表:给函数传递的数据,参数全部被放到函数后边的()中
  • 函数体:参数列表()后边的 { } 中的内容就是函数体
  • 返回值:函数名前边的关键字对应的就是函数的返回值类型

通过上面的描述我们就可以对示例程序中的代码进行解读了:

  • 第 6 行:主函数 main,没有参数,返回值为 int 类型
  • 第 7 ~ 11 行:main 函数的函数体,由于 main 函数是程序入口,所以程序启动之后从第 9 行开始执行(第8行是注释,不是代码)。
  • 第 9 行:不知道这是在干啥,通过第8行注释知道是进行了数据打印
  • 第 10 行:return 0 ,return 就是返回的意思,返回了一个整数 0,也就意味着 int对应的类型是整形。

在此处对函数概念有个大致的了解就可以了,后边讲到函数部分再详细给大家进行阐述。

2.4 printf

简而言之,printf()函数的作用是把字符、数字和单词发送到屏幕上。printf()有很多选项,但是我们不必精通所有这些选项也照样可以使用printf()在屏幕上进行输出。

printf 是标准C库中给我们提供的一个函数,这个函数对应两个文件:

  • 头文件:对函数进行声明,告诉使用者/编译器有这样一个函数的存在
  • 源文件:对函数进行实现,也就是在函数的函数体内部对函数进行定义,以此来实现该函数的功能。
1
2
#include <stdio.h>
int printf(const char *format, ...);

通过printf函数就可以在程序中进行数据输出,将其打印到终端。

3. C 程序的组成

在学习C语言之前,我们有必要搞清楚一个完整的C程序是由哪几部分组成的,我们需要先对它有一个整体上的认识,接下来再学习细节的时候才能有的放矢。

image-20230722154520348

通过上图我们可以知道一个C程序中需要包括以下内容:

  1. 预处理指令:包含头文件(#include),或者宏定义(#define

    • 所有的#开头的行,都代表预处理指令
    • 预处理指令行结尾处没有分号
  2. 程序入口函数(主函数):main 函数

  3. 其它函数:库(标准C库、第三方库)函数或者自定义函数

  4. 语句:程序的最小组成单位

    • 所有的可执行语句必须写到代码块里面

    • 每条语句后边都需要加分号;

C 语言中的语句可简单可复杂,并且需要用到一些关键字、标识符、运算符、数据等,再后边会给大家一一展开进行讲解。

4. C语言的编译过程

关于C语言的编译过程作为初学者可以不求甚解,在此大致给大家介绍一下,以满足部分好学之士的求知欲。C代码编译成可执行程序经过4步:

  1. 预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法

  2. 编译:检查语法,将预处理后文件编译生成汇编文件

  3. 汇编:将汇编文件生成目标文件(二进制文件)

  4. 链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去

image-20230722160439690

对于上述的编译过程,对于初学者来说可谓是一头雾水,如果理解不了那就可以先跳过,等学习一段时间之后再回来细细品味。

作为程序员都是基于IDE进行代码的编写,上述流程IDE会非常贴心的帮助我们进行自动化处理,唯一需要程序猿做的就是程序的编写。