《C++ primer plus》学习笔记——第五章

版权声明:扫我头像就可以向我提问,共同提高:) https://blog.csdn.net/u011436427/article/details/83623957

一、for循环

1.for循环的组成部分

for循环的步骤
a)设置初始值
b)执行测试,看看循环是否应当继续进行
c)执行循环操作
d)更新用于测试的值

在这里插入图片描述

说明:
a)每部分都是一个表达式,彼此用分号隔开,只要测试表达式为true,便会执行循环体body
b)循环只执行一次初始化;
c)test-expression(测试表达式),这个表达式是关系表达式,可以采用任意表达式,C++把结果强制转换为bool类型,so:0->bool的false,1->bool的true;
d)for循环是入口条件(entry-condition)循环,当测试表达式为false时,将不会执行循环体;
e)update-expression(更新表达式)在每轮循环结束的时候执行,此时循环体已经执行完毕;
f)写for语句的习惯:
在这里插入图片描述

eg:

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x

// num_test.cpp -- use numeric test in for loop

int main()
{
    using namespace std;
    cout << "Enter the starting countdown value: ";
    int limit;
    cin >> limit;
    int i;
    for (i = limit; i; i--)     // quits when i is 0
        cout << "i = " << i << "\n";
    cout << "Done now that i = " << i << "\n";
	system("pause");
	return 0;
}


在这里插入图片描述

解释:

在这里插入图片描述

一张图说明一切:
在这里插入图片描述

说明:
1)表达式和语句

扫描二维码关注公众号,回复: 4938409 查看本文章

C++中每个表达式都有值。C++优先级表明,赋值运算符是从右向左结合的。
只要加上分号,所有表达式都可以成为语句,但是不一定有编程意义;

eg:下面的是表达式的有:
在这里插入图片描述
在这里插入图片描述

下面的是语句的有:

在这里插入图片描述

有效但无意义的有:

在这里插入图片描述

eg:

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x

// num_test.cpp -- use numeric test in for loop

int main()
{
    using namespace std;
    int x;

    cout << "The expression x = 100 has the value ";
    cout << (x = 100) << endl;
    cout << "Now x = " << x << endl;
    cout << "The expression x < 3 has the value ";
    cout << (x < 3) << endl;
    cout << "The expression x > 3 has the value ";
    cout << (x > 3) << endl;
    cout.setf(ios_base::boolalpha);   //a newer C++ feature
    cout << "The expression x < 3 has the value ";
    cout << (x < 3) << endl;
    cout << "The expression x > 3 has the value ";
    cout << (x > 3) << endl;
    /// cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明 :
在这里插入图片描述

2)非表达式和语句

从语句中删除分号,并不一定能转换为表达式。
在这里插入图片描述

3)修改规则

C++可以在for循环初始化部分中申明和初始化变量,这种变量只存在于for中,当程序离开循环后,这种变量将消失。

2.回到for循环

eg:计算并存储16个阶乘

方法:通过观察规律发现
在这里插入图片描述

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x

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;
	// std::cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明:

a)

在这里插入图片描述

b)数组在何处停止?
在这里插入图片描述

c)const的作用
在这里插入图片描述

d)标准名称的使用
在这里插入图片描述

3.修改步长

可以通过修改更新表达式来修改步长

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x

int main()
{
	using std::cout;    // a using declaration
    using std::cin;
    using std::endl;;
    cout << "Enter an integer: ";
    int by;
    cin >> by;
    cout << "Counting by " << by << "s:\n";
    for (int i = 0; i < 100; i = i + by)
        cout << i << endl;
    // cin.get();
    // cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明:
a)更新表达式可以是任何有效的表达式
b)检测不等常比检测相同要好
c)
在这里插入图片描述

4.使用for循环访问字符串

1)可以使用string对象,也可以使用char数组,都可以使用数组表示法来访问字符串中的字符
2)string类的size()获得字符串中的字符数(使用这个不考虑空值字符);
3)反向计数用了递减运算符–

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

