C语言-第1章-概述


本章介绍了计算机语言发展历史上重要的语言类型,C语言的历史和优缺点,以及具体的、入门的“Hello,World程序”和编译运行程序的过程。本章重难点是“Hello,World程序”和“编译运行过程”这两节。理解“计算机语言”这一节的内容对理解编译运行过程有一定帮助。

1.1 计算机语言

计算机语言有很多种,各种语言想办法在一定的场景下方便程序员编程。最终,所有的编程语言要转换为计算机可以执行的指令。

  • 机器语言
    机器语言特指计算机本身的语言(native language),不同的计算机的本身的语言是不同的,它们是一组内建的指令。这组指令是二进制形式的,比如,为了加两个数,需要这样写出指令:
    1101101010011010
    显然,这样编写程序是非常繁琐的。而且非常难以阅读和修改。

  • 汇编语言
    汇编语言用来代替机器语言。汇编语言用称为助记符的描述性单词来代表机器指令。比如,助记符add表示加两个数,sub表示减两个数。2和3相加并把结果放到result里的汇编指令为:
    add 2, 3, result
    计算机不能直接执行汇编指令,一种称为汇编器(assembler)的程序将汇编语言程序翻译成机器语言程序。
    Assembly Language

    显然,相比机器语言,汇编语言是一大进步, 但是写汇编程序仍然比较麻烦,汇编语言的指令一般与机器指令对应,写汇编程序要求了解CPU如何工作。汇编语言被称为低级语言,因为本质上来说汇编语言与机器语言相近,是机器相关的。(不同的计算机上指令是不同的)

  • 高级语言
    上世纪50年代,新一代的编程语言出现了,它们被称为高级语言。它们是平台无关的,即用高级语言写的同一段程序可以运行在不同的机器上。高级语言与英语很像,容易读写。高级语言的指令称为语句。比如,下面给出一条语句,用来计算圆面积

    area = 5 * 5 * 3.1415;

    高级语言有很多,比如,C、C++、Java、Python等等,语法上它们会有一些不同,因为它们都是为不同环境下开发而发明出来的。
    用高级语言写出来的程序称为源程序/源代码。源程序需要通过解释程序/编译程序转换为机器语言才能被机器执行。
    解释程序从源程序中取出一条语句,将它翻译为机器码或者虚拟机码,然后立即执行它。注意,源程序的一条语句可能被翻译成多条机器指令。如很多脚本语言,如Python。
    解释执行
    编译程序将整个源代码文件翻译成机器指令文件,然后机器指令文件再
    执行。如C语言。

编译执行
很多语言是解释执行还是编译执行界限不是那么清楚,不需要过于深究。了解解释执行和编译执行这两个概念即可。

1.2 C语言的历史

C语言是贝尔实验室的Ken Thompson、Dennis Ritchie等人开发的UNIX操作系统的“副产品”。Thompson独自编写出了UNIX操作系统的最初版本,这套系统运行在DEC PDP-7计算机上。这款早期的小型计算机仅有16KB内存(毕竟那是在1969年)。

与同时代的其它操作系统一样,UNIX系统最初也是用汇编语言编写的。用汇编语言编写的程序往往难以调试和改进,UNIX系统也不例外。Thompson意识到需要用一种更加高级的编程语言来完成UNIX系统未来的开发,于是他设计了一种小型的B语言。(基于BCPL语言的基础上)后来,Ritchie也加入到UNIX项目中,并且开始着手用B语言编写程序。1970年,贝尔实验室为UNIX项目争取到一台PDP-11计算机。当B语言经过改进并能够在PDP-11计算机上成功运行后,Thompson用B语言重新编写了部分UNIX代码。到了1971年,B语言已经明显不适合PDP-11计算机了,于是Ritchie着手开发B语言的升级版。最初,他将新开发的语言命名为NB语言(意为“New B”),但是后来新语言越来越偏离B语言,于是他将其改名为C语言。到了1973年,C语言已经足够稳定,可以用来重新编写UNIX系统了。改用C语言编写程序有一个非常重要的好处:可移植性。只要为贝尔实验室的其它计算机编写C语言编译器,他们的团队就能让UNIX系统也运行在那些机器上。

