1

私が作成しているコードは、このクラスに取り組んだ3週目の結果です。私は物事をかなりうまく処理していました(またはそう思っていました)が、今週はポインターに焦点を当てており、なぜこのエラーが発生し続けるのかわかりません。デバッグアサーションが失敗し続けます!一般的な「バッファが小さすぎる」という説明とともにエラーが発生します。

私のエラーメッセージ

これは、VS2012RCバージョン11.0.505221.1を使用してWin8OSでコンパイルした完全なコードです。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

を定義しましたが、を除いてchar buffer[81]81文字を読み取ろうとしています。したがって、前のものをに、または後のものをに変更する必要があります。cin.getline(buffer, 81)\0char buffer[82]cin.getline(buffer, 80)

また、C ++を使用している場合は、使用しないのはなぜstringですか?

于 2012-11-13T04:17:13.480 に答える
0

MSが_s関数の使用を要求する理由は、コードが現在表示されているようなバッファオーバーフローからコードを保護するためです。詳細については、このリンクを確認してください。

81文字の文字列があります。サイズ+1(データが失われます)の新しい文字列を新しく作成します。これは現在82文字です。81文字の長さのguestにバッファをコピーしようとすると、アサートが発生します。

std :: stringの使用を検討し、文字列の割り当て/解放を停止します。この場合は役に立ちません。

于 2012-11-13T04:22:08.580 に答える
0

使用しない場合はstrcpy_s、ポインタからバッファにコピーする前に、自分で境界チェックを行う必要があります。

また、でdeleteを呼び出さないでくださいguest。Deleteは、newを使用して割り当てたメモリを解放するために使用されます。

于 2012-11-13T04:27:24.853 に答える