【C++ Primer Plus】第5章 循环和关系表达式

【for循环】

for语法

for (initialization; test-expression; update-expression){}

  1. 可以在for循环的初始化部分中声明和初始化变量。
  2. 在for循环中声明的 initialization 变量和for内部变量只存在于for循环过程。
  3. 可通过修改 **update-expression **修改步长(可以用”,“将两个表达式合并为一个,同时改变两个量)。
  4. initialization 和 **update-expression **可以省略。但两个分号”;“是必须的。
  5. C++常用的方式是,在for和括号之间加上一个空格,而省略函数名与括号之间的空格。(if 和 while 也是)

for循环步骤:

  1. 设置初始值 initialization
  2. 每轮循环开始前,执行测试 test-expression(bool类型),决定循环体是否被执行。(for循环是入口条件(entry-condition)循环)
  3. 执行循环操作。
  4. 每轮循环结束时,更新用于测试的值 update-expression
// 使用 for 循环反转字符串

#include <iostream>
#include <cstring>

int main(void)
{
    
    
    using namespace std;

    cout << "Enter a word:";
    string word;
    cin >> word;

    char temp;
    int i, j;   //代码在循环之前声明i和j,因为不能用逗号运算符将两个声明组合起来。这是因为声明已经将逗号用于其他用途—分隔列表中的变量。
    for (j=0, i=word.size()-1; j<i; --i, ++j)   // , 列表分隔符
    {
    
    
        temp = word[i];     // temp 循环结束后被丢弃
        word[i] = word[j];
        word[j] = temp;
    }
    cout << word << "\nDone\n";

    return 0;
}

【基于范围的for循环】

int prices[5] = {
    
    1, 2, 3, 4, 5};
for (int x : prices)	// x 最初表示数组的第一个元素
    cout << x << endl;	// 循环显示数组中的每个值

【C++中的一些基础知识】

i++和++i的区别

  1. i++ 返回原来的值,++i 返回加1后的值。
  2. i++ 不能作为左值,而++i可以。
  3. i++前者是先赋值,然后再自增;++i后者是先自增,后赋值。
  4. int i=0; a = i++; //a=0,i=1

bool类型:false and true

  1. cout在显示bool值之前将它们转换为int:0 and 1
  2. cout.setf(ios::boolalpha); 该标记函数命令cout显示true和false,而不是1和0。
  3. <<运算符的优先级比表达式中使用的运算符高, 因此代码使用括号来获得正确的运算顺序。

bool类型的输出:

//bool类型的输出

#include <iostream>

int main(void)
{
    
    
    using namespace std;

    int x;
    // <<运算符的优先级比表达式中使用的运算符高, 因此代码使用括号来获得正确的运算顺序。
    cout << " (x=100)=" << (x=100) << endl; //判定赋值表达式会带来副作用, 即修改被赋值者的值。
    cout << " (x<3)=" << (x<3) << endl;     //cout在显示bool值之前将它们转换为int
    cout << " (x>3)=" << (x>3) << endl;

    for (int i=0; i<2; i++)                 //可以在for循环的初始化部分中声明和初始化变量。i只是在for循环中存在
    {
    
    
        int a = 10;                         //在for循环中声明一个其他的变量,只是在for循环中存在
        cout << "i = " << i << endl;
        cout.setf(ios_base::boolalpha);     //该标记命令cout显示true和false,而不是1和0。
        cout << " (x<3)=" << (x<3) << endl;
        cout << " (x>3)=" << (x>3) << endl;
    }
    //cout << "i = " << i << endl;          // i 消失,只是在for循环中存在
    //cout << "a = " << a << endl;          // a 消失,只是在for循环中存在

    cout << " (x<3)=" << (x<3) << endl;     //false,不知道怎么让cout再显示回int
    cout << " (x>3)=" << (x>3) << endl;

    return 0;
}
 (x=100)=100
 (x<3)=0
 (x>3)=1
i = 0
 (x<3)=false
 (x>3)=true
i = 1
 (x<3)=false
 (x>3)=true
 (x<3)=false
 (x>3)=true

使用 cout 的三种方法

  1. 方法1:using namespae std; //using编译指令
  2. 方法2:using std::cout; //using声明
  3. 方法3:std::cout << "Enter a number:" << std::endl;

用for循环和数组计算阶乘:

//
// 用for循环和数组计算阶乘: n!=1×2×3×...×(n-1)×n, 0!=1
//

#include <iostream>

const int ArSize = 16;  // example of external declaration

