【初中数学】4.1【出题思路】–考查

4.1

【题目思路】

这个问题的目的是检查几个常见算术运算符的优先级和结合性。

【回答】

在算术运算符中,乘法和除法具有相同的优先级,并且都比加法和减法具有更高的优先级。因此,上面计算的结果应该是105,这在编程环境中很容易验证。

4.2

【题目思路】

C++ 定义了多种运算符。这些操作符根据操作的含义分为不同的优先级。本题意在让用户区分表达式中各个运算符的优先级关系,然后用括号的方式表示先执行哪个运算符。

C++ 运算符优先级

【回答】

本题涉及的运算符中,成员选择运算符和函数调用运算符的优先级最高,其次是解引用运算符,最后是加法运算符。所以加括号后的等价公式为:

#include 
#include 
#include 
#include 
using namespace std;
int main() {
    vector vec;
    srand((unsigned) time(NULL));
    cout << "系统自动为向量生成一组元素......" << endl;
    for (int i = 0; i != 10; i++)
        vec.push_back(rand() % 100);
    cout << "生成的向量数据是:" << endl;
    for (auto c : vec)
        cout << c << " ";
    cout << endl;
    cout << "验证添加的括号是否正确:" << endl;
    cout << "*vec.begin() 的值是:" << *vec.begin() << endl;
    cout << "*(vec.begin()) 的值是:" << *(vec.begin()) << endl;
    cout << "*vec.begin() + 1 的值是:" << *vec.begin() + 1 << endl;
    cout << "(*(vec.begin())) + 1 的值是:" << (*(vec.begin())) + 1 << endl;
}

// 运行结果
系统自动为向量生成一组元素......
生成的向量数据是:
52 51 75 33 32 56 43 55 95 60 
验证添加的括号是否正确:
*vec.begin() 的值是:52
*(vec.begin()) 的值是:52
*vec.begin() + 1 的值是:53
(*(vec.begin())) + 1 的值是:53
Process finished with exit code 0

4.3

【题目思路】

这个问题的关键是检查求值顺序对表达式求值过程的影响。

【回答】

正如标题所说,C++只规定了极少数二元运算符(逻辑AND运算符、逻辑OR运算符、逗号运算符)的求值顺序,而其他大多数二元运算符的求值顺序并没有明确规定。这样做可以提高代码生成效率,但可能会引入潜在的错误。

关键是,缺陷的风险有多大?我们知道,对于没有指定执行顺序的算子,如果表达式指向并修改了同一个对象,就会抛出错误,产生未定义的行为;而如果操作数不相关,则既不会改变同一个对象的状态,也不执行IO任务,函数的调用顺序不受限制。

从作者的角度来看,这样的做法在一定程度上是可以接受的,前提是在编写程序时要注意以下两点:

当有疑问时,最好用括号来强制表达式的组合符合程序逻辑的要求;一旦操作数的值改变,该操作数就不能在表达式的其他地方使用。4.4

【题目思路】

这个问题的目的是检查算术运算符的优先级和结合性。乘法和除法具有相同的优先级,并且高于加法和减法。算术运算符都满足左结合律,即当优先级相同时,按照从左到右的顺序进行组合。

【回答】

加括号后的形式应该是 ((12 / 3) * 4) + (5 * 15) + ((24 % 4) / 2), find取值的过程是:先计算12/3得到4,再计算4*4得到16,再计算5*15得到75,计算24%4得到0,再计算0/2得到0,最后进行加法运算 16 + 75 + 0 得到 91。最终计算为 91。

4.5

【题目思路】

本题主要考查乘除法余数的计算规则。

【回答】

这个问题使用两个典型的算术规则。

首先是除法:整数除法的结果仍然是整数。如果商包含小数部分,则直接丢弃。特别是当除法的两个操作数的符号不同时,商为负数。C++11的新标准规定商总是四舍五入为0。

二是取余:如果余数的两个操作数的符号不同,则负号的位置不同,运算的结果也不同。m % (-n) 等于 m % n,并且 (-m) % n 等于 - ( m % n)。

因此,该问题的评估结果为:

(一)-86

(b)-18

(c) 0

(d)-2

4.6

【题目思路】

根据奇偶数的定义,能被2整除的数是偶数,不能被2整除的数是奇数。

【回答】

