C语言中11次for循环使用时,有哪些注意事项需要特别注意?
- 内容介绍
- 文章标签
- 相关推荐
本文共计2274个文字,预计阅读时间需要10分钟。
C++11 for循环介绍一节已详细介绍了C++11标准中for循环的基本用法。在此基础上,本节将介绍一些for循环的使用注意事项,帮助读者更准确、高效地使用基于范围的for循环。
1. 确保迭代器类型正确:在使用基于范围的for循环时,迭代器类型必须与容器类型兼容。例如,对于vector,应使用iterator类型;对于set,应使用const_iterator类型。
2. 注意迭代器失效:在修改容器大小(如添加、删除元素)后,原有的迭代器可能会失效。此时,需要重新获取迭代器或使用新的迭代器。
3. 避免循环中的错误操作:在循环体内,避免进行可能导致迭代器失效的操作,如添加或删除容器中的元素。
4. 优化性能:对于大数据量的迭代,尽量使用基于范围的for循环,因为它通常比传统for循环更简洁、易读,且性能更优。
5. 适应不同场景:根据具体需求,选择合适的for循环形式。例如,当需要访问元素的前一个或后一个元素时,可以使用传统for循环。
6. 避免在循环体内进行复杂的操作:在循环体内进行复杂的操作可能会降低程序性能。尽量将复杂操作移至循环外。
7. 使用循环变量:在循环中,可以使用循环变量进行一些操作,但应尽量避免改变循环变量的值,以免影响循环逻辑。
8. 注意边界条件:在循环中,确保处理了边界条件,避免出现越界等错误。
9. 代码可读性:保持代码简洁、易读,适当使用注释,提高代码可维护性。
通过以上注意事项,读者可以更高效、准确地使用基于范围的for循环。
《C++11 for循环》一节已经详细介绍了 C++11 标准中 for 循环的基本用法。在此基础上,本节将介绍一些 for 循环的使用注意事项,帮助读者更准确高效地使用基于范围的 for 循环。1) 首先需要明确的一点是,当使用 for 循环遍历某个序列时,无论该序列是普通数组、容器还是用
{ }大括号包裹的初始化列表,遍历序列的变量都表示的是当前序列中的各个元素。举个例子:
#include <iostream> #include <vector> using namespace std; int main() { //for循环遍历初始化列表 for (int ch : {1,2,3,4,5}) { cout << ch; } cout << endl; //for循环遍历普通数组 char arc[] = "c.biancheng.net/cplus/11/"; for (char ch : arc) { cout << ch; } cout << endl; //for循环遍历 vector 容器 vector<char>myvector(arc, arc + 23); for (auto ch : myvector) { cout << ch; } return 0; } 程序执行结果为:
12345
c.biancheng.net/cplus/11/
c.biancheng.net/
为了加深读者对遍历容器的理解,下面程序以 map 容器为例,再举一个例子:
#include <iostream> #include <map> #include <string> using namespace std; int main() { map<string, string>mymap{ {"C++11","c.biancheng.net/cplus/11/"}, {"Python","c.biancheng.net/python/"}, {"Java","c.biancheng.net/java/"} }; for (pair<string,string> ch : mymap) { cout << ch.first << " " << ch.second << endl; } return 0; } 程序执行结果为:
C++11 c.biancheng.net/cplus/11/
Java c.biancheng.net/java/
Python c.biancheng.net/python/
值得初学者注意的一点是,基于范围的 for 循环也可以直接遍历某个字符串,比如:
for (char ch : "c.biancheng.net/cplus/11/") {
cout << ch;
}
前面提到,普通数组可以作为被遍历的序列。拿此程序中的字符串来说,其数据类型为const char[33],即在编译器看来字符串就是一个普通数组,因此完全可以直接作为被遍历的序列。
当然,基于范围的 for 循环也可以遍历 string 类型的字符串,这种情况下冒号前定义 char 类型的变量即可。
2) 总的来说,基于范围的 for 循环可以遍历普通数组、string字符串、容器以及初始化列表。除此之外,for 循环冒号后还可以放置返回 string 字符串以及容器对象的函数,比如:
#include <iostream> #include <vector> #include <string> using namespace std; string str = "c.biancheng.net/cplus/11/"; vector<int> myvector = { 1,2,3,4,5 }; string retStr() { return str; } vector<int> retVector() { return myvector; } int main() { //遍历函数返回的 string 字符串 for (char ch : retStr()) { cout << ch; } cout << endl; //遍历函数返回的 vector 容器 for (int num : retVector()) { cout << num << " "; } return 0; } 程序执行结果为:
c.biancheng.net/cplus/11/
1 2 3 4 5
注意,基于范围的 for 循环不支持遍历函数返回的以指针形式表示的数组,比如:
//错误示例
#include <iostream>
using namespace std;
char str[] = "c.biancheng.net/cplus/11/";
char* retStr() {
return str;
}
int main() {
for (char ch : retStr()) //直接报错
{
cout << ch;
}
return 0;
}
原因很简单,此格式的 for 循环只能遍历有明确范围的一组数据,上面程序中 retStr() 函数返回的是指针变量,遍历范围并未明确指明,所以编译失败。
3) 值得一提的是,当基于范围的 for 循环遍历的是某函数返回的 string 对象或者容器时,整个遍历过程中,函数只会执行一次。
举个例子:
#include <iostream> #include <string> using namespace std; string str= "c.biancheng.net/cplus/11/"; string retStr() { cout << "retStr:" << endl; return str; } int main() { //遍历函数返回的 string 字符串 for (char ch : retStr()) { cout << ch; } return 0; } 程序执行结果为:
retStr:
c.biancheng.net/cplus/11/
4) 系统学过 STL 标准库的读者应该知道,基于关联式容器(包括哈希容器)底层存储机制的限制:
- 不允许修改 map、unordered_map、multimap 以及 unordered_multimap 容器存储的键的值;
- 不允许修改 set、unordered_set、multiset 以及 unordered_multiset 容器中存储的元素的值。
因此,当使用基于范围的 for 循环遍历此类型容器时,切勿修改容器中不允许被修改的数据部分,否则会导致程序的执行出现各种 Bug。关于以上各个容器的具体用法,读者可猛击《C++ STL教程》进行系统学习。
另外,基于范围的 for 循环完成对容器的遍历,其底层也是借助容器的迭代器实现的。举个例子:
#include <iostream> #include <vector> int main(void) { std::vector<int>arr = { 1, 2, 3, 4, 5 }; for (auto val : arr) { std::cout << val << std::endl; arr.push_back(10); //向容器中添加元素 } return 0; } 程序执行结果可能为(输出结果不唯一):
1
-572662307
-572662307
4
5
因此,在使用基于范围的 for 循环遍历容器时,应避免在循环体中修改容器存储元素的个数。如果读者想要彻底搞清楚程序执行失败的原因,读了解 vector 容器的底层存储机制,可阅读《C++ vector容器底层实现机制》一文。
本文共计2274个文字,预计阅读时间需要10分钟。
C++11 for循环介绍一节已详细介绍了C++11标准中for循环的基本用法。在此基础上,本节将介绍一些for循环的使用注意事项,帮助读者更准确、高效地使用基于范围的for循环。
1. 确保迭代器类型正确:在使用基于范围的for循环时,迭代器类型必须与容器类型兼容。例如,对于vector,应使用iterator类型;对于set,应使用const_iterator类型。
2. 注意迭代器失效:在修改容器大小(如添加、删除元素)后,原有的迭代器可能会失效。此时,需要重新获取迭代器或使用新的迭代器。
3. 避免循环中的错误操作:在循环体内,避免进行可能导致迭代器失效的操作,如添加或删除容器中的元素。
4. 优化性能:对于大数据量的迭代,尽量使用基于范围的for循环,因为它通常比传统for循环更简洁、易读,且性能更优。
5. 适应不同场景:根据具体需求,选择合适的for循环形式。例如,当需要访问元素的前一个或后一个元素时,可以使用传统for循环。
6. 避免在循环体内进行复杂的操作:在循环体内进行复杂的操作可能会降低程序性能。尽量将复杂操作移至循环外。
7. 使用循环变量:在循环中,可以使用循环变量进行一些操作,但应尽量避免改变循环变量的值,以免影响循环逻辑。
8. 注意边界条件:在循环中,确保处理了边界条件,避免出现越界等错误。
9. 代码可读性:保持代码简洁、易读,适当使用注释,提高代码可维护性。
通过以上注意事项,读者可以更高效、准确地使用基于范围的for循环。
《C++11 for循环》一节已经详细介绍了 C++11 标准中 for 循环的基本用法。在此基础上,本节将介绍一些 for 循环的使用注意事项,帮助读者更准确高效地使用基于范围的 for 循环。1) 首先需要明确的一点是,当使用 for 循环遍历某个序列时,无论该序列是普通数组、容器还是用
{ }大括号包裹的初始化列表,遍历序列的变量都表示的是当前序列中的各个元素。举个例子:
#include <iostream> #include <vector> using namespace std; int main() { //for循环遍历初始化列表 for (int ch : {1,2,3,4,5}) { cout << ch; } cout << endl; //for循环遍历普通数组 char arc[] = "c.biancheng.net/cplus/11/"; for (char ch : arc) { cout << ch; } cout << endl; //for循环遍历 vector 容器 vector<char>myvector(arc, arc + 23); for (auto ch : myvector) { cout << ch; } return 0; } 程序执行结果为:
12345
c.biancheng.net/cplus/11/
c.biancheng.net/
为了加深读者对遍历容器的理解,下面程序以 map 容器为例,再举一个例子:
#include <iostream> #include <map> #include <string> using namespace std; int main() { map<string, string>mymap{ {"C++11","c.biancheng.net/cplus/11/"}, {"Python","c.biancheng.net/python/"}, {"Java","c.biancheng.net/java/"} }; for (pair<string,string> ch : mymap) { cout << ch.first << " " << ch.second << endl; } return 0; } 程序执行结果为:
C++11 c.biancheng.net/cplus/11/
Java c.biancheng.net/java/
Python c.biancheng.net/python/
值得初学者注意的一点是,基于范围的 for 循环也可以直接遍历某个字符串,比如:
for (char ch : "c.biancheng.net/cplus/11/") {
cout << ch;
}
前面提到,普通数组可以作为被遍历的序列。拿此程序中的字符串来说,其数据类型为const char[33],即在编译器看来字符串就是一个普通数组,因此完全可以直接作为被遍历的序列。
当然,基于范围的 for 循环也可以遍历 string 类型的字符串,这种情况下冒号前定义 char 类型的变量即可。
2) 总的来说,基于范围的 for 循环可以遍历普通数组、string字符串、容器以及初始化列表。除此之外,for 循环冒号后还可以放置返回 string 字符串以及容器对象的函数,比如:
#include <iostream> #include <vector> #include <string> using namespace std; string str = "c.biancheng.net/cplus/11/"; vector<int> myvector = { 1,2,3,4,5 }; string retStr() { return str; } vector<int> retVector() { return myvector; } int main() { //遍历函数返回的 string 字符串 for (char ch : retStr()) { cout << ch; } cout << endl; //遍历函数返回的 vector 容器 for (int num : retVector()) { cout << num << " "; } return 0; } 程序执行结果为:
c.biancheng.net/cplus/11/
1 2 3 4 5
注意,基于范围的 for 循环不支持遍历函数返回的以指针形式表示的数组,比如:
//错误示例
#include <iostream>
using namespace std;
char str[] = "c.biancheng.net/cplus/11/";
char* retStr() {
return str;
}
int main() {
for (char ch : retStr()) //直接报错
{
cout << ch;
}
return 0;
}
原因很简单,此格式的 for 循环只能遍历有明确范围的一组数据,上面程序中 retStr() 函数返回的是指针变量,遍历范围并未明确指明,所以编译失败。
3) 值得一提的是,当基于范围的 for 循环遍历的是某函数返回的 string 对象或者容器时,整个遍历过程中,函数只会执行一次。
举个例子:
#include <iostream> #include <string> using namespace std; string str= "c.biancheng.net/cplus/11/"; string retStr() { cout << "retStr:" << endl; return str; } int main() { //遍历函数返回的 string 字符串 for (char ch : retStr()) { cout << ch; } return 0; } 程序执行结果为:
retStr:
c.biancheng.net/cplus/11/
4) 系统学过 STL 标准库的读者应该知道,基于关联式容器(包括哈希容器)底层存储机制的限制:
- 不允许修改 map、unordered_map、multimap 以及 unordered_multimap 容器存储的键的值;
- 不允许修改 set、unordered_set、multiset 以及 unordered_multiset 容器中存储的元素的值。
因此,当使用基于范围的 for 循环遍历此类型容器时,切勿修改容器中不允许被修改的数据部分,否则会导致程序的执行出现各种 Bug。关于以上各个容器的具体用法,读者可猛击《C++ STL教程》进行系统学习。
另外,基于范围的 for 循环完成对容器的遍历,其底层也是借助容器的迭代器实现的。举个例子:
#include <iostream> #include <vector> int main(void) { std::vector<int>arr = { 1, 2, 3, 4, 5 }; for (auto val : arr) { std::cout << val << std::endl; arr.push_back(10); //向容器中添加元素 } return 0; } 程序执行结果可能为(输出结果不唯一):
1
-572662307
-572662307
4
5
因此,在使用基于范围的 for 循环遍历容器时,应避免在循环体中修改容器存储元素的个数。如果读者想要彻底搞清楚程序执行失败的原因,读了解 vector 容器的底层存储机制,可阅读《C++ vector容器底层实现机制》一文。

