1月18日 C Primer Plus学习

7.2.5 多层嵌套的if语句

if...else if...else序列是嵌套if的一种形式,从一系列选项中选择一个执行。有时,选择一个特定选项后又引出其他选择,这种情况可以使用另一种嵌套 if。

从技术角度看,if else语句作为一条单独的语句,不必使用花括号。外层if也是一条单独的语句,也不必使用花括号。但是,当语句太长时,使用花括号能提高代码的可读性,而且还可防止今后在if循环中添加其他语句时忘记加花括号。

小结:用if语句进行选择

关键字:ifelse

一般注解:

下面各形式中,statement可以是一条简单语句或复合语句。表达式为真

说明其值是非零值。形式1

if (expression)

statement

如果expression为真,则执行statement部分。

形式2

if (expression) statement1 else statement2

如果expression为真,执行statement1部分;否则,执行statement2部分。

形式3

if (expression1) statement1 else if (expression2) statement2 else statement3

如果expression1为真,执行statement1部分;如果expression2为真,执行

statement2部分;否则,执行statement3部分。

7.3 逻辑运算符

逻辑运算符两侧的条件必须都为真,整个表达式才为真。逻辑运算符的优先级比关系运算符低,所以不必在子表达式两侧加圆括号。

7.3.1 备选拼写:iso646.h头文件

C 是在美国用标准美式键盘开发的语言。但是在世界各地,并非所有的键盘都有和美式键盘一样的符号。因此,C99标准新增了可代替逻辑运算符的拼写,它们被定义在ios646.h头文件中。如果在程序中包含该头文件,便可用and代替&&、or代替||、not代替!。

“新增C99和C11的标准ANSI C库”列出了一些运算符的备选拼写,有些我们还没见过。

7.3.2 优先级

!运算符的优先级很高,比乘法运算符还高,与递增运算符的优先级相同,只比圆括号的优先级低。&&运算符的优先级比||运算符高,但是两者的优先级都比关系运算符低,比赋值运算符高。

7.3.3 求值顺序

除了两个运算符共享一个运算对象的情况外,C 通常不保证先对复杂表达式中哪部分求值。

C 把先计算哪部分的决定权留给编译器的设计者,以便针对特定系统优化设计。但是,对于逻辑运算符是个例外,C保证逻辑表达式的求值顺序是从左往右。&&和||运算符都是序列点,所以程序在从一个运算对象执行到下一个运算对象之前,所有的副作用都会生效。而且,C 保证一旦发现某个元素让整个表达式无效,便立即停止求值。

7.3.4 范围

&&运算符可用于测试范围。例如,要测试score是否在90~100的范围内,可以这样写:

if (range >= 90 && range <= 100) 
千万不要模仿数学上的写法:
if (90 <= range <= 100)  // 千万不要这样写!
    //话是这么说,可我觉得应该没人会这么写吧?

这样写的问题是代码有语义错误,而不是语法错误,所以编译器不会捕获这样的问题(虽然可能会给出警告)。

由于<=运算符的求值顺序是从左往右,所以编译器把测试表达式解释为:

(90 <= range) <= 100

子表达式90 <= range 的值要么是1(为真),要么是0(为假)。

这两个值都小于100,所以不管range的值是多少,整个表达式都恒为真。因此,在范围测试中要使用&&。

7.4 一个统计单词的程序

现在,我们可以编写一个统计单词数量的程序(即,该程序读取并报告单词的数量)。该程序还可以计算字符数和行数。先来看看编写这样的程序要涉及那些内容。

首先,该程序要逐个字符读取输入,知道何时停止读取。然后,该程序能识别并计算这些内容:字符、行数和单词。据此我们编写的伪代码如下:

读取一个字符

当有更多输入时

​ 递增字符计数

​ 如果读完一行,递增行数计数

​ 如果读完一个单词,递增单词计数

​ 读取下一个字符

前面有一个输入循环的模型:

while ((ch = getchar()) != STOP)

{

...

}

这里,STOP表示能标识输入末尾的某个值。以前我们用过换行符和句点标记输入的末尾,但是对于一个通用的统计单词程序,它们都不合适。我们暂时选用一个文本中不常用的字符(如,|)作为输入的末尾标记。第8章中会介绍更好的方法,以便程序既能处理文本文件,又能处理键盘输入。现在,我们考虑循环体。因为该程序使用getchar()进行输入,所以每次迭代都要通过递增计数器来计数。为了统计行数,程序要能检查换行字符。