C语言在20世纪70年代持续发展。这一时期出现了第一本有关C语言的书。Brian Kernighan和Dennis Ritchie合作编写的The C Programming Language一书于1978年出版,并迅速成为C程序员必读的“圣经”。由于当时没有C语言的正式标准,所以这本书就成了事实上的标准,编程爱好者把它称为“K&R”或者“白皮书”。

在20世纪70年代,C程序员相对较少,而且他们中的大多数人都是UNIX系统的用户。然而,到了20世纪80年代,C语言已不再局限于UNIX领域。运行在不同操作系统下的多种类型的计算机都开始使用C语言编译器。特别是迅速壮大的IBM PC平台也开始使用C语言。

随着C语言的迅速普及,一系列问题也接踵而至。编写新的C语言编译器的程序员都用"K&R"作为参考,但是遗憾的是,"K&R"对一些语言特性的描述非常模糊,以至于不同的编译器常常hui对这些特性做出不同的处理。而且,"K&R"也没有对属于C语言的特性和属于UNIX系统的特性进行明确的区分。更糟糕的是,"K&R"出版以后C语言仍在不断变化,增加了新特性并去除了一些旧的特性。很快,C语言需要一个全面、准确的最新描述开始成为共识。如果没有这样一种标准,就会出现各种“方言”,这势必威胁到C语言的主要优势-程序的可移植性。

1983年,在美国国家标准协会(ANSI)的推动下,美国开始制定本国的C语言标准。经过多次修订,C语言标准于1988年完成并在1989年12月正式通过,成为ANSI标准X.159-1989。1990年,国际标准化组织(ISO)通过了此项标准,将其作为ISO/IEC9899:1990国际标准。我们把这一C语言版本称为C89或C90,以区别于原始的C语言版本(经典C)。

1995年,C语言发生了一些改变。1999年通过的ISO/IEC9899:1999新标准中包含了一些更重要的改变,这一标准所描述的语言通常称为C99。
尽管从经典C、C89到C99,C语言存在这样几个重大的版本,但是目前国内大多数教材还是基于C89的,因此我们也以C89为基础,但是C99在某些地方的修改确实方便了C语言的使用,因此我们也会提到C99的改变。

1.3 C语言的优缺点

1.3.1 C语言的优点

C语言在产业和高校中使用广泛,在语言排行榜中似乎从未跌出前三,其众多优点有助于解释为什么这种语言如此流行。

  • 高效。
  • 可移植性。
  • 功能强大。
  • 灵活。
  • 标准库。
  • 与UNIX系统的集成。

1.3.2 C语言的缺点

C语言毕竟是一门有几十年的历史了,在它的基础上诞生了C++、Java、Python等一系列的语言,这些语言各自有自己的特色,换句话说,它们在某些地方改进了C语言。C语言的缺点和它的许多优点是同源的,均来自C语言与机器的紧密结合。下面是众所周知的几个问题。

  • C程序更容易隐藏错误。
  • C程序可能会难以理解。
  • C程序可能会难以修改。

1.3.3 C语言的优缺点个人感受

  • 语法简单明了,易于学习。(是很多语言的基石,学好C语言,有利于学习其它语言和理解编程。)

  • 语言不够抽象,标准库不够强大,不易于编写应用程序。

1.4 Hello,World程序

作为第一个C语言的程序,下面的程序的功能是向控制台窗口输出一段文字,文字的内容是“Hello, World!”

#include <stdio.h>

int main(void)
{
   // 输出文字Hello, World!
   printf("Hello, World!\n");
   return 0;
}

helloworld
下面来分析下这个程序,从大的角度来看,整个程序可以分成这几块:

预处理指令

int main(void)  // 定义main函数
{
   语句
   return 0;
}
  • 语句。语句是程序执行时运行的代码,一个程序由哪些语句组成是与程序要完成的功能密切相关的。printf("Hello, World!\n");语句实际上调用标准库中的函数printf来输出文字Hello, World!和一个换行符’\n’。输出一个换行符意味着接下来的输出会另起一行。
  • 函数定义。程序整体是在定义函数main:
    int main(void)
    {
     ...
     return 0;
    }
    
    函数是由多条语句组成,完成一个逻辑功能的“小程序”,通俗的说就是一段代码。定义函数就是在“编写代码”(写出若干条语句告知计算机如何完成一个功能),而定义好的函数就可以被别的函数来使用(调用)。比如printf就是一个已经写好(定义好)的函数,其功能是输出文字,在上面的程序中,被main函数使用(调用)。

