1

我提交的代码是这门课第三周工作的结果。我对事情的处理非常好,(或者我是这么认为的),但是本周的重点是指针,我不知道为什么我不断收到这个错误。我不断收到调试断言失败!错误以及一般的“缓冲区太小”解释。

我的错误信息

这是我使用 VS 2012 RC 版本 11.0.505221.1 在 Win8 操作系统上编译的完整代码。与我在 Linux 中编译的唯一区别是我在这段代码中使用了 strcpy_s(),因为出于某种原因,MS 不喜欢 strcpy()。

#include "stdafx.h"
#include <iostream>
#include <string>
#include <iomanip>
#include <limits>

using namespace std;

class HotelRoom
{
    char roomNumber[4];
    char guest[81];
    int roomCapacity, currentOccupants;
    double roomRate;

public:
    HotelRoom(char[], char[], int, double);
    ~HotelRoom();
    void DisplayRoom();
    void DisplayNumber();
    void DisplayName();
    int GetCapacity();
    int GetStatus();
    double GetRate();
    void ChangeStatus(int);
    void ChangeRate(double);
};

HotelRoom::~HotelRoom() {
cout << endl << endl;
cout << "Room #" << roomNumber << " no longer exists." << endl;
delete [] guest;
}

void HotelRoom::DisplayName() {
cout << guest;
}

void HotelRoom::DisplayNumber() {
cout << roomNumber;
}

int HotelRoom::GetCapacity() {
return roomCapacity;
}

int HotelRoom::GetStatus() {
return currentOccupants;
}

double HotelRoom::GetRate() {
return roomRate;
}

void HotelRoom::ChangeStatus(int occupants) {
if(occupants <= roomCapacity) {
    currentOccupants = occupants;
}
else {
    cout << endl << "There are too many people for this room. Setting occupancy to -1." << endl;
    currentOccupants = -1;
}
}

void HotelRoom::ChangeRate(double rate) {
roomRate = rate;
}

HotelRoom::HotelRoom(char room[], char guestName[], int capacity, double rate)
{
strcpy_s(roomNumber, room);     //Compiles fine with strcpy on Linux, but MS is making me use strcpy_s to compile
guestName = new char[strlen(guestName) + 1];
strcpy_s(guest, guestName);     //Same as above
roomCapacity     =  capacity;
currentOccupants = 0;
roomRate         = rate;
}

void HotelRoom::DisplayRoom()
{
cout << setprecision(2)
     << setiosflags(ios::fixed)
     << setiosflags(ios::showpoint);
cout << endl << "The following is pertinent data relating to the room:\n"
     << "Guest Name:        " << guest << endl
     << "Room Number:       " << roomNumber << endl
     << "Room Capacity:     " << GetCapacity() << endl
     << "Current Occupants: " << GetStatus() << endl
     << "Room Rate:         $" << GetRate() << endl;
}


