第1章 导言

“苔花如米小,也学牡丹开.” ——袁枚«苔»

1.1 入门

​ 学习一门新程序设计语言的唯一途径就是使用它编写程序.

请打印出下列内容

hello, world

​ 要实现这个目的,我们首先必须编写程序文本,然后成功地进行编译,并加载,运行,最后输出到某个地方.

​ 在C语言中,我们可以用下列程序(hello.c)打印出”hello, world”:

#include <stdio.h>				// 包含标准库的信息

int main(void)					// 定义名为main的函数,它不接受参数值
{						// main函数的语句都被括在花括号中
    printf("hello, world\n");	        // main函数调用库函数printf以显示字符序列;\n代表换行符
    return 0;					// 返回值为int类型,通常返回0表示成功返回
}

​ 使用下列命令进行编译:

cc hello.c

​ 如果安装了make,可以使用:

make hello

​ 下面对程序本身做些说明:

一个C语言程序,无论其大小如何,都是由函数和变量组成的.

函数中包含一些语句,以指定所要执行的计算操作;

变量则用于存储计算过程中使用的值.

用双引号括起来的字符序列称为字符串字符串常量,如”hello, world\n”就是一个字符串.

\n只代表一个字符.类似于\n的转义字符序列为表示无法输入的字符或不可见字符提供了一种通用的可扩充的机制.除此之外,C语言提供的转义字符序列还包括:\t表示制表符;\b表示回退符;\“表示双引号;\\表示反斜杠符本身.

1.2 变量与算术表达式

​ 我们来看下一个程序,使用公式 °C = (5/9) (°F-32) 打印下列华氏温度与摄氏温度对照表:

0 -17 20 -6 40 4 60 15 80 26 100 37 120 48 … … 280 137 300 148

​ 此程序中仍只包括一个名为main的函数定义.这个程序中引入了一些新的概念,包括注释,声明,变量,算术表达式,循环以及格式化输出.该程序如下所示:

#include <stdio.h>
//	fahr2celsius.c

/*	当fahr= 0, 20, ..., 300时,分别
	打印华氏温度与摄氏温度对照表	*/
int main(void)
{
    int fahr, celsius;
    int lower, upper, step;
    
    lower = 0;		/*	温度表的下限	*/
    upper = 300;	/*	温度表的上限	*/
    step = 20;		/*	步长	*/
    
    fahr = lower;
    while(fahr <= upper){
        celsius = 5 * (fahr-32) / 9;
        printf("%d\t%d\n", fahr, celsius);
        fahr += step;
    }
    
    return 0;
}

注释: 单行//或多行/* */

在C语言中,所有变量必须先声明后使用,声明通常放在函数起始处,在任何可执行语句之前.声明用于说明变量的属性,它由一个类型名和一个变量表组成.例如:int fahr, celsius;

数据类型:int整型, float单精度浮点型, char字符(一个字节), short短整型, long长整型, double双精度浮点型, longlong.数据类型的大小取决于具体的机器.另外,还存在这些基本数据类型的数组,结构,联合,指向这些类型的指针以及返回这些类型值的函数.

语句必须以分号结尾;

整数除法操作将执行舍位,结果中的任何小数部分都会被舍弃.

​ 存在两个问题,一是不是右对齐,二是计算精度.修改版本如下;

#include <stdio.h>
//	fahr2celsius.c

/*	当fahr=0. 20, ..., 300时,打印华氏温度与摄氏温度对照表;
	浮点数版本	*/

int main(void)
{
    float fahr, celsius;
    int lower, upper, step;
    
    lower = 0;
    upper = 300;
    step = 20;
    
    fahr = lower;
    while(fahr <= upper){
        celsius = (5.0/9.0) * (fahr-32.0);
        printf("%3.0f %6.1f\n", fahr, celsius);
        fahr += step;
    }
    
    return 0;
}

​ 使用预处理指令#define:

#include <stdio.h>
//	fahr2celsius.c

/*	当fahr=0, 20, ..., 300时,打印华氏温度与摄氏温度对照表;
	浮点数版本	*/

