• C 语言简单入门


    1 C语言发展历史|标准

    1972年,丹尼斯·里奇(Dennis Ritch)在贝尔实验室和肯·汤普逊(Ken Tompson)开发 UNIX 操作系统时基于 B 语言(由肯·汤普逊开发)设计出 C 语言。

    1987年,布莱恩·柯林汉(Brian Kernighan)和丹尼斯·里奇合著的 《The C Programming Language》(《C 语言程序设计》)第 1 版是公认的 C 标准,称之为 K&R C 或经典 C。

    1989年,C 语言被美国国家标准协会 ANSI 标准化为 ANSI C,其定义了 C 语言和 C 标准库。这套 C 标准也被称为 C89

    1990年,国际标准化组织 ISO 采用了 ANSI 制定的 C 标准,改为 ISO C。它与 ANSI C 是完全相同的。ISO C 也称为 C90

    1994年,ANSI/ISO联合委员会发布 C99 标准。其修改如下:

    1. 增加 3 个新的标准库头文件:iso646.hwctype.hwchar.h
    2. 几个新的记号与预定义宏,用于对国际化提供更好的支持。
    3. printf/sprintf 函数一系列的格式代码。
    4. 大量的函数与一些类型和常量,用于多字节字符和宽字节字符。

    2011年,ISO 发布了 C11 标准。

    C18

    C2X

    2 C语言的特性

    1. 可移植性(Portability):C语言的代码在不同平台上通常可以轻松移植,这意味着您可以在不同的计算机体系结构和操作系统上运行相同的代码,只需稍作修改。这得益于C语言的抽象性和硬件无关性。
    2. 高性能(Performance):C语言具有卓越的性能,因为它允许程序员对计算机硬件进行更低级别的控制。这使得C语言非常适合开发需要高性能的应用程序,如系统软件、嵌入式系统和游戏引擎。
    3. 低级别编程(Low-Level Programming):C语言允许程序员直接操作内存和硬件资源,包括指针操作、位操作和汇编语言嵌入。这使得C语言非常适合系统编程和硬件控制。
    4. 可扩展性(Extensibility):C语言允许程序员编写自己的函数和库,以扩展语言的功能。这使得C语言可以应对各种不同的问题领域。
    5. 面向过程编程(Procedural Programming):C语言是一种面向过程的编程语言,它以函数为基本构建块,使得程序的组织和管理变得简单。

    3 C语言的应用领域

    1. 系统编程:C 语言最初设计用于 Unix 系统的开发,因此在系统内核、驱动程序和系统工具的编写中得到广泛应用。它允许程序员直接访问计算机硬件,提供了对系统资源的更好控制。
    2. 嵌入式系统:C 语言的低级别控制和高效性使其成为嵌入式编程的理想选择,包括微控制器、嵌入式系统-on-chip(SOC)和嵌入式软件。
    3. 编译器和解释器:C 语言也用于编写其他编程语言的编译器和解释器。例如 Python 的 CPython 解释器就是用 C 语言写的。
    4. 游戏开发:虽然游戏的高级逻辑通常由 C++ 等语言编写,但是 C 语言在游戏引擎、图形编程和性能优化等方面仍起到关键作用。许多游戏的底层引擎和系统组件都是用C语言编写的。
    5. 数据库系统:关系型数据库管理系统(RDBMS)如 MySQL 和 PostgreSQL 使用 C 语言进行核心开发。C 语言的性能和可移植性对数据库系统至关重要。
    6. 网络编程:C语言广泛用于开发网络应用程序、服务器和协议栈。它提供了对底层网络套接字编程的支持,使得开发网络应用更加灵活。
    7. 图形编程:C语言用于开发图形应用程序、图形库和图形用户界面(GUI)工具包。例如,GTK+和Qt这些GUI库都支持C语言。
    8. 科学和工程计算:C语言在科学计算、数值分析和工程领域得到广泛应用,因为它的性能非常高。许多数学库和科学计算工具都使用C语言编写。
    9. 金融领域:C语言在金融领域用于高性能的金融建模、算法交易和数据分析应用程序的开发。其速度和精度对于金融计算至关重要。

    4 编译与链接

    C 语言编写的源代码文件以 .c 结尾。

    在这里插入图片描述

    编译器(compiler)将源代码编译成中间代码或目标代码,最普遍的中间代码是机器语言代码,但是中间代码还不能直接运行,因为缺少启动代码和库代码。启动代码是程序与操作系统间的接口,不同操作系统的启动代码不同。

    链接器最后把中间代码、系统的标准启动代码和库代码这三部分合并成一个文件:可执行文件。中间代码与可执行代码都由机器语言指令组成。

    5 C语言的关键字与保留标识符

    K&R C标准关键字:

    autoexternshortwhile
    breakfloatcasefor
    chargotostaticif
    structcontinueswitchdefault
    inttypedefdolong
    uniondoubleregisterunsigned
    elserestrictvoidreturn
    sizeof

    C89/C90新增标准关键字:

    1. signed
    2. const
    3. enum
    4. volatile

    C99新增标准关键字:

    1. inline

    C11新增标准关键字:

    1. _Alignas
    2. _Alignof
    3. _Atomic
    4. _Bool
    5. _Complex
    6. _Generic
    7. _Imaginary
    8. _Noreturn
    9. _Static_assert
    10. _Thread_local

    保留标识符包括那些以下划线字符开头的标识符和标准库函数名,如printf()scanf()malloc()等。

    6 C语言基本数据类型

    C语言的数据类型关键字:

    K&R C最初给出的C90新增C99新增
    intsigned_Bool
    shortvoid_Complex
    long_Imaginary
    char
    float
    double
    unsigned

    6.1 整数类型

    C语言针对不同使用情况,提供了多种整数类型。

    6.1.1 int

    int是常用的数据类型,被认为是计算机处理整型类型时最高效的类型

    int类型是有符号整型,可以是正负整数和零,第一位为符号位。

    int类型的取值范围与计算机处理器位数相关:16位的处理器使用16位来存储一个int值,取值范围为 − 2 15 = 32768 -2^{15} = 32768 215=32768 2 15 − 1 = 32767 2^{15} -1 = 32767 2151=32767,这也是ISO规定的int最小的取值范围;32位处理器则使用32位来存储一个int值;还有 64 位的。

    声明并初始化int变量

    在这里插入图片描述

    int a,b=1; // a并没有像b一样被初始化为1
    
    • 1

    表示八进制和十六进制:C语言默认数字常量是十进制,但在数字前添加0前缀表示8进制,添加0x0X前缀表示16进制。

    使用printf库函数在控制台打印int变量

    在这里插入图片描述

    十进制、八进制和十六进制的显示

    /*
    * 以指定格式显示整型
    */
    printf("%d %d\n", 010, 0x10); // 8 16
    printf("%o %o\n", 8, 0x10); // 10 20
    printf("%x %x\n", 16, 0x20); // 10 20
    /*
    * 以原型显示整型,即保留0、0x或0X前缀
    */
    printf("%#o %#o\n", 010, 0x10); // 010 020
    printf("%#x %#x\n", 010, 0x10); // 0x8 0x10
    printf("%#X %#X\n", 010, 0x10); // 0X8 0X10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    转换说明

    • %d —转为—> 十进制整数
    • %o —转为—> 八进制整数
    • %x —转为—> 十六进制整数
    • %#o —显示—> 八进制整数
    • %#x —显示—> 0x开头十六进制整数
    • %#X —显示—> 0X开头十六进制整数

    不被捕获的输出错误

    printf("%d %d",1); // 第二个%d没有提供值,它会打印出内存中的任意值
    
    • 1

    上面这种错误不会被编译器捕获,因为printf函数无法预知使用者传参数量。

    6.1.2 short

    short 是 short int 类型的简写,其占用存储空间不会比 int 多,可能相等,一般为 16 位。在某些情况下可以节省空间。

    short 的打印可以使用 %hd(十进制)、%ho(八进制)和 %hx(十六进制)。

    6.1.3 long

    long 是 long int 的简写,占用空间不比 int 少,一般为 32 位。适用于数值大的场合。

    long 的打印可以使用 %ld(十进制)、%lo(八进制)和 %lx(十六进制)。

    对于 long 类型常量,后缀要加 lL

    6.1.4 long long

    long long int 的简写,占用空间不比 long 少,至少占用 64 位。

    long long 的打印可以使用 %lld(十进制)、%llo(八进制)和 %llx(十六进制)。

    long long 类型常量后缀要加 llLL

    6.1.5 unsigned

    unsigned int的简写,表示无符号整型。

    C90 中添加了 unsigned longunsigned long int ,以及 unsigned shortunsigned short int

    C99 中添加了 unsigned long longunsigned long long int

    有符号类型前面都省略了signed。加上也无妨。

    常量后缀:

    类型后缀
    unsigned%u
    unsigned long%lu、%ul、%UL、%LU …
    unsigned long long%llu …

    ...后面显而易见了。

    6.2 字符类型:char

    在C语言中,字符类型主要用于表示单个字符。char 变量通常占用一个字节的内存空间,即8位,但其确切大小和编码方式可能因不同的编译器和平台而异。

    从技术层面看,char是整数类型,因为它实际上存储的是整数而非字符,特定整数用于表示特定的字符,这也是字符的编码,美国最常用的编码是ASCII(American Standard Code for Information Interchange),标准ASCII码使用7位二进制数表示0-9、a-z、A-Z、标点符号、美式英语中的特殊控制字符,剩余1位为0,这一位也使用在了扩展ASCII码

    字符常量和初始化

    char a = 'A'; // 使用单引号括起来的单个字符是字符常量
    
    • 1

    也可以使用数字初始化char变量,'A'的ASCII码是65:

    char a = 65; // 只适合使用ASCII编码的系统
    
    • 1

    C语言将字符常量视为int类型而非char类型,在int为32位、char为8位的系统中,它会把字符常量存储在32位的存储单元,但只取后8位

    char x = 'abcd'; // x 实际为 d
    
    • 1

    C语言中还有一些有趣的非打印字符,比如退格、换行、蜂鸣或响铃,它们可以用如下称为转义序列的字符表示。

    转义序列含义
    \a警报(ANSI C)
    \b退格
    \f换页
    \n换行
    \r回车
    \t水平制表符
    \v垂直制表符
    \\反斜杠
    \’单引号
    \"双引号
    \?问号
    \0xx八进制值
    \xhh十六进制值

    接下来是字符类型的打印了,printf函数使用%c作为字符类型的转换说明。如果使用%d打印字符,则会打印一个整数。

    printf函数中转换说明决定了数据的显示方式,而数据的声明决定了数据存储形式。

    C语言提供了两种主要的字符类型:charwchar_t

    wchar_t 是C语言中的宽字符类型,用于表示更广范围的字符,包括国际化字符集中的字符。

    wchar_t 变量的大小和编码方式因平台而异,通常会比 char 大。

    在C语言中,wchar_t 类型的变量可以用L前缀和单引号括起来,例如:wchar_t wideChar = L'宽';

    6.3 _Bool 类型

    _Bool类型用于表示布尔值,即truefalse。C99标准引入了这个数据类型,以提供对布尔逻辑的原生支持。

    _Bool类型原则上只占用1位存储空间,用0表示false,用1表示true

    要使用 _Bool 类型,需要包含 头文件。

    为了更方便地使用 _Bool,C标准库还定义了 bool 作为 _Bool 的别名。

    6.4 可移植类型

    为了提高可移植性,C99 新增了两个头文件 stdint.hinttypes.h

    stdint.h提供精确宽度整数类型(exact-width integer type)。例如 int32_t 表示 32 位的有符号整数,在 32 位 int 的系统中会将其作为 int 别名,而在 16 位 int、32 位 long 的系统中则会将其作为 long 的别名。但是,如果系统中并没有 32 位这么短的类型,那么这时就有问题了。

    因此,C99和 C11提供了最小宽度类型(minimum width type)来解决该情况。例如,int_least8_t 是可容纳 8 位有符号整数值的类型中宽度最小的类型的一个别名。如果系统最小数据类型是 16 位,那么int_least8_t可能被实现为 16 位。

    如果你更关心数据类型的速度而非空间,那么 C99 和 C11 也定义一组可使计算达到最快的类型集合,称为最快最小宽度类型。例如 int_fast8_t

    最后,还有最大整数类型 intmax_tuintmax_t

    这些类型都被包含在 stdint.h 中。

    inttypes.h 定义了一系列的宏,用于在格式化字符串中指定不同大小和带符号性质的整数类型。这些宏通常以PRISCN开头,后面跟随整数类型的缩写,例如 PRId32 用于表示带符号32位整数的格式宏,PRIu64 用于表示无符号64位整数的格式宏。这些宏可用于 printfscanf 等函数,以确保在不同平台上正确处理整数类型的输入和输出。

    printf("%"PRId32"",x); 
    // PRId32被定义在inttypes.h中的d替换
    // 因此,上行代码等价于:
    printf("%"d"",x); => printf("%d",x);
    
    • 1
    • 2
    • 3
    • 4

    6.5 浮点类型

    C语言中的浮点类型有floatdoublelong double。浮点类型用于金融和数学领域的场合。

    一般计数法:120.55

    科学计数法:1.2055 x 10^2

    指数计数法:1.2055e2

    float 类型至少表示小数点后 6 位有效数字,取值范围为 1 0 − 37 至 1 0 37 10^{-37} 至 10^{37} 10371037

    float 类型通常占据 32 位,采用 IEEE 754 标准来表示浮点数,其中 8 位用于表示指数的符号和值,另外 24 位用于表示尾数及其符号

    尾数范围是-1~1,指数范围是-128~128,底数是2,所以float类型的范围是 − 2 − 128 − 2 128 -2^{-128} - 2^{128} 21282128

    IEEE 754 是一个用于浮点数表示和计算的标准,它定义了浮点数的二进制表示方法、舍入规则以及基本算术运算规则。

    让我们考虑一个单精度浮点数:0 10000010 10010000000000000000000。

    IEEE 754 单精度浮点数由三个部分组成:符号位(Sign Bit)、指数部分(Exponent)、小数部分(Fraction/Mantissa)。让我们一步步来解剖这个例子:

    1. 符号位(Sign Bit):第一个位是符号位。0 表示正数,1 表示负数。在这个例子中,符号位是0,所以这是一个正数。
    2. 指数部分(Exponent):接下来的 8 位是指数部分。这个部分用于表示浮点数的指数。在 IEEE 754 中,指数采用偏移表示法,即需要减去一个偏移值来得到真实的指数。偏移值为127(单精度浮点数的情况)。所以,在这个例子中,指数部分是 10000010。要计算真实的指数,需要将它解释为二进制,然后减去偏移值:
      10000010 (二进制) = 130 (十进制) 真实的指数 = 130 - 127 = 3
    3. 小数部分(Fraction/Mantissa):剩下的位数(23 位)组成小数部分。这个部分用于表示浮点数的精度和小数部分。在这个例子中,小数部分是 10010000000000000000000。

    现在,我们有了这些部分的值,我们可以计算出这个浮点数的实际值。根据 IEEE 754 的规则,实际值可以计算为:

    实际值 = (-1)^符号位 × 1.10010000000000000000000(二进制) × 2^真实的指数

    在这个例子中:

    • 符号位是 0,表示正数。
    • 小数部分是 1.10010000000000000000000(二进制)。
    • 真实的指数是 3。

    现在,我们可以将这些值代入公式中来计算实际值:

    实际值 = (-1)^0 × 1.10010000000000000000000 × 2^3

    实际值 = 12.5(十进制)

    double 是双精度浮点型,与 float 最小取值范围相同,但是最小有效数字必须至少为 10 位,double 一般占用 64 位实际上,double类型的值至少有13位有效数字

    long double 至少与 double 精度相同。

    有效的浮点型常量的示例:

    3.14
    .2
    2e2
    .2E-2
    10.
    
    • 1
    • 2
    • 3
    • 4
    • 5

    默认情况下,浮点型常量被认为是double类型的精度。在浮点数后加上fF后缀可以覆盖这种行为,被认为是float类型。加上lL后缀则会使得数字成为long double类型。

    打印浮点数:printf函数使用%f打印十进制记数法的float、double类型浮点数,使用%e打印指数记数法的浮点数,使用LfLe打印long double类型。

    浮点数的上溢(overflow)和下溢(underflow)

    上溢指计算结果超出当前类型能表示最大范围:

    float toobig = 1e30 * 1e30f; // toobig上溢,会被赋值为一个表示无穷的值,如inf、infinity
    
    • 1

    下溢指损失了类型全精度的计算,得到的结果称为低于正常的(subnormal)浮点值,通常发生在尾数部分非常小,以至于无法用规格化的方式表示时。在这种情况下,尾数部分会被右移,以适应更小的指数值。比如将最小的正浮点数除以2。

    还有一个特殊的浮点值NaN(Not a Number),比如给asin函数传递一个大于1的参数就会返回NaN。

    7 复数和虚数类型

  • 相关阅读:
    C语言学习之路(工具篇)—— Visual Studio的使用
    搭建统一的依赖管理
    R语言使用zoo包中的rollapply函数以滚动的方式、窗口移动的方式将指定函数应用于时间序列、计算时间序列的滚动标准差(设置每个窗口不重叠)
    JMU软件20Linux考试复习
    leetcode分类刷题:基于数组的双指针(四、小的移动)
    在访问一个网页时弹出的浏览器窗口,如何用selenium 网页自动化解决?
    七年之痒!一个 PHP 程序员职业生涯的自述
    Python中的Numpy向量计算(R与Python系列第三篇)
    Java程序设计——注解(Java高级应用)
    Btrace入门
  • 原文地址:https://blog.csdn.net/2201_75288929/article/details/133206671