mainprocess

intreturn 0;有关联,都是组成函数的语句。作用是在程序运行结束后向操作系统返回一个整数值0。

printf和main都是函数,但是区别在printf函数是定义好的函数,其名称是固定的printf,而main函数是我们自己定义的,可以叫其它的名字。但是,C语言规定,一个程序中必须有而且只能有一个main函数,程序以main函数中的代码的运行而运行,以main函数中代码运行的结束为结束。换句话说,main函数是整个程序的入口和出口函数。

  • 预处理指令。在编译程序之前,预处理器首先对源文件进行编辑。#include <stdio.h>的作用是,在编译之前把文件<stdio.h>中的信息“包含”到程序中 。为什么要包含stdio.h文件呢?因为printf函数的使用信息在这个文件中。而C语言要求使用函数时,需要将函数的使用信息包含到源文件中。

1.5 程序注释

为了增加程序的可读性(一段时候后程序员本人也可能忘记代码的含义),可以在源文件中添加文本注释。注释作为源文件的一部分文字起到解释代码、添加作者名、编写日期等等作用。但是不会作为代码被编译/解释。有一种说法是程序是写给人看的,而不光是给计算机运行的。为程序添加必要的注释是非常好的编程习惯。
具体来看,C语言的注释有两种:

  • 多行注释
    多行注释是C89标准中就引入的注释方式,用/*和*/将含有连续多行的文字包含起来,这些文字就不会被看成代码。比如,

    /*
      文件名:area.c
      功能:计算圆的面积
      作者:张三
    */
    #include <stdio.h>
    ...
    

    注意,多行注释不支持嵌套。

  • 单行注释
    //是C99标准引入的注释形式,用来为单行做注释。

    #include <stdio.h>
    
    int main(void)
    {
       printf("Hello, World!\n");  // 输出文字Hello, World!
       return 0;
    }
    

显然,多行注释也可以只用来注释一行文字,单行注释连续使用也可以用来注释多行文字。

1.6 其它若干程序的例子

下面的程序输出多行文字

#include <stdio.h>
int main(void)
{
   printf("Hello, World!\n");
   printf("Programming is fun!\n");
   printf("Practice!\n");
   return 0;
}

helloworldmultiple

下面的程序显示9的平方根

#include <stdio.h>
#include <math.h>
int main(void)
{
   // sqrt是标准库中计算平方根的函数,其使用信息在头文件math.h中
   printf("9的平方根是%f\n", sqrt(9));
   return 0;
}

sqrtoutput
下面的程序自定义了一个函数print_hello

#include <stdio.h>

void print_hello(void)
{
	printf("Hello, World!\n");
}

int main(void)
{
   
   print_hello();
   printf("Programming is fun!\n");
   printf("Practice!\n");
   print_hello();
   return 0;
}

在这里插入图片描述

1.7 编译运行过程

cprogramingprocess
相应的,C语言的错误有:

1.生成期错误:

生成期错误指将源码生成为可执行代码过程中的错误,主要是指编译错误,也包括链接错误。

1.1 编译错误

编译器发现的语法错误,比如一句话结束没有写分号,小括号或者大括号没有匹配等等。

#include <stdio.h>

int main()
{
	printf("Hello, World!\n")  // 缺少分号
	return 0;
}

1.2 链接错误

将源代码的目标文件(二进制文件)和相关的系统库函数的目标文件(二进制文件),链接为可执行程序过程中出现的错误,比如程序中没有定义main函数,或者使用了不存在的函数。

#include <stdio.h>

int mian()  // 没有定义main函数
{
	printf("Hello, World!\n");
	return 0;
}

2.执行(运行)期错误

将源码生成为可执行代码后,程序可以运行起来了,但是仍然可能有错误,这种错误称为运行期错误,主要是指逻辑错误,也包括运行时错误(runtime error)。

2.1 逻辑错误

这个错误比较好理解,就是程序可以正常运行,但是由于代码逻辑错误,导致运行结果不符合预期。比如计算两个数和的程序,加号写成了减号。