int main()
{
    using namespace std;
    cout << "Enter a word: ";
    string word;
    cin >> word;


	cout<<word.size()<<endl;
    // display letters in reverse order
    for (int i = word.size() - 1; i >= 0; i--)
        cout << word[i];
    cout << "\nBye.\n";
    // cin.get();
    // cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

5.递增运算符++和递减运算符–

前缀,++x;
后缀,x++;
两个版本对操作数的影响是一样的,但是影响的时间是不一样的

eg:

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

int main()
{
    using std::cout;
    int a = 20;
    int b = 20;

    cout << "a   = " << a << ":   b = " << b << "\n";
    cout << "a++ = " << a++ << ": ++b = " << ++b << "\n";
    cout << "a   = " << a << ":   b = " << b << "\n";
    // std::cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明:

1)
a++意味着使用a的当前值计算表达式,然后再将a的值加1;
++b的意思是先将b的值加1,然后使用新的值来计算表达式;

2)eg:
在这里插入图片描述

6.副作用和顺序点

副作用side effect指的是:计算表达式时对某些东西(eg:存储在变量中的值)进行了修改;

顺序点sequence point指的是:程序执行过程中一个点,在C++中,分号就是一个顺序点,另外,任何完整的表达式末尾都是一个顺序点。
顺序点的作用:能够有助于阐明后缀递增何时进行。
eg:
在这里插入图片描述

说明:
表达式guests++<10是一个完整表达式,因为他是一个while循环的测试条件,因此该表达式的末尾是一个顺序点。所以,C++确保副作用(将guests加1)在程序进入cout之前完成

eg:
在这里插入图片描述

说明:
在这里插入图片描述

7.前缀格式和后缀格式

eg:
在这里插入图片描述

说明:
1)在这里插入图片描述

2)
在这里插入图片描述

8.递增/递减运算符和指针

可将递增运算符用于指针和基本变量,将递增运算符用于指针时,将把指针的值增加其指向的数据类型占用的字节数

前缀递增(递减)和解除引用*的优先级相同,以从右到左的方向进行结合;
后缀递增和递减的优先级相同,但比前缀运算符的优先级高,这俩运算符是从左到右的方式进行结合。

不理解上述的话,就看例子就懂了!
前置和后置运算符的使用举例(注意最终的值以及pt指向哪里
eg:
在这里插入图片描述

**在这里插入图片描述**
说明:++*pt意味着:先取地pt指向的值,然后将这个值加1

在这里插入图片描述
说明:pt仍然指向arr[2]

在这里插入图片描述
说明:圆括号指出先对指针解除引用,得到24.4。然后运算符++将这个值递增到25.4,pt仍然指向arr[2]

在这里插入图片描述
说明:注意x最终的值以及pt指向哪里
在这里插入图片描述

9.组合赋值运算符

在这里插入图片描述

组合赋值运算符的表格
在这里插入图片描述

10.复合语句(语句块)

C++可以在循环体中包含任意多条语句,方法是用两个花括号来构造一条复合语句(代码块)。

eg:

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

int main()
{
    using namespace std;
    cout << "The Amazing Accounto will sum and average ";
    cout << "five numbers for you.\n";
    cout << "Please enter five values:\n";
    double number;
    double sum = 0.0;
    for (int i = 1; i <= 5; i++)
    {                                   // block starts here
        cout << "Value " << i << ": ";
        cin >> number;
        sum += number;
    }                                   // block ends here
    cout << "Five exquisite choices indeed! ";
    cout << "They sum to " << sum << endl;
    cout << "and average to " << sum / 5 << ".\n";
    cout << "The Amazing Accounto bids you adieu!\n";
    // cin.get();
    // cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明:
1)
在这里插入图片描述

2)若在语句块中定义一个新的变量,则仅当程序执行该语句块中的语句时,该变量才存在,执行完该语句块后,变量将被释放。

3)若在一个语句块中申明一个变量,而在外部语句中也有一个这种名称的变量,情况?
在申明位置到内部语句块结束的范围之内,新变量将隐藏旧变量,然后旧变量再次可见
eg:
在这里插入图片描述

11.其它语法技巧——逗号运算符

逗号运算符对表达式完成同样的任务,允许将两个表达式放到C++语法只允许放一个表达式的地方。

eg:for循环的更新部分可将两个表达式合并为一个
在这里插入图片描述

