约瑟夫环问题 Game函数中play指针为什么会有读取访问权限冲突的问题



```c++
#include<iostream> 
#include<assert.h>
#include<string> 
#include<stdio.h>  
#include<math.h> 
#include<random>
#include <fstream> //完成文件读写
using namespace std;
struct Players { //自定义结构体变量 
    long int ID;              // 规定玩家ID为八位数字
    int points;
};
class player {
public:
    long int ID;              // 规定玩家ID为八位数字
    string name;
    string telenumber;
    string email;
    string IDcard;            //规定玩家IDcard为18位数字
    long int password;        //规定玩家密码为八位
    int points;
    string status;            //身份分为两级:菜鸟,王者
    void privilege();         //特权
    player* next;
    player* play_front;       //游戏指针
    player* play_next;
    player() { //cl 
        ID = 0;
        name = '\0';
        telenumber = '\0';
        IDcard = '\0';
        password = 0;
        points = 0;
        status = '\0';
        next = (player*)malloc(sizeof(player));
        play_next = (player*)malloc(sizeof(player));
        play_front = (player*)malloc(sizeof(player));
        play_front = NULL;
        play_next = NULL;
        next = NULL;
    }
    ~player() { //cl
        delete next;
        delete play_front;
        delete play_next;
    }
};

class Josephus {
protected:
    player* head;  //头指针
    player* rear;//尾指针
    int length;  //链表长度
public:
    player* Gethead() { return head; }
    

player* Getrear() { return rear; }


```c++



player* Loacting(long int id) {
    player* p = head->next;
    int i = 1;
    while (i++ <= length && p->ID != id) {
        p = p->next;
    }
    if (p->ID == id) return p;
    else return NULL;
}
bool enroll(player& Player) {//开户,尾插//debug——zxr 
    printf("请输入您的游戏8位数ID");
    cin >> Player.ID;
    while (Player.ID >= 10000000 && Player.ID <= 99999999) {
        break;
        cout << "该ID无效,请重新输入您的游戏8位数ID(ID应由8个数字组成)";
        cin >> Player.ID;
    }
    cout << "您的游戏ID创建成功" << endl;

    printf("请输入您的姓名");
    int name1 = 1;//一个标志,判断是否合法 
    cin >> Player.name;
    while (name1 != 0) {
        break;
        int name2 = 0;
        for (int k = 0; k < Player.name.length(); k++) {
            if (Player.name[k] < 'A' || (Player.name[k] > 'Z' && Player.name[k] < 'a') || Player.name>"z")
                name2++;
        }
        if (name2 == 0)name1 = 0;
        else cout << "该姓名无效,请重新输入您的姓名(姓名应由大小字母组成)";
    }
    cout << "您的姓名输入成功" << endl;

    printf("请输入您的18位身份证号码");
    int idcard1 = 1;
    cin >> Player.IDcard;
    while (idcard1 != 0) {
        if (Player.IDcard.length() == 18) {
            int idcard2 = 0;
            for (int k = 0; k < 16; k++) {
                if (Player.IDcard[k] > '9' || Player.IDcard[k] < '0')idcard2++;
            }
            if ((Player.IDcard[17] > '9' && Player.IDcard[17] < 'X') || Player.IDcard[17] < '0' || Player.IDcard[17]>'X')idcard2++;
            if (idcard2 == 0)idcard1 = 0;
        }
        if (idcard1 != 0)
        {
            cout << "该身份证号无效,请重新输入您的身份证号";
            cin >> Player.IDcard;
        }
    }
    cout << "您的身份证号输入成功" << endl;

    printf("请输入您的电话号码");
    cin >> Player.telenumber;
    int tele1 = 1;
    while (tele1 != 0) {
        int tele2 = 0;
        if (Player.telenumber.length() == 11) {
            if (Player.telenumber[0] != '1')
            {
                tele2++;
            }
            //if (Player.telenumber[1] <= '2' || (Player.telenumber[1] >= '6' || Player.telenumber[1] <= '7') || Player.telenumber[1] > '9')tele2++;
            //for (int k = 1; k < 11; k++) {
                //if (Player.telenumber[k] < '0' || Player.telenumber[k]> '9' )tele2++;
            //}
            if (tele2 == 0)tele1 = 0;
        }
        if (tele1 != 0)
        {
            cout << "该电话号码无效,请重新输入您的电话号码";
            cin >> Player.telenumber;
        }
    }
    cout << "您的电话号码输入成功" << endl;

    printf("请输入您的邮箱");
    cin >> Player.email;
    cout << "您的邮箱输入成功" << endl;

    printf("已为您自动生成8位密码,请牢记!");
    long int min = 0, max = 99999999;
    random_device seed;//硬件生成随机数种子
    ranlux48 engine(seed());//利用种子生成随机数引擎
    uniform_int_distribution<> distrib(min, max);//设置随机数范围,并为均匀分布
    Player.password = distrib(engine);
    if (Player.password % 2 == 0) {   //偶数自动设为负值
        Player.password = -Player.password;
    }
    cout << "您的密码是:" << Player.password;
    rear->next = &Player;
    rear->play_next = &Player;
    Player.play_front = rear;
    rear = rear->next;
    head->play_front = &Player;
    Player.play_next = head;
    Player.next = head;
    length++;
    assert(head->next != NULL);
    assert(rear->next != NULL);
    assert(head->play_front != NULL);
    assert(head->play_next != NULL);
    assert(rear->play_front != NULL);
    assert(rear->play_next != NULL);
    assert(Player.next != NULL);
    assert(Player.play_next != NULL);
    if (Player.next == NULL || Player.play_next == NULL || head->next == NULL || rear->next == NULL || head->play_front == NULL || head->play_next == NULL || rear->play_front == NULL || rear->play_next == NULL)
    {
        cout << "cuowu" << endl;
        exit(1);
    }
    return true;
};
bool Dead(player* Player) {
    //(Player->play_front)->play_next = Player->play_next;
    //(Player->play_next)->play_front = Player->play_front;
    //Player->play_front = NULL;
    //Player->play_next = NULL;
    return true;
};

