如何运行程序?
C语言是一种编译型语言,也就是说计算机不会直接解释代码,而是需要将给人阅读的源代码转化(或编译)为机器能够理解的机器代码,这样计算机才能够执行。
为了编译代码,需要一个叫编译器的程序。GNU编译器套件(GNU Compiler Collection),也叫gcc
,是最流行的C编译器之一。gcc
可以在很多操作系统中使用,而且除了C语言,它还可以编译很多其他语言,最重要的是,它是完全免费的。
下面是用gcc
编译并运行程序的过程:
- 将前一页那道“代码冰箱贴”练习中的代码保存在一个叫cards.c的文件中。
- 在命令提示符或终端中使用
gcc cards.c -o cards
命令
- 在Windows命令提示符中输入
cards
或在Mac和Linux终端中输入./cards
运行程序。
百宝箱
在大部分机器中,可以用下面这个技巧来编译并运行代码:
这条命令只有在编译成功的情况下才会运行新程序,一旦编译过程中出了问题,它就会跳过运行程序这一步,仅仅在屏幕上显示错误消息。
现在就应该创建cards.c文 件,然后编译它。随着本章内容的展开,我们会在它的基础上逐步改进。
试驾
让我们来看看程序能否成功编译和运行。在你的机器上打开命令提示符或终端,试试吧!
程序工作了!
恭喜!你已经成功编译并运行了C程序。gcc
编译器从cards.c中提取出了供人阅读的源代码,并将其转换为cards
程序中机器才能理解的机器代码。如果你用的是Mac或Linux,计算机会在一个叫cards
的文件中创建机器代码;而在Windows中,所有程序的扩展名必须是.exe,因此这个文件叫cards.exe。
这里没有蠢问题
问:为什么我在Linux和Mac中运行程序时必须在程序前加上./?
答:因为在类Unix操作系统中,运行程序必须指定程序所在的目录,除非程序的目录已经列在了PATH环境变量中。
C语言不支持现成的字符串。
C语言比其他大多数语言的抽象层次更低,因此它不提供字符串,而是用了相似的东西来代替:以字符为元素的数组。如果你用过其他语言,一定已经见过数组了,数组就是一张有名有姓的事物清单,所以card_name
只是一个变量名,用来引用你在命令提示符输入的那张字符列表的。把card_name
定义为大小为2个字符的数组,就可以用card_name[0]
和card_name[1]
分别引用第一和第二个字符。为了理解字符串的工作原理,让我们深入计算机的存储器,看看C语言是如何处理文本的……
字符串聚焦
字符串只是字符数组,当C语言看到一个这样的字符串时:
- s = "Shatner"
会把它当做一个数组读取,而这个数组是由一个个独立的字符组成的:
字符串中的每个字符是数组中的一个元素,这就是为什么可以通过索引来引用字符串中的某个字符,比如
s[0]
、s[1]
。
别在字符串的尽头掉下去
当C语言想要读取字符串中的内容时,会发生什么呢?比如说它想打印字符串吧。在如今的很多语言中,计算机会时刻记录数组的大小,但C语言比大多数语言更低层,它无法确切地知道数组有多长,如果C语言想在屏幕上显示字符串,它就需要知道什么时候会到达字符数组的尾部,为此C语言加入了哨兵字符。
哨兵字符是一个出现在字符串末尾的附加字符,它的值为
\0
。每当计算机需要读取字符串的内容时,它会逐一扫描字符数组中的所有元素,直到碰到\0
,也就是说当计算机看到下面这个字符串时:
- s = "Shatner"
存储器中实际保存的是:
这就是为什么我们要在代码中像这样定义
card_name
变量:
- 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语言采取不同的方式在存储器中保存字符串字面值。总线错误意味着程序无法更新那一块存储器空间。
虎口拔牙
“等号”不一定表示等于。
在C语言中,“等号”(=)用来赋值(assignment),而“双等号”用来检查两个值是否相等。
如果想要增加或减小变量的值,可以用+=和-=这两个赋值运算符,它们让代码看起来更简短。
最后,如果想要对变量的值加 1 或减 1 ,可以用 + + 和--。
![]()