//	预处理指令语句后面不需要加分号,如果是表达式,需要使用圆括号括起来().
#define LOWER 0
#define UPPER 300
#define STEP 20

int main(void)
{
    float fahr, celsius;
    
    fahr = LOWER;
    while(fahr <= UPPER){
        celsius = (5.0/9.0) * (fahr-32.0);
        printf("%3.0f %6.1f\n", fahr, celsius);
        fahr += STEP;
    }
    
    return 0;
}

1.3 for语句

​ 温度转换的另一种写法:

#include <stdio.h>
//	fahr2celsius.c

/*	打印华氏温度-摄氏温度对照表	*/
int main(void)
{
    printf("Fahr Celsius\n");
    float fahr;
    for(fahr = 0; fahr <= 300; fahr += 20)
        printf("%3.0f  %6.1f\n", fahr, (5.0/9.0)*(fahr-32.0));
    return 0;
}

1.4 符号常量

​ #define 名字 替换文本

#include <stdio.h>
//	fahr2celsius.c

/*	打印华氏温度-摄氏温度对照表	*/

#define LOWER 0
#define UPPER 300
#define STEP 20

int main(void)
{
    printf("Fahr Celsius\n");
    float fahr;
    for(fahr = LOWER; fahr <= UPPER; fahr += STEP)
        printf("%3.0f  %6.1f\n", fahr, (5.0/9.0)*(fahr-32.0));
    return 0;
}

1.5 字符输入/输出

​ 标准库提供了一次读/写一个字符的函数,最简单的是getchar和putchar两个函数.

c = getchar() putchar(c)

1.5.1 文件复制

​ 基本思想:

读一个字符 while(该字符不是文件结束指示符) ​ 输出刚读入的字符 ​ 都下一个字符

​ 将上述基本思想转换为C语言程序为:

#include <stdio.h>

/*	将输入复制到输出: 版本1	*/
int main(void)
{
    int c;
    
    c = getchar();
    while(c != EOF){
        putchar(c);
        c = getchar();
    }
}

上述字符复制程序可以改写的更精炼,(因为运算符顺序,所以,需要将c=gerchar()整体加圆括号):

#include <stdio.h>

/*	将输入复制到输出: 版本2	*/
int main(void)
{
    int c;
    
    while((c = getchar()) != EOF)
        putchar(c);
}

1.5.2 字符计数

​ 下列程序用于对字符进行计数,while版本:

#include <stdio.h>

/*	统计输入的字符数: 版本1	*/
int main(void)
{
    long nc = 0;
    while(getchar() != EOF)
        ++nc;
    printf("%ld\n", nc);
    return 0;
}

​ 下列程序用于对字符进行计数,for版本:

#include <stdio.h>

/*	统计输入的字符数: 版本2	*/
int main(void)
{
    double nc:
    for(nc = 0; getchar() != EOF; ++nc)
        ;	//	单独的分号表示空语句
    printf("%.0f\n", nc);
    return 0;
}

1.5.3 行计数

​ 统计行数等价于统计换行符的个数:

#include <stdio.h>

/*	统计输入的行数	*/
int main(void)
{
    int c, nl;
    
    nl = 0;
    while((c =  getchar()) != EOF)
        if(c == '\n')
            ++nl;
    printf("%d\n", nl);
    return 0;
}

1.5.4 单词计数

​ 下列程序用于统计行数,单词数与字符数,这里对单词的定义比较宽松,它是任何其中不包含空格,制表符或换行符的字符序列:

#include <stdio.h>

#define IN 1	//	在单词内
#define OUT 0	//	在单词外

/*	统计输入的行数,单词数与字符数	*/
int main(void)
{
    int c, nl, nw, nc, state;
    
    state = OUT;
    nl = nw = nc = 0;
    
    while((c = getchar()) != EOF){
        ++nc;
        if(c == '\n')
            ++nl;
        if(c == ' ' || c == '\n' || c == '\t')
            state = OUT;
        else if(state == OUT){
            state = IN;
            ++nw;
        }
    }
    printf("行数:%d 单词数:%d 字符数:%d\n", nl, nw, nc);
    return 0;
}