int main()
{
    
    
    long long factorials[ArSize];
    factorials[1] = factorials[0] = 1LL;    //连续赋值,从右到左
    for (int i = 2; i < ArSize; i++)
        factorials[i] = i * factorials[i-1];
    for (int i = 0; i < ArSize; i++)
        std::cout << i << "! = " << factorials[i] << std::endl;
    return 0;
}

//下面是我自己写的,哈哈哈太low了,而且很多地方没有考虑到位
//#include <iostream>
//
//int main(void)
//{
    
    
//    using namespace std;
//
//    int jiecheng=1;   //阶乘增加很快,int数值范围太小
//    int n;
//
//    cout << "Enter a number:";
//    cin  >> n;
//
//    if (n!=0)
//        for(int i=1; i<(n+1); i++)
//        {
    
    
//            jiecheng = i * jiecheng;
//        }
//    cout << n << "!=" << jiecheng << endl;
//
//    return 0;
//}

完整表达式

何为完整表达式呢?它是这样一个表达式: 不是另一个更大表达式的子表达式。
完整表达式的例子: 表达式语句中的表达式部分 以及 用作while循环中检测条件的表达式。

int guests = 9;
while (guests++ < 10)
    cout << guests << endl;	//output 10,while循环中检测条件是一个完整表达式,所以和10比较之后自加一存储

非完整表达式的例子:y = (4 + x++) + (6 + x++);4 + x++不是一个完整的表达式不保证x的值在计算子表达式4 + x++后立刻增加1。

前缀后缀

  1. C++允许您针对类定义这些运算符
  2. 前缀函数++i: 将值加1, 然后返回结果;
  3. 后缀i++:首先复制一个副本, 将其加1, 然后将复制的副本返回。
  4. 因此, 对于类而言, 前缀版本的效率比后缀版本高。

递增递减运算符和指针

将递增/递减运算符用于指针时, 将把指针的值增加/减少其指向的数据类型占用的字节数.

//
// Created by chaikeya on 2022/8/21.
//递增递减运算符和指针, 前缀和后缀
//
#include <iostream>

int main(void)
{
    
    
    using namespace std;

    double arr[5] = {
    
    21.1, 32.8, 23.4, 45.2, 37.4};
    double *pt = arr;   // 该语句执行完: pt = &arr[0], *pt = arr[0] = 21.1
    ++pt;               // 该语句执行完: pt = &arr[1], *pt = arr[1] = 32.8
    double x = *++pt;   // 该语句执行完: pt = &arr[2], *pt = arr[2] = 23.4, x =  arr[2] = 23.4

    ++*pt;              // 该语句执行完: pt = &arr[2], *pt = arr[2] = 23.4 + 1 = 24.4
    (*pt)++;            // 该语句执行完: pt = &arr[2], *pt = arr[2] = 24.4 + 1 = 25.4

    x = *pt++;          // 该语句执行完: pt = &arr[3], *pt = arr[3] = 25.4, x =  arr[2] = 25.4
    //后缀运算符意味着将对原来的地址(&arr[2]) 而不是递增后的新地址解除引用, 因此*pt++的值为arr[2],即25.4.

    return 0;
}

复合语句(语句块)

  1. 代码块由一对花括号和它们包含的语句组成, 被视为一条语句.
  2. 如果在语句块中定义一个新的变量,则仅当程序执行该语句块中的语句时,该变量才存在。执行完该语句块后,变量将被释放。这表明此变量仅在该语句块中才是可用的.
  3. 如果在一个语句块中声明一个变量,而外部语句块中也有一个这种名称的变量,情况将如何呢?在声明位置到内部语句块结束的范围之内,新变量将隐藏旧变量;然后就变量再次可见.
//
// Created by chaikeya on 2022/8/21.
// 复合语句(语句块)
//
#include <iostream>

int main(void)
{
    
    
    using namespace std;

    int x = 20;             // original x

    {
    
       // block starts
        cout << x << endl;  // use original x

        int y;              // y 只存在于语句块中
        y = x++;            // 后缀运算符,y = 20, x = 21

        int x = 100;        // new x = 100
        x += 1;             // 组合赋值运算符,左=左+右
        cout << x << endl;  // use new x = 101
    }   // block ends

    cout << x << endl;      // use original x = 20
    //cout << y << endl;    // y 不存在

    return 0;
}

运算符

组合赋值运算符:
+=运算符将两个操作数相加,并将结果赋给左边的操作数。这意味着左边的操作数必须能够被赋值,如变量、数组元素、结构成员或通过对指针解除引用来标识的数据。

逗号运算符:

  1. int cats = 17, 240; // cats=17, 240不起作用
  2. int cats = (17, 240); // cats=240, 逗号表达式的值是第二部分的值.

