如何运行程序?

C语言是一种编译型语言,也就是说计算机不会直接解释代码,而是需要将给人阅读的源代码转化(或编译)为机器能够理解的机器代码,这样计算机才能够执行。

为了编译代码,需要一个叫编译器的程序。GNU编译器套件(GNU Compiler Collection),也叫gcc,是最流行的C编译器之一。gcc可以在很多操作系统中使用,而且除了C语言,它还可以编译很多其他语言,最重要的是,它是完全免费的。

下面是用gcc编译并运行程序的过程:

  • 将前一页那道“代码冰箱贴”练习中的代码保存在一个叫cards.c的文件中。

如何运行程序? - 图1

  • 在命令提示符或终端中使用gcc cards.c -o cards命令

如何运行程序? - 图2

  • 在Windows命令提示符中输入cards或在Mac和Linux终端中输入./cards运行程序。

如何运行程序? - 图3

如何运行程序? - 图4百宝箱

在大部分机器中,可以用下面这个技巧来编译并运行代码:

如何运行程序? - 图5

这条命令只有在编译成功的情况下才会运行新程序,一旦编译过程中出了问题,它就会跳过运行程序这一步,仅仅在屏幕上显示错误消息。

如何运行程序? - 图6

现在就应该创建cards.c文 件,然后编译它。随着本章内容的展开,我们会在它的基础上逐步改进。

如何运行程序? - 图7试驾

让我们来看看程序能否成功编译和运行。在你的机器上打开命令提示符或终端,试试吧!

如何运行程序? - 图8

程序工作了!

恭喜!你已经成功编译并运行了C程序。gcc编译器从cards.c中提取出了供人阅读的源代码,并将其转换为cards程序中机器才能理解的机器代码。如果你用的是Mac或Linux,计算机会在一个叫cards的文件中创建机器代码;而在Windows中,所有程序的扩展名必须是.exe,因此这个文件叫cards.exe

这里没有蠢问题

问:为什么我在Linux和Mac中运行程序时必须在程序前加上./?

:因为在类Unix操作系统中,运行程序必须指定程序所在的目录,除非程序的目录已经列在了PATH环境变量中。

如何运行程序? - 图9

C语言不支持现成的字符串。如何运行程序? - 图10

C语言比其他大多数语言的抽象层次更低,因此它不提供字符串,而是用了相似的东西来代替:以字符为元素的数组。如果你用过其他语言,一定已经见过数组了,数组就是一张有名有姓的事物清单,所以card_name只是一个变量名,用来引用你在命令提示符输入的那张字符列表的。把card_name定义为大小为2个字符的数组,就可以用card_name[0]card_name[1]分别引用第一和第二个字符。为了理解字符串的工作原理,让我们深入计算机的存储器,看看C语言是如何处理文本的……

如何运行程序? - 图11字符串聚焦

字符串只是字符数组,当C语言看到一个这样的字符串时:

  1. s = "Shatner"

会把它当做一个数组读取,而这个数组是由一个个独立的字符组成的:

如何运行程序? - 图12

字符串中的每个字符是数组中的一个元素,这就是为什么可以通过索引来引用字符串中的某个字符,比如s[0]s[1]

如何运行程序? - 图13

别在字符串的尽头掉下去

当C语言想要读取字符串中的内容时,会发生什么呢?比如说它想打印字符串吧。在如今的很多语言中,计算机会时刻记录数组的大小,但C语言比大多数语言更低层,它无法确切地知道数组有多长,如果C语言想在屏幕上显示字符串,它就需要知道什么时候会到达字符数组的尾部,为此C语言加入了哨兵字符。

如何运行程序? - 图14

哨兵字符是一个出现在字符串末尾的附加字符,它的值为\0。每当计算机需要读取字符串的内容时,它会逐一扫描字符数组中的所有元素,直到碰到\0,也就是说当计算机看到下面这个字符串时:

  1. s = "Shatner"

存储器中实际保存的是:

如何运行程序? - 图15

这就是为什么我们要在代码中像这样定义card_name变量:

  1. char card_name[3];

字符串card_name只需要记录1到2个字符,但因为字符串要以哨兵字符结尾,所以我们必须把数组的大小定义为3,以放下一个额外的字符。

 

这里没有蠢问题

问:为什么字符要从0开始编号?为什么不是1?

:字符的索引值是一个偏移量:它表示当前要引用的这个字符到数组中第一个字符之间有多少字符。

问:为什么要这样做?

:计算机在存储器中以连续字节的形式保存字符,并利用索引计算出字符在存储器中的位置。如果计算机知道c[0]位于存储器1 000 000 号单元,那么就可以很快地计算出c[96]在1 000 000 + 96号单元。

问:为什么要设立哨兵字符?难道计算机就不知道字符串的长度吗?

:通常不知道。记录数组的长度不是C语言的强项,字符串其实就是个数组。

问:C语言居然不知道数组有多长?

:是的,虽然编译器有时可以通过分析代码计算出数组的长度,但一般情况下,C语言希望你来记录数组的长度。

问:单、双引号有区别吗?

:有区别,单引号通常用来表示单个字符,而双引号通常用来表示字符串。

问:我应该用双引号(")定义字符串,还是以显式字符数组的形式定义字符串?

:通常应该用双引号来定义字符串。用双引号定义的字符串叫字符串字面值(string literal),比起字符数组,它输入起来也更方便。

问:字符串字面值和字符数组有没有区别?

:只有一个区别:字符串字面值是常量。

问:那是什么意思?

:也就是说这些字符一旦创建完毕,就不能再修改它们。

问:如果我改了会怎么样?

:这取决于编译器,gcc通常会显示总线错误(bus error)。

问:总线错误?那是什么东西?

:C语言采取不同的方式在存储器中保存字符串字面值。总线错误意味着程序无法更新那一块存储器空间。

 

如何运行程序? - 图16虎口拔牙

“等号”不一定表示等于。

在C语言中,“等号”(=)用来赋值(assignment),而“双等号”用来检查两个值是否相等。

如何运行程序? - 图17

如果想要增加或减小变量的值,可以用+=和-=这两个赋值运算符,它们让代码看起来更简短。

如何运行程序? - 图18

最后,如果想要对变量的值加 1 或减 1 ,可以用 + + 和--。

如何运行程序? - 图19