int main()
{
int numOfGuests;
char roomNum[4]; 
char buffer[81];    //Buffer to store guest's name
int roomCap;
double roomRt;
bool badInput = true;
cout << endl << "Please enter the 3-digit room number: ";
do {        //loop to check user input
    badInput = false;   
    for(int x = 0; x < 3; x++)
    {
        cin >> roomNum[x];
        if(!isdigit(roomNum[x]))        //check all chars entered are digits
        {
            badInput = true;
        }
    }
    char x = cin.get();
    if(x != '\n')       //check that only 3 chars were entered
    {
        badInput = true;
    }
    if(badInput)
    {
        cout << endl << "You did not enter a valid room number. Please try again: ";
    }
} while(badInput);
for(;;)     //Infinite loop broken when correct input obtained
{
    cout << "Please enter the room capacity: ";
    if(cin >> roomCap) {
        break;
    } else {
        cout << "Please enter a valid integer" << endl;
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
}
for(;;)     //Infinite loop broken when correct input obtained
{
    cout << "Please enter the nightly room rate: ";
    if(cin >> roomRt) {
        break;
    } else {
        cout << "Please enter a valid rate" << endl;
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
}
cin.get();      //Dump the trailing return character
cout << "Please enter guest name: ";
cin.getline(buffer, 81);
HotelRoom room1(roomNum, buffer, roomCap, roomRt);
for (;;) {      //Infinite loop broken when correct input obtained
cout << "Please enter the number of guests for room #";
room1.DisplayNumber();
cout << ": ";
    if (cin >> numOfGuests) {
        break;
    } else {
        cout << "Please enter a valid integer" << endl;
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
}
room1.ChangeStatus(numOfGuests);
room1.DisplayRoom();
cout << endl << "The following shows after the guests have checked out." << endl;
room1.ChangeStatus(0);
room1.DisplayRoom();
room1.ChangeRate(175.0);
for (;;) {      //Infinite loop broken when correct input obtained
cout << "Please enter the number of guests for room #";
room1.DisplayNumber();
cout << ": ";
    if (cin >> numOfGuests) {
        break;
    } else {
        cout << "Please enter a valid integer" << endl;
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
}
room1.ChangeStatus(numOfGuests);
room1.DisplayRoom();
return 0;
}

更新:

我添加了 cout 语句来查看程序中出现问题的位置,它肯定是在 HotelRoom 构造函数中的 strcpy() 语句中。这是构造函数,以下是我收到的输出

HotelRoom::HotelRoom(char room[], char guestName[], int capacity, double rate)
{
cout << endl << "Attempting 1st strcpy...";
strcpy_s(roomNumber, room);     //Compiles fine with strcpy on Linux, but MS is making me use strcpy_s to compile
cout << endl << "1st strcpy successful!";
guestName = new char[strlen(guestName) + 1];
cout << endl << "Attempting 2nd strcpy...";
strcpy_s(guest, guestName);     //Same as above
cout << endl << "2nd strcpy successful!";
roomCapacity     =  capacity;
currentOccupants = 0;
roomRate         = rate;
}

cout 输出

4

4 回答 4

1

我想你可能需要再看看这个:

guestName = new char[strlen(guestName) + 1];
cout << endl << "Attempting 2nd strcpy...";
strcpy_s(guest, guestName);     //Same as above

我很确定,因为guestName[]是一个参数,你的意图是不要在函数范围内永久丢失该指针,用一个新分配的非终止指针替换它,然后继续将未初始化的内存复制到你的成员变量。

也许你想要这个:

strcpy_s(guest, guestName);

此外,guest是类型的成员变量char[81]。除非您希望堆管理器再次抛出该讨厌的对话框,否则您可能希望避免在类析构函数中这样做:

delete [] guest;

这是删除非堆内存并且几乎保证使堆管理器呕吐。

于 2012-11-13T04:53:45.000 回答
0

如果您不使用strcpy_s,则需要在从指针复制到缓冲区之前进行边界检查。

此外,您不应该调用 delete on guest。Delete 用于释放您使用 new 分配的内存。

于 2012-11-13T04:27:24.853 回答
0

您已定义char buffer[81],但您正在尝试读取 81 个字符,但cin.getline(buffer, 81)不包括\0. 因此,您需要将较早的一项更改为char buffer[82]或将较晚的一项更改为cin.getline(buffer, 80)

如果你使用 C++ 为什么不使用string

于 2012-11-13T04:17:13.480 回答
0

MS 要求您使用 _s 函数的原因是为了保护您的代码免受缓冲区溢出的影响,就像您的代码当前显示的那样。检查此链接以获取更多信息。

您有一个 81 个字符的字符串。您新建一个大小为 + 1 的新字符串(您将丢失数据),现在是 82 个字符。当您尝试将缓冲区复制到长度为 81 个字符的客户机中时,您会得到一个断言。

考虑使用 std::string 并停止分配/释放字符串,这对您的情况没有用。

于 2012-11-13T04:22:08.580 回答