C++二维vector实现好友关系类时出现内存访问错误
问题分析与修复:好友关系类的内存访问错误
问题描述
我尝试用C++编写一个表示人群好友关系的类,每个人对应二维vector的一行,行内元素代表该人的好友(好友关系为双向)。编写的代码如下:
class Friends { public: Friends(int n); // Creates a set of n people, no one knows each other. bool knows(int a, int b); // returns true if the 2 people know each other void getToKnow(int a, int b); // Person a & b meet. void mutualFriends(int a, int b); // cout's the mutual friends of person a & b void meeting(int a); //all friends of person a also become friends int max(); //return the person with the highest number of friends private: vector<vector<int>> friends; }; Friends::Friends(int n) { vector<vector<int>> friends; } bool Friends::knows(int a, int b) { for(int i=0; i<friends[a].size(); i++) { if (friends[a][i]==b) { return true; } } return false; } void Friends::getToKnow(int a, int b) { friends[a].push_back(b); friends[b].push_back(a); } void Friends::mutualFriends(int a, int b) { for (int i=0; i<friends[a].size(); i++) { for (int j=0; j<friends[b].size(); j++) { if (friends[a][i]==friends[b][j]) cout << friends[a][i] <<", "; } } } void Friends::meeting(int a) { for (int i=0; i<friends[a].size(); i++) { for(int j=0; j<friends[a].size();j++) { if(i!=j && i!=a && j!=a) { getToKnow(i,j); } } } } int Friends::max() { int maks = 0; for (int i=0; i<friends[i].size(); i++) { if (friends[i].size()<friends[i+1].size()) maks = i; } return maks; } int main() { Friends f1 (4); f1.getToKnow(1,3); }
但每次尝试向vector中添加元素(例如调用getToKnow函数)时,程序触发错误:Thread 1: EXC_BAD_ACCESS (code=1, address=0x20),错误指向friends[a].push_back(b);和friends[b].push_back(a);两行。我不清楚问题所在,也不确定是否正确使用了二维vector,希望得到帮助。
核心错误原因
构造函数中重新定义了局部的vector<vector<int>> friends;,这会遮蔽类的成员变量friends,导致成员变量始终是空的二维vector。当调用getToKnow访问friends[a]时,a(比如示例中的1)超出了空vector的索引范围,直接触发内存访问错误。
其他次要问题
- 缺乏索引合法性检查:所有涉及人员编号的函数都没有验证参数是否在0到
n-1范围内,容易触发越界。 - 重复添加好友:
getToKnow未检查两人是否已成为好友,会导致同一好友被多次添加到列表中。 meeting函数逻辑错误:循环变量i、j是friends[a]的索引,而非人员编号,应该使用friends[a][i]和friends[a][j]获取好友的实际编号。max函数逻辑错误:循环条件错误,应该遍历所有人员(0到friends.size()-1),而非friends[i].size();同时比较逻辑会遗漏最后一个元素,还可能触发i+1越界。- 头文件缺失:代码使用了
vector和cout,但未包含<vector>和<iostream>头文件,编译会报错。
修正后的完整代码
#include <vector> #include <iostream> #include <algorithm> using namespace std; class Friends { public: Friends(int n); bool knows(int a, int b); void getToKnow(int a, int b); void mutualFriends(int a, int b); void meeting(int a); int max(); private: vector<vector<int>> friends; bool isValidPerson(int idx); }; Friends::Friends(int n) { friends.resize(n); } bool Friends::isValidPerson(int idx) { return idx >= 0 && idx < friends.size(); } bool Friends::knows(int a, int b) { if (!isValidPerson(a) || !isValidPerson(b)) return false; return find(friends[a].begin(), friends[a].end(), b) != friends[a].end(); } void Friends::getToKnow(int a, int b) { if (!isValidPerson(a) || !isValidPerson(b) || a == b) return; if (!knows(a, b)) { friends[a].push_back(b); friends[b].push_back(a); } } void Friends::mutualFriends(int a, int b) { if (!isValidPerson(a) || !isValidPerson(b)) return; for (int friendA : friends[a]) { if (knows(b, friendA)) { cout << friendA << ", "; } } cout << endl; } void Friends::meeting(int a) { if (!isValidPerson(a)) return; const vector<int>& aFriends = friends[a]; for (size_t i = 0; i < aFriends.size(); ++i) { for (size_t j = i + 1; j < aFriends.size(); ++j) { getToKnow(aFriends[i], aFriends[j]); } } } int Friends::max() { if (friends.empty()) return -1; int maxIdx = 0; size_t maxCount = friends[0].size(); for (size_t i = 1; i < friends.size(); ++i) { if (friends[i].size() > maxCount) { maxCount = friends[i].size(); maxIdx = i; } } return maxIdx; } int main() { Friends f1(4); f1.getToKnow(1, 3); f1.getToKnow(1, 0); f1.getToKnow(3, 0); cout << "Mutual friends of 1 and 3: "; f1.mutualFriends(1, 3); f1.meeting(1); cout << "Person with most friends: " << f1.max() << endl; }
关键修复说明
- 初始化成员变量:构造函数改用
friends.resize(n)创建n个空的子vector,对应n个人的好友列表。 - 合法性检查:添加
isValidPerson辅助函数,统一验证人员编号的有效性,避免越界访问。 - 避免重复添加:
getToKnow先调用knows检查关系,防止同一好友被多次添加。 - 修正
meeting逻辑:使用好友的实际编号而非索引进行操作,同时优化为只遍历i<j的配对,避免重复调用getToKnow。 - 修正
max函数:遍历所有人员,正确比较好友数量,返回好友最多的人员编号。 - 补充头文件:添加
<vector>、<iostream>和<algorithm>头文件,确保编译通过。
内容的提问来源于stack exchange,提问作者jchraplak
相关产品推荐
相关产品推荐