关系运算符:>, <, >=, <=, !=, ==,
比较结果为 bool 值,int x = (3>5);此时x=0,将bool值提升为int。
算术运算符:+, -, *, /,
优先级:(由高到低执行)算术运算符 > 关系运算符 > 逗号运算符
x + 3 > y -2等价于(x + 3) > (y -2)

C-风格字符串的比较 strcmp()

  1. strcmp()该函数接受两个字符串地址作为参数(数组名是一个地址,字符串也是一个地址)
  2. strcmp()如果两个字符串相同,该函数将返回零
  3. strcmp()如果第一个字符串按字母顺序排在第二个字符串之前(后)返回一个负(正)数
// C-风格字符串的比较 strcmp()
// 该程序显示一个单词,修改其首字母,然后再次显示这个单词,这样循环往复,直到strcmp( )确定该单词与字符串“mate”相同为止。
// strcmp()该函数接受两个字符串地址作为参数(数组名是一个地址,字符串也是一个地址)
// strcmp()如果两个字符串相同,该函数将返回零
// strcmp()如果第一个字符串按字母顺序排在第二个字符串之前(后)返回一个负(正)数

#include <iostream>
#include <cstring>	// strcmp()函数的头文件

int main(void)
{
    
    
    using namespace std;

    char word[5] = "?ate";     // strcmp()该函数接受两个字符串地址作为参数(数组名是一个地址,字符串也是一个地址)
    for (char ch = 'a'; strcmp(word, "mate"); ch++) // strcmp()如果字符串不相等,则它的值为非零(true);
                                                    // strcmp()如果字符串相等,则它的值为零(false)。
    {
    
    
        cout << word << endl;
        word[0] = ch;
    }
    cout << "After loop ends, word is " << word << endl;

    cout << strcmp("abc", "ABC") << endl;   // return 1 (正数),ASCII表中A在a前

    return 0;
}

string 类字符串的比较:关系运算符

// string 类字符串的比较
// 类设计让您能够使用关系运算符进行比较
#include <iostream>
#include <string>   // string class

int main(void)
{
    
    
    using namespace std;

    string word = "?ate";
    for (char ch  = 'a'; word != "mate"; ch++)  // 可以将关系运算符用于string对象
    {
    
    
        cout << word << endl;
        word[0] = ch;
    }
    cout << "After loop ends, word is " << word << endl;

    return 0;
}

类型别名

  1. 预处理器:#define A B 用 A 替代 B
  2. 关键字typedef:typedef A B; 用 B 替代 A

【while循环】

while循环是没有初始化和更新部分的for循环,它只有测试条件和循环体:(入口条件(entry-condition)循环)

头文件ctime:

  1. 首先,定义了一个符号常量—CLOCKS_PER_SEC,该常量等于每秒钟包含的系统时间单位数.
  2. 因此,将系统时间除以这个值,可以得到秒数。或者将秒数乘以CLOCK_PER_SEC,可以得到以系统时间单位为单位的时间.
  3. 其次, ctime将clock_t作为clock( )返回类型的别名, 这意味着可以将变量声明为clock_t类型,编译器将把它转换为long、unsigned int或适合系统的其他类型。

用 while 和 clock 编写一个延迟循环:

// 如何使用clock()和头文件ctime来创建延迟循环。

#include <iostream>
#include <ctime>    // clock_t 的头文件

int main(void)
{
    
    
    using namespace std;

    cout << "Enter the delay time, in seconds:";
    float secs;
    cin  >> secs;
    clock_t delay = secs * CLOCKS_PER_SEC;  // 以系统时间单位为单位(而不是以秒为单位) 计算延迟时间

    cout << "starting\a\n";
    clock_t start = clock();
    while (clock() - start < delay);    // while 循环体为空语句
    cout << "done!\a\n";

    return 0;
}

【do while 循环】

  1. 出口条件(exit condition)循环。
  2. 首先执行循环体, 然后再判定测试表达式, 决定是否应继续执行循环。
  3. 如果条件为false, 则循环终止; 否则, 进入新一轮的执行和测试。
  4. 这样的循环通常至少执行一次,因为其程序流必须经过循环 体后才能到达测试条件。

用法:请求用户输入时, 程序必须先获得输入, 然后对它进行测试 。

【循环和文本输入】

cin对象支持3种不同模式的单字符输入

  1. cin
  2. cin.get(char);
    C语言:要修改变量的值, 必须将变量的地址传递给函数。C++:头文件iostream将cin.get(ch)的参数声明为引用类型, 因此该函数可以修改其参数的值。
    函数重载允许创建多个同名函数, 条件是它们的参数列表不同。
    数组名是其第一个元素的地址, 因此字符数组名的类型为char*
    检测文件尾(EOF)
    while (cin.fail() == false){...}通过键盘来模拟文件尾条件。
    在Unix中, 可以在行首按下Ctrl+D来实现; 在Windows命令提示符模式下, 可以在任意位置按Ctrl+Z和Enter。
  3. cin.get()