eg:申明中的逗号将变量列表中相邻的名称分开
在这里插入图片描述

eg:该程序将数组中的字符顺序反转,还用了语句块(将几条语句合成一条)

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

int main()
{
    using namespace std;
    cout << "Enter a word: ";
    string word;
    cin >> word;

    // physically modify string object
    char temp;
    int i, j;
    for (j = 0, i = word.size() - 1; j < i; --i, ++j)
    {                       // start block
        temp = word[i];
        word[i] = word[j];
        word[j] = temp;
    }                       // end block
    cout << word << "\nDone\n";
    // cin.get();
    // cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明:
1)初始化和更新部分
在这里插入图片描述

2)循环体
测试条件j<i使得到达数组的中间,循环将终止。
用一个图来说明反转字符串
在这里插入图片描述

3)也可以使用一个申明语句表达式来创建并初始化两个变量。
eg:
在这里插入图片描述

4)也可以在for循环内部声明temp

eg:
在这里插入图片描述

4)逗号运算符最常见的用途是将两个或更多的表达式放到一个for循环表达式中
首先,它确保计算第一个表达式,然后计算第二个表达式;
其次,C++规定,逗号表达式的值是第二部分的值。
在所有运算符中,逗号运算符的优先级是最低的。

eg:
在这里插入图片描述

12.关系表达式

在C++中,关系运算符可以对值进行比较;
关系运算符不能用于C风格的字符串,但是可以用于string类对象

对于所有的关系表达式,如果比较结果为真,则其值将为true,否则为false,因此可将其用于循环测试的表达式。

在这里插入图片描述

eg:
在这里插入图片描述

13.赋值、比较和可能犯的错误

不要混淆等于运算符(==)与赋值运算符

eg:
下面的程序指出了可能出现这种错误的情况。
该程序的作用是:检查一个存储了测验成绩的数组,在遇到第一个不为20的成绩时停止。

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

int main()
{
    using namespace std;
    int quizscores[10] =
        { 20, 20, 20, 20, 20, 19, 20, 18, 20, 20};

    cout << "Doing it right:\n";
    int i;
    for (i = 0; quizscores[i] == 20; i++)
        cout << "quiz " << i << " is a 20\n";
// Warning: you may prefer reading about this program
// to actually running it.
    cout << "Doing it dangerously wrong:\n";
    for (i = 0; quizscores[i] = 20; i++)
        cout << "quiz " << i << " is a 20\n";
	// cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明:

1)错误的地方始终是true
在这里插入图片描述

对于C++类,可以设计一种保护数组类型来防止这种错误,如果所有的成绩都是20,“好”的循环也会超出数组边界。总之,循环需要测试数组的值和索引的值

2)注意:不要使用=来比较两个量是否相等,而要使用==

14.C风格字符串的比较

1)数组名是数组的地址
2)如果word是数组名,eg:
在这里插入图片描述
用括号括起来的字符串常量也是其地址
因此,上面的关系表达式不是判断两个字符串是否相同,而是查看它们是否存储在相同的地址上。两个字符串的地址是否相同呢??答案是否定的,虽然他们包含相同的字符串。

C++将C风格的字符串视为地址,如果使用关系运算符来比较它们,将无法得到满意的结果。

3)应该使用C风格字符串库中的strcmp()函数来比较。
该函数接受两个字符串地址作为参数,这些参数可以是指针、字符串常量或者字符串数组名。
若两个字符串相同,该函数将返回0;
如果第一个字符串按字母顺序排在第二个字符串之前,则strcmp()将返回一个负数值;
如果第一个字符串按字母顺序排在第二个字符串之后,则strcmp()将返回一个正数值;

在这里插入图片描述

4)对于存储在不同长度的数组中的字符串而言,C风格字符串是通过结尾的空值字符定义的,而不是由其所在数组的长度定义的。
也就是说,两个字符串即使被存储在长度不同的数组中,也有可能是相同的

eg:

在这里插入图片描述

说明:虽然不能用关系运算符来比较字符串,但是却可以用它们来比较字符,因为字符实际上是整型。

在这里插入图片描述