void Game(player* p) {         //正为顺,负为逆
    int j = 1; int m = 4; int flag = 1;
    player* play = head->next;
    if (Difficulty()) {
        while (play->play_front != NULL && play->play_next != NULL) {
            if (j == m) {
                Dead(play);
                j = 1;
                m = play->password;
                if (m < 0) {
                    flag = 0;
                }
            }
            else {
                if (flag == 1) {
                    play = play->play_next;
                    ++j;
                }
                else {
                    play = play->play_front;
                    ++j;
                }
            }
        }
    }
    else {
        while (play->play_front != NULL && play->play_next != NULL) {
            if (j == 4) {
                Dead(play);
                j = 1;
            }
            else {
                play = play->play_next;
                ++j;
            }
        }
    }
    if (play == p) {
        p->points += 10;
    }
    play = head->next;
    while (play->next != NULL) {
        play->play_next = play->next;
        (play->next)->play_front = play;
        ++play;
    }
};
player* login(long int n)//登录,定位//debug——zxr 
{
    player* P = new player;
    P = Josephus::Loacting(n);
    cout << "请输入密码: ";
    long int se;
    cin >> se;
    if (P != NULL && se == P->password) {
        cout << length;
        return P;
    }
    else {
        cout << "密码错误,请再次输入密码(您还有两次机会): ";
        cin >> se;
        if (P != NULL && se == P->password) {
            return P;
        }
        else {
            cout << "密码错误,请再次输入密码(您还有一次机会): ";
            cin >> se;
            if (P != NULL && se == P->password) {
                return P;
            }
            else {
                return NULL;
            }
        }
    }
};
bool Delete(player* player)//销户 debugcl?
{
    if (head == player) {
        head = player->next;
        (player->play_next)->play_front = NULL;
        return true;
    }
    else {
        (player->play_front)->next = (player->play_next);
        (player->play_front)->play_next = (player->play_next);
        (player->play_next)->play_front = (player->play_front);
        return true;
    }
    delete player;
};