#include <stdio.h>

int main()
{
	printf("2 + 3 = %d\n", 2 - 3);    // 加好错写成了减号
	return 0;
}

2.2 运行时错误

运行时错误(runtime error)是一类在运行时导致程序突然中止的错误的总称。比如除法除数为0,或者应该输入整数,但是输入了字符串。

#include <stdio.h>

int main()
{
	int x, y, z;
    x = 10;
	y = 0;
	z = x / y;  // 除数为0,运行时出错
	printf("%d\n", z); 
	return 0;
}

1.8 使用VS2010

在 VS2010 下开发程序首先要创建项目,不同类型的程序对应不同类型的项目,初学者应该从控制台程序学起。

1) 创建项目

打开 VS2010,在上方菜单栏中选择“文件 --> 新建 --> 项目”:
在这里插入图片描述
或者按下Ctrl+Shift+N组合键,都会弹出下面的对话框:
在这里插入图片描述
选择“Win32控制台应用程序”,填写好项目名称,选择好存储路径,点击“确定”按钮即可。

点击“确定”按钮后会弹出向导对话框:
在这里插入图片描述
点击“下一步”按钮,弹出新的对话框:
在这里插入图片描述
然后点击“完成”按钮就创建了一个新的项目。

2) 添加和编辑源文件

在这里插入图片描述
或者按下Ctrl+Shift+A组合键,都会弹出添加源文件的对话框。如下图所示:
在这里插入图片描述
注意,文件名后缀要主动以.c结束,标志该文件为C语言源代码文件,否则,默认生成.cpp文件,而.cpp文件是C++语言文件后缀名。

在这里插入图片描述
3) 编译源文件

打开 hello.c,将本节开头的代码输入到 hello.c 中,上图是输入完成以后的效果。

注意:虽然可以将整段代码复制到编辑器,但是我还是强烈建议你手动输入,我敢保证你第一次输入代码会有各种各样的错误,只有把这些错误都纠正了,你才会进步。本教程后续章节还会给出很多示例代码,这些代码一定要手动输入,不要复制后运行成功了就万事大吉。

编译(Compile)
在上方菜单栏中点击“生成”按钮,会弹出一个子菜单,再点击“编译”按钮,就完成了 hello.c 源文件的编译工作。
在这里插入图片描述
或者直接按下Ctrl+F7组合键,也能够完成编译工作,这样更加便捷。

如果代码没有错误,会在下方的“输出窗口”中看到编译成功的提示:
在这里插入图片描述
编译完成后,打开项目目录下的 Debug 文件夹,会看到一个名为hello.obj的文件,这就是经过编译产生的中间文件,这种中间文件的专业称呼是目标文件(Object File)。在 VS 和 VC 下,目标文件的后缀都是.obj。

链接(Link)
在菜单栏中选择“项目 --> 仅用于项目 --> 仅链接 cDemo”,就完成了 hello.obj 的链接工作,如下图所示:

在这里插入图片描述
如果代码没有错误,会在下方的“输出窗口”中看到链接成功的提示:
在这里插入图片描述

本项目中只有一个目标文件,链接的作用是将 hello.obj 和系统组件(专业讲是静态链接库)结合起来,形成可执行文件。如果有多个目标文件,这些目标文件之间还要相互结合。

再次打开解决方案目录下的 Debug 文件夹,会看到一个名为cDemo.exe的文件,这就是最终生成的可执行文件,就是我们想要的结果。

双击 cDemo.exe 运行,并没有输出“Hello, World!”几个字,而是会看到一个黑色窗口一闪而过。这是因为,程序输出“Hello, World!”后就运行结束了,窗口会自动关闭,时间非常短暂,所以看不到输出结果,只能看到一个“黑影”。

对上面的代码稍作修改,让程序输出“Hello, World!\n”后暂停下来:

#include <stdio.h>

int main(void)
{
   // 输出文字Hello, World!
   printf("Hello, World!\n");
   getchar();
   return 0;
}

在这里插入图片描述
按下键盘上的任意一个键,程序就会关闭。

VS 提供了一种更加快捷的方式,可以一键完成编译、链接、运行三个动作,点击菜单栏中的“运行”按钮,或者按下F5键就能做到这一点。

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值