下面的表达式可以用来判断一个整数是奇数还是偶数,假设整数命名为num,那么表达式num % 2 == 0 当num为偶数时为真,当表达式为假时,num为奇数.

4.7

【题目思路】

当计算结果超出类型可以表示的范围时,就会发生溢出。

【回答】

溢出是一种常见的算术错误。因为计算机中用于存储某种类型的内存空间是有限的js中运算符的优先级,所以该类型的表示能力(范围)也是有限的。当计算的结果值超出这个范围时,会产生一个未定义的值。此错误称为溢出。.

假设编译器指定int占用32位,下面三个表达式都会产生溢出错误:

int i = 2147483647 + 1;
int j = -100000 * 300000;
int k = 2019 * 2019 * 2019 * 2019;

编程测试如下所示:

#include 
using std::cout;
using std::endl;
int main() {
    int i = 2147483647 + 1;
    int j = -100000 * 300000;
    int k = 2019 * 2019 * 2019 * 2019;
    cout << "i: " << i << endl;
    cout << "j: " << j << endl;
    cout << "k: " << k << endl;
}

// 运行结果
i: -2147483648
j: 64771072
k: -509465903
Process finished with exit code 0

显然这不是我们所期望的,这是溢出后的错误结果。

4.8

【题目思路】

逻辑 AND 和 OR 执行短路评估,而相等运算符则正常评估两个操作数。

【回答】

对于逻辑 AND 运算符,当且仅当两个操作数都为真时,结果才为真;对于逻辑 OR 运算符,只要两个操作数之一为真,结果就为真。

逻辑 AND 运算符和逻辑 OR 运算符都先计算左操作数,然后计算右操作数,并且当且仅当左操作数无法确定表达式值的结果时才计算右操作数。这种策略是短路评估。策略是:对于逻辑 AND 运算符,当且仅当左操作数为真时才计算右操作数;对于逻辑 OR 运算符,当且仅当左操作数为假时才计算。计算右手操作数。

值得注意的是,逻辑 AND 运算符和逻辑 OR 运算符是 C++ 中唯一指定计算顺序的运算符。相等运算符的两个操作数都需要求值,C++ 没有指定求值顺序。

4.9

【题目思路】

这个问题的目的是检查指针和取消引用运算符的使用,就像条件一样。

【回答】

cp是一个指向字符串的指针,所以上面表达式的条件部分的意思是先检查指针cp是否有效。如果 cp 是空指针或无效指针,则不满足条件。如果cp有效,即cp指向内存中的有效地址,继续解引用指针cp,检查cp指向的对象是否为空字符\0,如果cp指向的对象不为空字符,条件满足;否则不满足。

在这个例子中,很明显cp指向初始化状态的字符串的第一个字符,是有效的;同时cp指向的对象是字符H,不是空字符,所以if的条件部分为真。

4.10

【题目思路】

综合使用逻辑与运算符和相等运算符。注意,本题使用了逻辑与运算符的短路求值特性,左操作数是为了保证右操作数求值过程的正确性和安全性。

【回答】

最简洁的形式是:

while (cin >> num && num != 42)

该语句首先检查从输入流中读取的数据是否正常,然后判断当前输入数是否为42,如果遇到42,则不满足条件,退出循环。还有一种形式可以做同样的事情:

int num;
while (cin >> num) {
  if (num == 42)
    break;
  // 其他操作
}

4.11

【题目思路】

这个问题的目的是检查关系运算符的使用。

【回答】

要使用表达式测试 a、b、c、d 并确保 a 大于 b、b 大于 c、c 大于 d,您可以编写:

a > b && b > c && c > d

从不写:

a > b > c > d

因为关系运算符满足左结合性,并且运算结果是布尔值,把几个关系运算符写在一起难免会产生意想不到的结果。a > b > c > d的实际评估过程是首先判断a > b是否为真,如果为真则为1,如果不为真则为0;然后用这个布尔值(1或0)与c进行比较,得到的结果还是布尔值;最后将刚刚得到的布尔值与d进行比较。显然,这个过程违背了用户的初衷的写作。

4.12

【题目思路】

!=和<这两个关系运算符的优先级关系需要搞清楚,这是回答这个问题的关键。

C++ 运算符优先级

【回答】

