0

私は PCB アセンブリ論文の C++ プロジェクトを行っており、(私の教授から) C++ コードの古いセットを与えられています。コードをテストして実行しようとすると、クラッシュします...プログラムは正常にコンパイルされますが、実行時にクラッシュします..コードは次のとおりです。

main.cpp:

#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
#include <climits>
#include "NozzleBank.h"
#include "PlacementHead.h"

int main (int argc, char * const argv[]) {
    std::vector<char> list;
    for (int i=0; i<3; i++) {list.push_back('a');}
    for (int i=0; i<3; i++) {list.push_back('b');}
    for (int i=0; i<3; i++) {list.push_back('c');}
    for (int i=0; i<3; i++) {list.push_back('d');}
    for (int i=0; i<3; i++) {list.push_back('_');}

    int i = 0;
    char set[list.size()];
    while (!list.empty()) {
        int x = (rand() % list.size());
        set[i] = list.at(x);
        list.erase(list.begin()+x);
        i++;
    }

    NozzleBank bank(15,set);
    PlacementHead head(4,2,1,"abababab");

    return 0;
} 

PlacementHead.cpp:

#include "PlacementHead.h"
#include <string>
#include <iostream>
#include <string.h>

PlacementHead::PlacementHead(int width, int height, int gap, char* s) {
    width_ = width;
    height_ = height;
    gap_ = gap;
    size_ = (width*height)+1;
    set_ = new char[size_];
    from_ = new int[size_];
    original_ = new char[size_];
    strcpy(set_,s);
    strcpy(original_,s);
}

PlacementHead::~PlacementHead() {

}

int PlacementHead::getSize() { return size_; }
int PlacementHead::getHeight() { return height_; }
int PlacementHead::getWidth() { return width_; }
int PlacementHead::getGap() { return gap_; }

// Palauttaa indeksissä i olevan suuttimen
char PlacementHead::getNozzle(int i) {
    return set_[i-1];
}

// Asettaa indeksissä i olevan suuttimen
void PlacementHead::setNozzle(int i, char c) {
    set_[i-1] = c;
}

// Merkitsee suuttimen poimituksi poistamalla sen listasta
void PlacementHead::markNozzle(int i, int bankPos) {
    set_[i-1] = ' ';
    from_[i-1] = bankPos;
}

// Palauttaa seuraavan poimimattoman suuttimen indeksin
int PlacementHead::getNextUnmarkedPos() {
    for (int i=0; i<size_; i++) {
        if (set_[i]!=' ') {
            return i+1;
        }
    }
    return 0;
}

// Palauttaa suuttimen alkuperäisen sijainnin pankissa
int PlacementHead::getBankPos(int i) {
    return from_[i-1];
}

// Plauttaa alkuperäisen ladontapaan suutinjärjestyksen
void PlacementHead::reset() {
    //for (int i=0; i<size_; i++) {
    //  set_[i] = original_[i];
    //}
    strcpy(set_,original_);
}

// Tulostusmetodi
void PlacementHead::print() {
    std::cout << "ladontapää:\n";
    for (int h=height_; h>0; h--) {
        for (int w=width_; w>0; w--) {
            int i = ((h-1)*width_)+w;
            std::cout << getNozzle(i);
        }
        std::cout << "\n";
    }
}

NozzleBank.cpp:

#include "NozzleBank.h"
#include <string>
#include <iostream>
#include <string.h>

NozzleBank::NozzleBank(int size) {
    bank_ = new char[size];
    original_ = new char[size];
    size_=size;
    for (int i=0; i<size_; i++) {
        bank_[i] = ' ';
        original_[i] = ' ';
    }
}

NozzleBank::NozzleBank(int size, char* s) {
    bank_ = new char[size];
    original_ = new char[size];
    size_ = size;
    strcpy(bank_,s);
    strcpy(original_,s);
}

NozzleBank::~NozzleBank() {

}

int NozzleBank::getSize() { return size_; }