while (cin.get(ch)); 三条指导原则(确定结束条件、 对条件进行初始化以及更新条件) 全部被放在循环测试条件中。

  1. cin.get(ch) 为判断循环测试条件, 程序必须首先调用cin.get(ch)。如果成功,则将值放入ch中。
  2. 然后,程序获得函数调用的返回值,即cin。
  3. 接下来,程序对cin进行bool转换, 如果输入成功, 则结果为true, 否则为false。

while ((ch = cin.get()) != EOF)

  1. 程序必须首先调用cin.get( )函数, 然后将该函数的返回值赋给ch。
  2. 由于赋值语句的值为左操作数的值, 因此整个子表达式变为ch的值。
  3. 如果这个值是EOF, 则循环将结束, 否则继续。
  4. 该测试条件中所有的括号都是必不可少的。 (因为!=运算符的优先级高于=)

输入/输出

// 方法一:
int ch; 			// for compatibility with EOF value
ch = cin.get();
while (ch != EOF)
{
    
    
    cout.put(ch); 	// cout.put(char(ch)) for some implementations
    ch = cin.get();
}

// 方法二:
char ch;
cin.get(ch);	// cin.get(ch)返回一个对象, 而不是读取的字符
while (cin.fail() == false) 	// test for EOF
{
    
    
    cout << ch;
    cin.get(ch);
}

【嵌套循环和二维数组 】

二维数组int maxtemps[4][5];

假设要打印数组所有的内容, 可以用一个for循环来改变行, 用另一个被嵌套的for循环来改变列:

for (int row = 0; row < 4; row++)
{
    
    
    for (int col = 0; col < 5; ++col)
        cout << maxtemps[row][col] << "\t";
        cout << endl;
}

将一个指针数组初始化为一组字符串常量:

也就是说,将cities声明为一个char指针数组。这使得每个元素(如cities[0])都是一个char指针,可被初始化为一个字符串的地址。程序将cities [0]初始化为字符串“Gribble City”的地址.

指针数组 = char数组的数组 = string对象数组

  1. 指针数组:char * cities[5]
  2. char数组的数组:char cities[5][25]
  3. string对象数组:char string cities[5]
// 初始化了一个二维数组, 并使用了一个嵌套循环

// 将一个指针数组初始化为一组字符串常量。
// 也就是说,将cities声明为一个char指针数组。这使得每个元素(如cities[0])都是一个char指针,可被初始化为一个字符串的地址。
// 程序将cities [0]初始化为字符串“Gribble City”的地址

#include <iostream>
const int Cities = 5;
const int Years = 4;
int main()
{
    
    
    using namespace std;
                                    // 可以试用使用char数组的数组 char cities[Cities][25]
                                    // 还可以使用string对象数组 string cities[Cities]
    const char * cities[Cities] =   // 将cities声明为一个char指针数组
            {
    
     // to 5 strings
                    "Gribble City", // cities[0]初始化为字符串“Gribble City”的地址
                    "Gribbletown",
                    "New Gribble",
                    "San Gribble",
                    "Gribble Vista"
            };
    int maxtemps[Years][Cities] = // 2-D array 初始化
            {
    
    
                    {
    
    96, 100, 87, 101, 105}, // values for maxtemps[0]
                    {
    
    96, 98, 91, 107, 104}, // values for maxtemps[1]
                    {
    
    97, 101, 93, 108, 107}, // values for maxtemps[2]
                    {
    
    98, 103, 95, 109, 108} // values for maxtemps[3]
            };
    cout << "Maximum temperatures for 2008 - 2011\n\n";
    for (int city = 0; city < Cities; ++city)
    {
    
    
        cout << cities[city] << ":\t";
        for (int year = 0; year < Years; ++year)
            cout << maxtemps[year][city] << "\t";
        cout << endl;
    }
// cin.get();
    return 0;
}