C++规定=的优先级高于==和!=,所以上式的求值过程等价于i != (j < k),即先比较j和k的大小,再比较结果是一个布尔值( 1 或 0); 然后判断 i 的值是否等于它。

4.13

【题目思路】

图片[1]-【初中数学】4.1【出题思路】–考查-老王博客

本题涉及到两个知识点:第一,如果赋值运算符的左右操作数的类型不同,则将右操作数转换为左操作数的类型;其次,赋值运算符满足右结合性。

【回答】

从题意来看,式(a)的意思是先将3.5赋给整数i。此时发生自动类型转换,小数部分被丢弃,i的值为3;然后再次分配 i 的值。给出一个双精度浮点数 d,所以 d 的值也是 3。

公式(b)的意思是先把3.5赋给双精度浮点数d,所以d的值为3.5;然后将d的值赋给整数i,此时自动进行类型转换,舍弃小数部分,i的值为3。

编程测试如下所示:

#include 
using std::cout;
using std::endl;
int main() {
    int i;
    double d;
    d = i = 3.5;
    cout << "d = " << d << " " << "i = " << i << endl;
    i = d = 3.5;
    cout << "i = " << i << " " << "d = " << d << endl;
    return 0;
}

// 运行结果
d = 3 i = 3
i = 3 d = 3.5
Process finished with exit code 0

4.14

【题目思路】

本题涉及两个知识点:第一,赋值运算符的左操作数必须是左值,右操作数既可以是左值也可以是右值;二、赋值运算符和等式运算 当用作if语句的条件时,表示法有不同的含义。

【回答】

第一条语句会产生编译错误,因为赋值运算符的左操作数必须是左值,而字面常量 42 显然不是左值,不能用作左操作数。

第二个语句在语法上是正确的,但与程序的意图不符。程序的初衷是判断i的值是否为42,应该写成i == 42;而i = 42表示将42赋给i,然后判断i的值是否为真。由于所有非零整数在转换为布尔值时都对应于 true,因此此条件始终为 true。

4.15

【题目思路】

赋值运算符满足右结合律,从右到左分析赋值运算的意义。

【回答】

赋值语句是非法的,虽然连续赋值的形式本身并没有错,但是赋值中涉及的几个变量的类型是不同的。其中 dval 是双精度浮点数,ival 是整数,pi 是整数指针。

从右到左分析赋值操作的含义,pi = 0表示pi为空指针,然后ival = pi尝试将整数指针的值赋值为整数,是不符合的操作语法规范,无法编译。稍加调整,上述程序就可以合法化。

double dval;
int ival, *pi;
dval = ival = 0;
pi = 0;

4.16

【题目思路】

这个问题检查运算符优先级和赋值表达式的含义,就像条件一样。

C++ 运算符优先级

【回答】

(a)的初衷是将getPtr()得到的指针赋值给p,然后判断p是否为空指针,但上述表达式的实际执行结果却远非如此。因为赋值运算符的优先级低于不等运算符,所以真正的表达式求值过程是首先判断getPtr()的返回值是否为空指针。如果是空指针,则 getPtr() != 0 布尔值为0,然后将0赋给p,即p = 0;否则,如果是非空指针,getPtr() != 0 得到的布尔值为1,然后将1赋给p,即p = 1。最后,将 p 的值作为 if 语句的条件。为符合原意,应改为:

if ((p = getPtr()) != 0)

(b)的本意是判断i的值是否为1024,但上面的表达式其实是把1024赋给了i,然后用i作为if语句的条件。由于所有非零整数在转换为布尔值时都对应于 true,因此此条件始终为 true。

4.17

【题目思路】

C++ 实现了两种类型的递增(递减)运算符:pre-version 和 post-version。两者的工作机制不同。一般来说,预版本是更好的选择。

【回答】

递增和递减运算符有两种形式:pre-version 和 post-version。前版本首先将操作数加 1(或减去 1),然后将更改的对象作为评估结果。后版本也将操作数加 1(或减去 1) ),但计算结果是操作数更改前的值的副本。两个运算符都必须对左值操作数进行操作。preversion 将对象本身作为左值返回,postversion 将对象原始值的副本作为右值返回.

我们的建议是除非绝对必要,否则不要使用增量(减量)运算符的后缀版本。增量运算符的前一个版本通过将值增加 1 并直接返回更改的操作数来避免不必要的工作。相反,后期版本需要存储原始值才能返回此未修改的内容。如果我们不需要修改之前的值,那么后期版本的操作就是浪费。