5)
eg:
在这里插入图片描述

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

int main()
{
    using namespace std;
    char word[5] = "?ate";

    for (char ch = 'a'; strcmp(word, "mate"); ch++)
    {
        cout << word << endl;
        word[0] = ch;
    }
    cout << "After loop ends, word is " << word << endl;
    // cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明:
1)我们希望只要word不是mate,循环就可以继续进行

在这里插入图片描述
使用strcmp(word,“mate”),若字符串不相等,则它的值为非0(true);
若字符串相等,则它的值为0(false);

2)strcmp()的其它用法
在这里插入图片描述

15.比较string类字符串

string类字符串可以直接使用关系运算符进行比较,这是因为类函数重载(重新定义)了这些运算符

eg:

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

int main()
{
    using namespace std;
    string word = "?ate";

    for (char ch = 'a'; word != "mate"; ch++)
    {
        cout << word << endl;
        word[0] = ch;
    }
    cout << "After loop ends, word is " << word << endl;
    // cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明:

1)
在这里插入图片描述

2)进一步,如果不对语句块执行指定的次数做出要求的话,对于这种测试,C++通常使用while循环

二、while循环

while介绍

1)while循环是没有初始化和更新部分的for循环,它只有测试条件和循环体
在这里插入图片描述

说明:
a)
在这里插入图片描述

b)若希望循环体最终能够结束,循环体中的代码必须完成某种影响测试条件表达式的操作;

c)和for循环一样,while循环也是一种入口条件循环。因此,如果测试条件一开始为false,则程序将不会执行循环体;

2)一张图搞定while如何循环
在这里插入图片描述

例子:关于循环遍历字符串
在这里插入图片描述
说明:
a)循环遇到空值字符时停止,由于字符串中包含了结尾标记,所以程序通常不需要知道字符串的长度;
b)逐字符遍历字符串直到遇到空值字符的技术是C++处理C风格字符串的标准方法;

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

const int ArSize = 20;
int main()
{
    using namespace std;
    char name[ArSize];

    cout << "Your first name, please: ";
    cin >> name;
    cout << "Here is your name, verticalized and ASCIIized:\n";
    int i = 0;                  // start at beginning of string
    while (name[i] != '\0')     // process to end of string
    {
        cout << name[i] << ": " << int(name[i]) << endl;
        i++;                    // don't forget this step
    }
	system("pause");
	return 0;
}


在这里插入图片描述

说明:
1)循环体结尾将i+1使得该测试能够成功,若省略这一步,是导致死循环的常见问题直以
通常,不要忘记在循环体中更新某个值

2)可将while条件:
while(name[i]!=’\0’)
->
while(name[i])

经过这种修改后,程序的工作方式不变。(强烈推荐上述的写法,简洁且常用)
由于name[i]是常规字符,其值为该字符的编码,为非0或true
当name[i]为空值字符时,其编码为0或false;

3)要打印ASCII码,必须通过强制类型转换,将name[i]转换为整型

4)不同于C风格字符串,string对象不适用空字符来标记字符串末尾

1.for与while

1)在C++中,for和while循环本质上是相同的

可将for循环->while循环
在这里插入图片描述

->
在这里插入图片描述

while循环->改写成for循环
在这里插入图片描述
->
在这里插入图片描述
说明:只有两个分号是必须的。

2)省略for循环中的测试表达式时,测试结果将为true,因此,下面的循环将一直运行下去。
在这里插入图片描述

3)由于for循环和while循环几乎是等效的。
所以,for和while循环的区别主要在于:
a)for循环中省略了测试条件时,将认为条件为true;
b)在for循环中,可使用初始化语句申明一个局部变量,但是在while中不能这么做;
c)如果循环体中包括continue,情况将稍有不同;

so,程序员使用for循环来为循环计数;再无法预知循环执行的次数时,使用while

4)在设计for和while循环的时候,应该记住下面的几条指导原则
a)在首次测试之前初始化条件
b)指定循环终止的条件
c)在条件被再次测试之前更新条件

补充:写循环的时候,错误的标点符号
a)语句块是由花括号,而不是由缩进定义的
eg:
在这里插入图片描述