【总结】

  1. C++提供了3种循环: for循环、 while循环和do while循环。 如果循环测试条件为true或非零, 则循环将重复执行一组指令; 如果测试条件为false或0, 则结束循环。 for循环和while循环都是入口条件循环, 这意味着程序将在执行循环体中的语句之前检查测试条件。 do while循环是出口条件循环, 这意味着其将在执行循环体中的语句之后检查条件。
  2. 每种循环的句法都要求循环体由一条语句组成。 然而, 这条语句可以是复合语句, 也可以是语句块(由花括号括起的多条语句) 。
  3. 关系表达式对两个值进行比较, 常被用作循环测试条件。 关系表达式是通过使用6种关系运算符之一构成的: <、 <=、 = =、 >=、 >或! =。关系表达式的结果为bool类型, 值为true或false。
  4. 许多程序都逐字节地读取文本输入或文本文件, istream类提供了多种可完成这种工作的方法。
  5. 如果ch是一个char变量, 则下面的语句将输入中的下一个字符读入到ch中:cin >> ch; 它将忽略空格、 换行符和制表符。
  6. 下面的成员函数调用读取输入中的下一个字符(而不管该字符是什么) 并将其存储到ch中:cin.get(ch);成员函数调用cin.get( )返回下一个输入字符—包括空格、 换行符和制表符, 因此, 可以这样使用它:ch = cin.get();
  7. cin.get(char) 成员函数调用通过返回转换为false的bool值来指出已到达EOF, 而cin.get( )成员函数调用则通过返回EOF值来指出已到达EOF, EOF是在文件iostream中定义的。
  8. 嵌套循环是循环中的循环, 适合用于处理二维数组。

【编程练习】

// 5.9.2
// 使用array对象(而不是数组)和long double(而不是long long)重新编写程序清单5.4,并计算100!的值。

#include <iostream>
#include <array>

using namespace std;

const int ArSize = 100;  // example of external declaration

int main()
{
    
    
    array<long double, ArSize> factorials;
    factorials[1] = factorials[0] = 1LL;    //连续赋值,从右到左

    for (int i = 2; i < ArSize; i++)
        factorials[i] = i * factorials[i-1];

    cout << ArSize << "! = " << factorials[99] << endl;

    return 0;
}


// 5.9.4
// Daphne   利息 = 0.10×原始存款
// Cleo     利息 = 0.05×当前存款
// 计算多少年后, Cleo的投资价值才能超过Daphne的投资价值, 并显示此时两个人的投资价值。

#include <iostream>

int main(void)
{
    
    
    using namespace std;

    double Daphne_account=100;
    double Cleo_account=100;
    int years=0;
    while (Daphne_account >= Cleo_account)
    {
    
    
        years++;
        Daphne_account+=10;
        Cleo_account=Cleo_account*1.05;
    }
    cout << "After " << years << " years " << "Cleo is richer than Daphne " << endl;
    cout << "Cleo_account = " << Cleo_account << endl;
    cout << "Daphne_account = " << Daphne_account << endl;

    return 0;
}


// 5.9.7
// 设计一个名为car的结构, 用它存储下述有关汽车的信息: 生产商(存储在字符数组或string对象中的字符串) 、 生产年份(整数) 。
// 编写一个程序,向用户询问有多少辆汽车。随后,程序使用new来创建一个由相应数量的car结构组成的动态数组。
// 接下来, 程序提示用户输入每辆车的生产商(可能由多个单词组成) 和年份信息。
// 请注意, 这需要特别小心, 因为它将交替读取数值和字符串(参见第4章) 。
// 最后,程序将显示每个结构的内容。

#include <iostream>
#include <cstring>

using namespace std;
struct car
{
    
    
    std::string make;
    int year;
};

int main(void)
{
    
    
    int n;
    cout << "How many:";
    cin >> n;
    car *pt = new car[n];

    for (int i=0; i < n; ++i)
    {
    
    
        cout << "Car #" << i+1 << ":" << endl;
        cout << "Place enter the make:";
        cin >> pt[i].make;
        cout <<"please enter the year make: ";
        cin>>pt[i].year;
    }
    cout<<" Here is your collection: "<<endl;
    for (int i = 0; i < n; i++)
    {
    
    
        cout << pt[i].make<<"   "<<pt[i].year<<endl;
    }

    delete [] pt;
}


// 5.9.8
// 编写一个程序, 它使用一个char数组和循环来每次读取一个单词,直到用户输入done为止。
// 随后,该程序指出用户输入了多少个单词(不包括done在内) 。
// 用string类的方法实现

#include <iostream>
#include <cstring>

int main(void)
{
    
    
    using namespace std;

    int num_word=0;
    char letter[128];   //string letter;
    cout<<"Enter words (type done to stop)"<<endl;
    while (cin >> letter)
    {
    
    
        if (!(strcmp(letter, "done")))  //if (letter == "done")
        {
    
    
            break;
        }
        num_word++;
    }
    cout<<"You enter a total of "<<num_word<<" words."<<endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39751352/article/details/126530764
今日推荐