bool Correct(player& Player) {
    int n;
    cout << "您想修改的是(请选择一个数字)" << endl;
    cout << "1.电话号码" << endl;
    cout << "2.电子邮箱" << endl;
    cout << "请输入一个数字";
    cin >> n;
    if (n != 1 && n != 2)cout << "该选择无效,请重新输入一个数字(数字应为1或2)";
    else if (n == 1) {
        cout << "请输入您的新电话号码";
        cin >> Player.telenumber;
        int tele1 = 1;
        while (tele1 != 0) {
            int tele2 = 0;
            if (Player.telenumber.length() == 11) {
                if (Player.telenumber[0] != 1)tele2++;
                if (Player.telenumber[1] <= '2' || (Player.telenumber[1] >= '6' || Player.telenumber[1] <= '7') || Player.telenumber[1] > '9')tele2++;
                for (int k = 2; k < 11; k++) {
                    if (Player.telenumber[k] < '0' || Player.telenumber[k]>'9')tele2++;
                }
                if (tele2 == 0)tele1 = 0;
            }
            if (tele1 != 0)cout << "该电话号码无效,请重新输入您的电话号码";
        }
        cout << "您的电话号码输入成功" << endl;
    }
    else if (n == 2) {
        cout << "请输入您的新电子邮箱";
        cin >> Player.email;
        cout << "您的邮箱输入成功" << endl;
    }
    return true;
};//修改,定位!!!!//zxr 

bool Browse(player& Player) {//浏览,排序(直接内置) cl
    cout << "当前账户数量:" << length << endl;
    cout << "您的账户是" << Player.ID << endl;
    cout << "您的积分是" << Player.points << endl;
    Players a[100];
    Players m;
    int i = 0;
    player* p = new player;
    p = head->next;
    for (i = 1; i <= length; i++)
    {
        a[i - 1].ID = p->ID;
        a[i - 1].points = p->points;
    }
    int j = 0;
    for (j = 1; j <= length - 1; j++)
    {
        for (i = 0; i < length - j; j++)
        {
            if (a[i].points < a[i + 1].points)
            {
                m = a[i];
                a[i] = a[i + 1];
                a[i + 1] = m;
            }
        }
    }
    cout << "排行榜" << endl;
    for (i = 0; i < length; i++)
    {
        cout << "第" << i + 1 << "名" << " " << a[i].ID << "    POINTS:" << a[i].points << endl;
    }
    return true;
};

bool Searching() {
    long int n;
    cout << "您想查找的ID是" << endl;
    cin >> n;
    player* P = Josephus::Loacting(n);
    cout << "该玩家的电话号码是" << P->telenumber << endl;
    cout << "该玩家的电子邮箱是" << P->email << endl;
    return true;
};//查找,定位//zxr 
bool Difficulty()
{
    return 0;
}
bool If_challenge() //挑战模式,只能在Game()中调用
{

}
bool status_upgrade()  //升级,定位,只能在Game()中调用
{

}

void Main_interface() {//主界面 cl
    cout << "                    *                       " << endl;
    cout << "              *           *                 " << endl;
    cout << "         *                      *           " << endl;
    cout << "    *                                 *     " << endl;
    cout << "*           约瑟夫环游戏模拟器             *" << endl;
    cout << "    *                                 *     " << endl;
    cout << "         *  开户(1)     登录(2)  *           " << endl;
    cout << "              *           *                 " << endl;
    cout << "                    *                       " << endl;
};

void Function_Select(int a) {//Function_Select函数将主函数的switch和交互封装起来 cl
    long int n; int b;
    int mode;
    player* Player = new player;
    switch (a) {
    case 1://开户
        enroll(*Player);
        cout << "请再次输入账号";
        cin >> n;
        login(n);

        cout << "您想要做什么:" << endl;
        cout << "1.查询 2.修改 3.销户 4.浏览 5.查找 6.游戏";
        cin >> mode;
        switch (mode) {
        case 1:Searching(); break;
        case 2:Correct(*Player); break;
        case 3:Delete(Player); break;
        case 4:Browse(*Player); break;
        case 5:Loacting(Player->ID); break;
        case 6:Game(Player); break;
        default:cout << "您输入的模式不存在,请再输一次";
        };
        break;

    case 2://登录
        cout << "请输入账号";
        cin >> n;
        Player = login(n);
        if (login(n) != 0) {
            cout << "您想要做什么:" << endl;
            cout << "1.查询 2.修改 3.销户 4.浏览 5.查找 6.游戏";
            cin >> mode;
            switch (mode) {
            case 1:Searching(); break;
            case 2:Correct(*Player); break;
            case 3:Delete(Player); break;
            case 4:Browse(*Player); break;
            case 5:Loacting(Player->ID); break;
            case 6:Game(Player); break;
            default:cout << "您输入的模式不存在,请再输一次";
            }
            break;
        }
        else {
            cout << "您输入的账户不存在,或密码错误" << endl;
        }
    }
};
void Mode_Select();   //Mode_Select函数将主函数的switch和交互封装起来