b)while后面直接加分号,会造成一种死循环
在这里插入图片描述

2.等待一段时间:编写延时循环

C和C++都一个函数名为clock()的一个函数,返回程序开始执行后所用的系统时间

在头文件ctime提供了这些问题的解决方案:
a)它定义了一个符号常量CLOCKS_PER_SEC,该常量=每秒钟包含的系统时间的单位数。
所以,将系统时间除以这个值,可以得到秒数;将秒数乘以这个值,可以得到以系统时间为单位的时间。
b)ctime将clock_t作为clock()返回类型的别名,意思是可将变量申明为clock_t类型。

eg:

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

#include <ctime> // describes clock() function, clock_t type
int main()
{
    using namespace std;
    cout << "Enter the delay time, in seconds: ";
    float secs;
    cin >> secs;
    clock_t delay = secs * CLOCKS_PER_SEC;  // convert to clock ticks
    cout << "starting\a\n";
    clock_t start = clock();
    while (clock() - start < delay )        // wait until time elapses,为啥这么写?
        ;                                   // note the semicolon注意分号
    cout << "done \a\n";
	system("pause");
	return 0;
}


在这里插入图片描述

说明:
在这里插入图片描述

补充:类型别名typedef和define

C++为类型建立别名的方式有两种
a)使用预处理器define
在这里插入图片描述

b)使用C++和C的关键字typedef来创建
typedef的通用格式是:
在这里插入图片描述

eg:
在这里插入图片描述

eg:
在这里插入图片描述

3.do while循环

1)for和while是入口循环,do while是出口循环

2)do while循环的程序流程
首先执行循环体,然后再判定测试表达式,若false,则循环终止;否则,进入新的一轮进行执行和测试。

在这里插入图片描述

3)循环至少被执行一次;
入口条件循环比出口条件循环好,因为入口条件循环在循环开始之前对条件进行检查。

eg:

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

#include <ctime> // describes clock() function, clock_t type
int main()
{
    using namespace std;
    int n;

    cout << "Enter numbers in the range 1-10 to find ";
    cout << "my favorite number\n";
    do
    {
        cin >> n;       // execute body
    } while (n != 7);   // then test
    cout << "Yes, 7 is my favorite.\n" ;
    // cin.get();
    // cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

补充:编写清晰、容易理解的代码比使用语言的晦涩特性来显示自己的能力更为有用。

例如以下的三个等价的循环的使用:for,while,do while

a)for循环中的空测试条件被视为true
在这里插入图片描述

<=>
在这里插入图片描述

b)while循环
在这里插入图片描述

c)do while循环
在这里插入图片描述

4.基于范围的for循环(C++):目前作为了解即可

eg:
在这里插入图片描述

说明:
1)x最初表示数组prices的第一个元素,会不断执行循环,x以此表示数组的其他元素,最终会循环显示数组中的每个值

2)如果要修改数组的元素
在这里插入图片描述

符号&表明x是一个引用变量,这种申明让接下来的代码能够修改数组的内容。

3)初始化列表的方法:
在这里插入图片描述

5.循环和文本输入:逐字符地读取来自文件或键盘的文本

cin对象支持3种不同模式的单字符输入,其用户接口各不相同。

1.使用原始cin输入:逐字符读-空格不可算

如果程序要使用循环来读取来自键盘的文本输入,则必须有办法知道何时停止读取。

eg:(最原始的方法)
哨兵字符sentinel character:用来标记停止。
在这里插入图片描述

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

#include <ctime> // describes clock() function, clock_t type
int main()
{
    using namespace std;
    char ch;
    int count = 0;      // use basic input
    cout << "Enter characters; enter # to quit:\n";
    cin >> ch;          // get a character
    while (ch != '#')   // test the character
    {
        cout << ch;     // echo the character
        ++count;        // count the character
        cin >> ch;      // get the next character
    }
    cout << endl << count << " characters read\n";
    // cin.get();
    // cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明:
1)对于循环设计而言,结束循环的条件是最后读取的一个字符是#,该条件是通过在循环之前,读取一个字符进行初始化,并通过循环体结尾读取下一个字符进行更新。

具体解释如下:
在这里插入图片描述