如果输入的字符是一个换行符,该程序应该递增行数计数器。这里要注意STOP 字符位于一行的中间的情况。是否递增行数计数?我们可以作为特殊行计数,即没有换行符的一行字符。可以通过记录之前读取的字符识别这种情况,即如果读取时发现 STOP 字符的上一个字符不是换行符,那么这行就是特殊行。

最棘手的部分是识别单词。首先,必须定义什么是该程序识别的单词。我们用一个相对简单的方法,把一个单词定义为一个不含空白(即,没有空格、制表符或换行符)的字符序列。因此,“glymxck”和“r2d2”都算是一个单词。程序读取的第 1 个非空白字符即是一个单词的开始,当读到空白字符时结束。判断非空白字符最直接的测试表达式是:

c != ' ' && c != '\n' && c != '\t' /* 如果c不是空白字符,该表达式为真*/ 检测空白字符最直接的测试表达式是:

c == ' ' || c == '\n' || c == '\t' /如果c是空白字符,该表达式为真/

然而,使用ctype.h头文件中的函数isspace()更简单,如果该函数的参数是空白字符,则返回真。所以,如果c是空白字符,isspace(c)为真;如果c不是空白字符,!isspace(c)为真。

要查找一个单词里是否有某个字符,可以在程序读入单词的首字符时把一个标记(名为 inword)设置为1。也可以在此时递增单词计数。然后,只要inword为1(或true),后续的非空白字符都不记为单词的开始。下一个空

白字符,必须重置标记为0(或false),然后程序就准备好读取下一个单词。我们把以上分析写成伪代码:

如果c不是空白字符,且inword为假设置inword为真,并给单词计数如果c是空白字符,且inword为真设置inword为假

这种方法在读到每个单词的开头时把inword设置为1(真),在读到每个单词的末尾时把inword设置为0(假)。只有在标记从0设置为1时,递增单词计数。如果能使用_Bool类型,可以在程序中包含stdbool.h头文件,把 inword的类型设置为bool,其值用true和false表示。如果编译器不支持这种用法,就把inword的类型设置为int,其值用1和0表示。

如果使用布尔类型的变量,通常习惯把变量自身作为测试条件。如下所

示:

用if (inword)代替if (inword == true) 用if (!inword)代替if (inword == false)

可以这样做的原因是,如果 inword为true,则表达式 inword == true为 true;如果 inword为false,则表达式inword == true为false。所以,还不如直接用inword作为测试条件。类似地,!inword的值与表达式inword == false的值相同(非真即false,非假即true)。

程序清单7.7把上述思路(识别行、识别不完整的行和识别单词)翻译

了成C代码。

程序清单**7.7 wordcnt.c**程序
// wordcnt.c -- 统计字符数、单词数、行数
#include <stdio.h>
#include <ctype.h>     // 为isspace()函数提供原型
#include <stdbool.h>    // 为bool、true、false提供定义
#define STOP '|' 
int main(void)
{
	char c;        // 读入字符 char prev;       // 读入的前一个字符
	long n_chars = 0L;// 字符数
    int n_lines = 0;    // 行数
    int n_words = 0;    // 单词数
    int p_lines = 0;    // 不完整的行数
    bool inword = false;  // 如果c在单词中,inword 等于 true
    
	printf("Enter text to be analyzed (| to terminate):\n");
	prev = '\n';      // 用于识别完整的行
	while ((c = getchar()) != STOP)
	{
		n_chars++;     // 统计字符
		if (c == '\n')
			n_lines++;   // 统计行
		if (!isspace(c) && !inword)
		{
			inword = true;// 开始一个新的单词 
            n_words++;   // 统计单词
		}
        if (isspace(c) && inword)
			inword = false;  // 打到单词的末尾 
        prev = c;     // 保存字符的值
	}
	if (prev != '\n') 
        p_lines = 1;
    printf("characters = %ld, words = %d, lines = %d, ", n_chars, n_words, n_lines);
    printf("partial lines = %d\n", p_lines);
    return 0;
}

判断用户输入的年份是否是闰年

判断用户输入的年份是否是闰年
#include<stdio.h>
#include<stdbool.h>
int main(void)
{
    printf("请输入要判断是否为闰年的年份:(仅需输入数字)\n");
	int year;
    if (scanf("%d",&year) == 1 && year > 0)
    {
        if (year / 4 == 0)
        {
            printf("%d年是闰年",year);
        }
        else
        {
            printf("%d年不是闰年",year);
        }
    }
    else
    {
        printf("请输入正确的年份!");
    }
    return 0;
}
posted @ 2022-02-07 10:48  shucharjer  阅读(67)  评论(0)    收藏  举报