Josephus() {//构造 cl
    head = new player;
    rear = new player;
    head->next = rear;
    rear->next = head;
    head->play_front = (player*)malloc(sizeof(player));
    head->play_next = (player*)malloc(sizeof(player));
    rear->play_front = (player*)malloc(sizeof(player));
    rear->play_next = (player*)malloc(sizeof(player));
    (rear->play_front)->next = head;
    (head->play_front)->next = rear;
    (rear->play_next)->next = head;
    (head->play_next)->next = rear;
    assert(head->next != NULL);
    assert(rear->next != NULL);
    assert(head->play_front != NULL);
    assert(head->play_next != NULL);
    assert(rear->play_front != NULL);
    assert(rear->play_next != NULL);

    if (head->next == NULL || rear->next == NULL || head->play_front == NULL || head->play_next == NULL || rear->play_front==NULL || rear->play_next==NULL)
    {
        cout << "cuowu" << endl;
        exit(1);
    }
    length = 0;
    while (1) {
        Main_interface();
        int a;
        cin >> a;
        Function_Select(a);
    }
}
~Josephus() {//析构 cl
    player* q = head->next;
    int i = 1;
    while (i++ <= length)
    {
        head->next = q->next;
        delete q;
        q = head->next;
    }
    length = 0;
    delete head;
    delete rear;
};

};
int main() {
Josephus game;
return 0;
}


```

来自NewBing和LP的编写:

在Game函数中,出现读取访问权限冲突的问题是因为play指针在函数开始时被定义为指向head->next,然后在后面的代码中进行了指针的移动,导致play指针指向了其他节点。而在函数末尾的返回结果需要使用play指针,但此时play指针已经不再指向head->next,因此出现了读取访问权限冲突的问题。

为了解决这个问题,可以在函数开头定义一个新的指针变量,例如player* current = head->next;,然后在后面的代码中使用current指针进行遍历和操作。这样在函数末尾就可以使用current指针返回正确的结果,而不会出现读取访问权限冲突的问题。

在Game函数中,可以进行如下修改:

void Game(player* p) {
    int j = 1;
    int m = 4;
    int flag = 1;
    player* current = head->next;  // 使用current指针进行遍历和操作

    if (Difficulty()) {
        while (current->play_front != NULL && current->play_next != NULL) {
            if (j == m) {
                Dead(current);
                j = 1;
                m = current->password;
                if (m < 0) {
                    flag = 0;
                }
            } else {
                if (flag == 1) {
                    current = current->play_next;
                    ++j;
                } else {
                    current = current->play_front;
                    ++j;
                }
            }
        }
    } else {
        while (current->play_front != NULL && current->play_next != NULL) {
            if (j == 4) {
                Dead(current);
                j = 1;
            } else {
                current = current->play_next;
                ++j;
            }
        }
    }
    
    if (current == p) {
        p->points += 10;
    }
    
    // 重新遍历链表,将指针连接起来
    current = head->next;
    while (current->next != NULL) {
        current->play_next = current->next;
        (current->next)->play_front = current;
        current = current->next;
    }
}

这样,在Game函数中使用了current指针进行链表的遍历和操作,而保留了p指针作为参数用于比较得分。通过重新遍历链表,将指针正确地连接起来,避免了读取访问权限冲突的问题。

在你的代码中,Game函数中的循环使用了一个名为play的指针,而该指针在每次循环迭代时被赋予一个新的值。问题出在你在循环内部对play指针进行了读取和写入操作,而这样的操作可能会导致读取访问权限冲突。
解决这个问题的方法是将play指针声明为每次循环迭代时的局部变量,而不是在循环之外声明。这样可以确保每次迭代都有一个新的指针,避免读取访问权限冲突。下面是修改后的Game函数代码:

void Game::play()
{
    Player* current = head;  // 指向头节点的指针
    for (int i = 0; i < num_of_players; i++)
    {
        cout << "Player " << i + 1 << "'s information:" << endl;
        current->privilege();  // 调用当前玩家的特权函数
        current = current->next;  // 指向下一个玩家
    }
}