// Palauttaa pankin alkuperäisen järjestyksen
void NozzleBank::reset() {
    strcpy(bank_,original_);
}

// Asettaa indeksissä i olevan suuttimen
void NozzleBank::setNozzle(int i, char c) {
    bank_[i-1] = c;
    original_[i-1] = c;
}

// Palauttaa indeksissä i olevan suuttimen
char NozzleBank::getNozzle(int i) {
    return bank_[i-1];
}

// Poimii suuttimen poistamalla sen listasta
void NozzleBank::pickNozzle(int i) {
    bank_[i-1] = ' ';
}

// Tulostusmetodi
void NozzleBank::print() {
    for (int i=size_; i>0; i--) {
        std::cout << bank_[i-1];
    }
}

プログラムを実行すると、次のようになります。

ここに画像の説明を入力

ここに画像の説明を入力

ここでも興味深いことがあります。main.cpp

NozzleBank bank(15,set);
PlacementHead head(4,2,1,"abababab");

に:

PlacementHead head(4,2,1,"abababab");
NozzleBank bank(15,set);

プログラムは正常に実行されます...:O? そして、ここで私は何のようになります...私はC ++の初心者なので、誰かが何が問題なのかを理解できれば幸いです:)助けてくれてありがとう!

4

2 に答える 2

2

ここで考えられる問題の1つは、使用していることですstrcpy

strcpynull 終了文字に到達するまで文字の配列を読み取ることで機能し'\0'ますが、ソース配列には null 終了文字が含まれていません。そのため、strcpy は永遠にコピーを続け、アクセスできないメモリを読み取り、コピー先の配列の末尾を超えて書き込みを行います。どちらもクラッシュを引き起こす可能性があります。strncpy固定数の文字のみをコピーする (常に優先する必要があります) どちらかを使用する必要があります。

strcpy のように、文字を文字列として扱う場合は、通常、任意の文字配列に常に余分なスペースを残す必要があります。個々の要素のみを使用し、個々の文字を独自に扱う場合は、その必要はありません。memcpyその場合も同様に使用できます。

コードには他にも問題がある可能性がありますが、これは私が見つけた 1 つに過ぎません。

メモリ リークもあります。新しい [] メンバー変数を [] 削除する必要があります。

于 2013-11-07T12:44:10.683 に答える
2

C ライブラリstrcpy()には、NUL で終了する C スタイルの文字列が必要です。NUL ターミネータを持たchar[]ない配列があります。

ランダム化された文字の配列を C スタイルの文字列に変換する場合は、最後にもう 1 つの要素を追加し、値 0 に設定する必要があります。代わりに、strcpy()呼び出しを呼び出しに変換しmemcpy()、長さを指定する必要があります。直接。

最小限のコード変更という点では、NUL ターミネータを追加すると、コードへの変更が最小限で済みます。これを変える:

    char set[list.size()];

これに:

    char set[list.size() + 1];
    set[list.size()] = 0;

そして、すべてのnew char[size_]通話を に変更しますnew char[size_ + 1]

よりクリーンなアプローチは、あなたが何を意味するかを言い、これをcharC 文字列ではなく の配列として扱うことです。strcpyすべての通話を に変換しますmemcpy。たとえば、次のようになります。

    strcpy(set_,s);
    strcpy(original_,s);

これになります:

    memcpy(set_,s,size_);
    memcpy(original_,s,size_);

注:これらのアレイでは、必ずすべて strcpyを変更してください。memcpy他に少なくとも一人はいると思います。私はあなたのコードをそれほど綿密にチェックしませんでした。

後者はより良いアプローチですが、私は両方を提供します。

また、上記のコードはメモリ リークを起こします。一度実行して終了するだけであれば問題ないかもしれません。あなたnew []は決して覚えていませんdelete []。プログラムが成長し、これらのオブジェクトの複数のインスタンスが出入りする場合は、それらのdelete[]呼び出しを追加する必要があります。そうしないと、別の種類の将来のクラッシュに備えることになります。

于 2013-11-07T12:44:36.190 に答える