对于下面画红圈的代码而言的,解释如下:
在这里插入图片描述
在这里插入图片描述

2)在运行程序的时候,可以在#后面输入字符的原因是,即
在这里插入图片描述

说明:
发送cin的输入被缓冲,这意味着,只有用户按下回车键以后,输入的内容才会被发送给程序

3)从最终的结果,我们可以看到:cin忽略空格和换行符,so,输入中的空格没有被回显,也没有被包括在计数内。

2.使用cin.get(char)进行补救:逐字符读-空格可算

cin属于istream,成员函数**cin.get(ch)**读取输入中的下一个字符(即使它是空格),并将其赋给变量ch。用其代替cin>>ch

eg:

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

#include <ctime> // describes clock() function, clock_t type
int main()
{
    using namespace std;
    char ch;
    int count = 0;

    cout << "Enter characters; enter # to quit:\n";
    cin.get(ch);        // use the cin.get(ch) function
    while (ch != '#')
    {
        cout << ch;
        ++count;
        cin.get(ch);    // use it again
    }
    cout << endl << count << " characters read\n";
// get rid of rest of line
    // while (cin.get() != '\n')
    //    ;
    //cin.get();
	system("pause");
	return 0;
}


在这里插入图片描述

说明:
1)该程序回显了每个字符,并将全部字符计算在内,其中包括空格,输入仍被缓冲

2)重点理解一下C与CPP的区别

通常,在CPP中传递参数的工作方式与在C语言中相同,但是除了cin.get(ch)

在C语言中,要修改变量的值,必须将变量的地址传递给函数。
但是在CPP中函数只需将参数申明为引用即可。头文件iostream将cin.get(ch)的参数申明为引用类型,因此,该函数可以修改其参数的值

3.使用哪一个cin.get()

eg:看看我们前面用的cin.get()的用法
在这里插入图片描述

在这里插入图片描述

说明:
1)cin.get(name,ArSize),可以接受两个参数:数组名(char *类型的字符串的地址)和ArSize(int类型的整数)。
注:数组名是其第一个元素的地址,so,字符数组名的类型为char * 。

2)cin.get(ch)
在C语言中,如果函数接受char指针和int参数,则使用该函数时,不能只传递一个参数,因为类型不同

但是在CPP中,支持函数重载的OOP特性。函数重载允许创建多个同名函数,条件是它们的参数列表不同。
函数重载允许对多个相关的函数使用相同的名称,这些函数以不同方式或针对不同类型执行相同的基本任务。
所以:
如果在CPP中使用cin.get(name,ArSize),则编译器将找到使用char *和int作为参数的cin.get()版本;
如果使用cin.get(ch),则编译器将使用接受一个char参数的版本;
如果使用cin.get(),则编译器将使用不接受任何参数的cin.get()版本。

6.文件尾条件:逐字符读-常用的方法

1)如果输入来自文件,可以使用EOF检测文件尾
很多操作系统都支持重定向,允许用文件替换键盘输入。
eg:
在这里插入图片描述

2)很多操作系统允许通过键盘来模拟文件尾条件。很多PC编程环境都将Ctrl+Z视为模拟的EOF

eg:
在这里插入图片描述

对下面cin.fail()提前的说明
在这里插入图片描述

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

#include <ctime> // describes clock() function, clock_t type
int main()
{
    using namespace std;
    char ch;
    int count = 0;
    cin.get(ch);        // attempt to read a char
    while (cin.fail() == false)  // test for EOF
    {
        cout << ch;     // echo character
        ++count;
        cin.get(ch);    // attempt to read another char
    }
    cout << endl << count << " characters read\n";
	system("pause");
	return 0;
}


在这里插入图片描述

说明:

1)cin.get()可以用来锁住屏幕,直到可以读取为止。但在这里不行,因为检测到EOF的时候,会关闭对输入的进一步读取

2)~Z指的是Ctrl+Z,我们用Ctrl+Z和回车键来模拟EOF条件

3)小小的补充:
在这里插入图片描述

1.EOF结束输入

在这里插入图片描述

2.常见的字符输入做法

1)每次读取一个字符,直到遇到EOF的输入循环的基本设计如下:

在这里插入图片描述

<=>
在这里插入图片描述

说明:
在这里插入图片描述

进一步,可以将1)改为2)的while式子:

2)
在这里插入图片描述

说明:
这比 !cin.fail()或者!cin.eof()更加通用 ,因为他可以检测如磁盘故障等失败原因

进一步,可以将2)精简为下面3)的式子

3)
在这里插入图片描述

说明:

1)cin.get(char)只被调用一次
在这里插入图片描述

2)写的话,如果要简化的去写,只有上面的一种方法
在这里插入图片描述

7.cin.get()的另一个版本:现在写代码最常用的了

1)ch=cin.get();
在这里插入图片描述

2)cout.put(ch)
在这里插入图片描述

3)为了成功地使用cin.get(),需要知道其如何处理EOF条件。当函数到达EOF时,将没有可返回的字符,而是用一个符号常量EOF表示的特殊值,被定义为 -1

eg:

在这里插入图片描述

说明:
在这里插入图片描述

4)对于判断EOF而言:
在这里插入图片描述

对于显示char而言:
在这里插入图片描述
在这里插入图片描述

eg:

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

#include <ctime> // describes clock() function, clock_t type
int main(void)
{
    using namespace std;
    int ch;                         // should be int, not char
    int count = 0;

    while ((ch = cin.get()) != EOF) // test for end-of-file
    {
        cout.put(char(ch));
        ++count;
    }
    cout << endl << count << " characters read\n";
	system("pause");
	return 0;
}


在这里插入图片描述

说明:

1)
在这里插入图片描述

2)如果上述的括号没写对
在这里插入图片描述

3)在这里插入图片描述
在这里插入图片描述

4)cin.get()与cin.get(char)的对比
在这里插入图片描述

三、循环嵌套和二维数组:for的再使用

eg:假设要存储5个城市在4年间的最高温度,可以这样申明数组
在这里插入图片描述

如何去认识和使用这样的数组呢?
1)由数组组成的数组
在这里插入图片描述

2)使用下标访问数组用的多
在这里插入图片描述

如果要打印数组所有的内容,那么可用一个for循环来改变行,用另一个嵌套的for循环来改变列,所以,最终的代码可以写成:

在这里插入图片描述

1.初始化二维数组

1)一维数组是用逗号分割的,用花括号括起来的值列表
在这里插入图片描述

2)对于二维数组而言,由于每个元素本身就是一个数组,因此,同样可由一系列逗号分割的一维数组初始化组成:
同样也得用花括号括起来
在这里插入图片描述

说明:可将数组maxtemps包含4行,每行包含5个数字

2.使用二维数组

eg:
该程序的意思是:在输出的时候,将列循环(城市索引)放在外面,将行循环(年份索引)放在内面。

// choices.cpp -- array variations
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <vector>   // STL C++98
#include <array>    // C++0x
#include <string>

#include <ctime> // describes clock() function, clock_t type
#include <iostream>
const int Cities = 5;
const int Years = 4;
int main()
{
    using namespace std;
    const char * cities[Cities] =   // array of pointers
    {                               // to 5 strings
        "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;
    }
	system("pause");
	return 0;
}


在这里插入图片描述

说明:
1)C++中一个常用做法:将一个指针数组初始化为一组字符串常量
在这里插入图片描述

对比的话,eg1:
可以使用char数组的数组,而不是字符串指针数组
在这里插入图片描述
说明:
a)使用char数组的数组时,将5个字符串分别复制到5个包含25个元素的char数组中。
b)从存储的角度讲,使用指针数组更为经济,然而缺点是:如果要修改其中的任何一个字符串,则二维数组是更好的选择。
相同点是:这两种方法使用相同的初始化列表,显示字符串的for循环代码页相同。

对比的话,eg2:
使用string对象数组
在这里插入图片描述

说明:
a)如希望字符串是可修改的,则应该省略const
b)string对象数组的初始化列表和显示字符串的for循环代码与前两者方法一致
c)在希望是可修改的情况下,string类自动调整大小的特性使得使用二维数组更为方便

七、总结咯——依然总结的非常好

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u011436427/article/details/83623957