对于整数和指针类型,编译器可能会在一定程度上优化这个额外的工作,但是对于相对复杂的迭代器类型,这个额外的工作是昂贵的。建议养成使用pre-version版本的习惯,这样不仅不用担心性能问题,更重要的是写出来的代码会更符合程序员的初衷。

4.18

【解决问题的方法】

前置自增运算符将操作数加 1,然后将更改的对象本身作为结果进行求值;后自增运算符也将操作数增加 1,但计算结果为操作数更改之前值的副本。

简而言之,如果表达式中出现自增运算符,其计算规则是:++在前,先加1,再参与运算;++在后面,先参与运算,再加1。

【回答】

根据以上分析,本题不应该将while循环的后自增运算符改为前自增运算符。这样做会产生两个错误结果:一个是向量对象的第一个元素无法输出;另一种是当所有元素都不是负数时,移动到最后一个元素的位置,程序尝试迭代向前,取消引用一个根本不存在的元素。

4.19

【题目思路】

这个问题的目的是检查增量运算符和关系运算符、逻辑运算符和取消引用运算符之间的优先关系。读者还需要了解后自增运算符的计算规则。

C++ 运算符优先级

【回答】

(a)的意思是先判断指针ptr是否为空,如果不是,继续判断指针ptr指向的整数是否为非零数。如果非零,则此表达式的最终评估为真;否则为假。最后,将指针 ptr 向后移动一位。该表达式在语法上是有效的,但最后一个指针移位操作不一定有意义。如果 ptr 引用整数数组中的元素,则 ptr 可以按预期移动到下一个元素。如果 ptr 仅引用一个单独的整数变量,则移动指针操作将产生未定义的结果。

(b)的意思是先检查ival的值是否非零,如果非零,继续检查(ival + 1)的值是否非零。只有当两个值都不为零,表达式的求值结果为真;否则为假。在4.1.3节我们了解到,如果二元运算符的两个操作数涉及同一个对象,改变对象的值,那么这是一个程序,这是一种不好的写法,应该重写。因此,按照程序的初衷,这个公式应该重写为ival &&(ival + 1) 。

(c)的意思是比较vec[ival]和vec[ival + 1]的大小,如果前者更小,则评估结果为真,否则为假。和公式(b)一样,这个公式也说明二元运算符的两个操作数涉及同一个对象并改变对象的值,应该改写为vec[ival] empty();相当于 (*iter) .empty(); . 解引用迭代器,得到迭代器当前指向的元素,结果是一个字符串。很明显,可以判断字符串是否为空,这里空函数是有效的。

(e) 是非法的,前置自增运算符与解引用运算符具有相同的优先级,但表达式的结合性是从右到左的(右结合性)。此公式首先取消引用 iter 以获取迭代器当前指向的元素。结果是一个字符串。显然,字符串没有预增操作。

(f) 是合法的,后自增运算符的优先级与成员访问运算符的优先级相同,但表达式的结合性是从左到右的(左结合性)。iter++->empty(); 等价于 (*iter++).empty(); . 意思是解引用迭代器当前位置的对象内容,得到一个字符串,判断该字符串是否为空,然后将迭代器向后移动一位。

4.21

【题目思路】

条件运算符允许我们将简单的 if-else 结构嵌入到表达式中。条件表达式可以用作赋值运算符的右手操作数。

【回答】

满足问题含义的过程如下:

#include 
#include 
#include 
#include 
using namespace std;
int main() {
    vector vInt;
    const int sz = 10;                          // 使用 sz 作为数组的维度
    srand((unsigned) time(NULL));               // 生成随机数种子
    // 使用普通 for 循环为数组赋初值
    cout << "数组的初始值是:" << endl;
    for (int i = 0; i != sz; ++i) {
        vInt.push_back(rand() % 100);           // 生成 100 以内的随机数
        cout << vInt[i] << " ";                 // 使用下标运算符输出数组内容
    }
    cout << endl;
    // 使用范围 for 循环把数组中的奇数翻倍
    for (auto &val : vInt) {
        val = (val % 2 != 0) ? val * 2 : val;   // 条件表达式
    }
    // 使用普通 for 循环和迭代器输出数组的当前值
    cout << "调整后的数组是:" << endl;
    for (auto it = vInt.cbegin(); it != vInt.cend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    return 0;
}

// 运行结果
数组的初始值是:
89 75 55 1 45 73 90 21 38 82 
调整后的数组是:
178 150 110 2 90 146 90 42 38 82 
Process finished with exit code 0

4.22

【题目思路】

条件表达式的工作方式类似于 if-else 语句。条件表达式可以嵌套,但是嵌套层数越少越好,如果嵌套层数太多,代码的可读性会变得很差。

【回答】

使用条件运算符实现的程序如下所示:

#include 
#include 
using namespace std;
int main() {
    string finalgrade;
    int grade;
    cout << "请输入您要检查的成绩:" << endl;
    // 确保输入的成绩合法
    while (cin >> grade && grade >= 0 && grade <= 100) {
        // 使用三层嵌套的条件表达式
        finalgrade = (grade > 90) ? "high pass"
                : (grade > 75) ? "pass"
                : (grade > 60) ? "low pass" : "fail";
        cout << "该成绩所处的档次是:" << finalgrade << endl;
        cout << "请输入您要检查的成绩:" << endl;
    }
    cout << finalgrade << endl;
}

// 运行结果
请输入您要检查的成绩:
77
该成绩所处的档次是:pass
请输入您要检查的成绩:
66
该成绩所处的档次是:low pass
请输入您要检查的成绩:
55
该成绩所处的档次是:fail
请输入您要检查的成绩:

使用 if 语句实现的程序如下所示:

#include 
#include 
using namespace std;
int main() {
    string finalgrade;
    int grade;
    cout << "请输入您要检查的成绩:" << endl;
    // 确保输入的成绩合法
    while (cin >> grade && grade >= 0 && grade <= 100) {
        // 使用 if 语句实现
        if (grade > 90)
            finalgrade = "high pass";
        else if (grade > 75)
            finalgrade = "pass";
        else if (grade > 60)
            finalgrade = "low pass";
        else
            finalgrade = "fail";
        cout << "该成绩所处的档次是:" << finalgrade << endl;
        cout << "请输入您要检查的成绩:" << endl;
    }
    cout << finalgrade << endl;
}

// 运行结果
请输入您要检查的成绩:
77
该成绩所处的档次是:pass
请输入您要检查的成绩:
66
该成绩所处的档次是:low pass
请输入您要检查的成绩:
55
该成绩所处的档次是:fail
请输入您要检查的成绩:

4.23

【题目思路】

条件运算符的优先级很低,因此在使用它们形成复合表达式时,必须在适当的地方添加括号。

C++ 运算符优先级

【回答】

题目中几个运算符的优先级顺序是加法运算、相等运算符、条件运算符和赋值运算符从高到低,所以表达式的求值过程是先把s和s[s.size() - 1]相加一个新的字符串,然后将该字符串与字符 s 进行比较是否相等是非法操作,并且不符合程序的意图。

达到程序的初衷,即先判断字符串s的最后一个字符是否为s,如果是,则什么都不做;如果没有,在s的末尾添加一个字符s,我们应该添加括号来强制定义运算符执行顺序。

string p1 = s + (s[s.size() - 1] == 's' ? "" : "s");

4.24

【题目思路】

假设条件运算符是左结合的,即嵌套的条件运算符从左到右求值。

【回答】

原来的程序是:

finalgrade = (grade > 90) ? "high pass"
                        : (grade < 60) ? "fail" : "pass";

根据左结合性的含义,这个公式等价于:

finalgrade = ((grade > 90) ? "high pass" : (grade < 60)) ? "fail" : "pass";

首先检查等级> 90是否为真。如果为真,则第一个条件表达式的值为“高通”;如果不是,则第一个条件表达式的值是grade < 60。该语句将不会编译js中运算符的优先级,因为条件运算符要求两个结果表达式是相同类型或可转换的。即使假设它在语法上通过,也就是第一个条件表达式求值为三种类型,即“高通”,1和0。接下来根据第一个条件表达式的求值结果求解第二个条件表达式,其评估结果为“失败”或“通过”。上述评估过程显然不符合我们的预期。

4.25

【题目思路】

本题的目的是考察位运算符的优先级和计算规则。

C++ 运算符优先级

【回答】

在按位运算符中,运算符 ~ 高于

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论