/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, Java, PHP, Ruby, Perl,
C#, OCaml, VB, Swift, Pascal, Fortran, Haskell, Objective-C, Assembly, HTML, CSS, JS, SQLite, Prolog.
Code, Compile, Run and Debug online from anywhere in world.
*******************************************************************************/
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <vector>
#include <cmath>
using namespace std;
class Okret {
public:
string nazwa;
int id, moc, szybkosc, zaloga, celnosc, hp;
Okret(int identifier, string name, int power, int speed, int crew, int accuracy, int hitpoints) {
nazwa = name;
moc = power;
szybkosc = speed;
zaloga = crew;
celnosc = accuracy;
id = identifier;
hp = hitpoints;
}
Okret() {}
void get() {
cout << "***************\nID: " << id << "\nNAZWA: " << nazwa << "\nMOC : " << moc << "\nSZYBKOSC: " << szybkosc << "\nHP: " << hp << "\nZALOGA: " << zaloga << "\nCELNOSC: " << celnosc << "\n\n";
}
};
class Krazownik : public Okret {
public:
int iloscDzial, zasieg;
Krazownik(int identifier, string name, int power, int speed, int crew, int accuracy, int hitpoints, int cannonCount, int range) : Okret(identifier, name, power, speed, crew, accuracy, hitpoints) {
iloscDzial = cannonCount;
zasieg = range;
}
Krazownik() {}
void get() {
Okret::get();
cout << "ILOSC DZIAL: " << iloscDzial << "\nZASIEG: " << zasieg << "\n\n";
}
};
class LodzPodwodna : public Krazownik {
public:
int glebokosc;
bool czyAtom;
LodzPodwodna(int identifier, string name, int power, int speed, int crew, int accuracy, int hitpoints, int cannonCount, int range, int depth, bool isAtomic) : Krazownik(identifier, name, power, speed, crew, accuracy, hitpoints, cannonCount, range) {
glebokosc = depth;
czyAtom = isAtomic;
}
LodzPodwodna() {}
void get() {
Krazownik::get();
cout << "GLEBOKOSC: " << glebokosc << "\nATOM: " << czyAtom << "\n\n";
}
};
class Flota {
public:
Okret** okrety;
Krazownik** krazowniki;
LodzPodwodna** lpodwodne;
int identifier = 0;
int ships[3];
Flota(int iloscOkretow, int iloscKrazownikow, int iloscLodziPodwodnych) {
ships[0] = iloscOkretow;
ships[1] = iloscKrazownikow;
ships[2] = iloscLodziPodwodnych;
okrety = new Okret * [ships[0]];
krazowniki = new Krazownik * [ships[1]];
lpodwodne = new LodzPodwodna * [ships[2]];
string name[2][10] = { {"HMS", "LA", "OZM", "ZLB", "SHW", "CHM", "KTR", "RJ45", "FFK", "REP"}, {"Danietz", "Magda", "Patrycja", "MOSiR", "JTFolio", "Pandziak", "Morcinek", "Fentanyl", "Robercia", "Malpa"} }, typy[3] = { "Okrety:", "Krazowniki:", "Lodzie podw.:" };
for (int i = 0; i < 3; i++)
for (int j = 0; j < ships[i]; j++) {
string tname = name[0][rand() % 10] + ' ' + name[1][rand() % 10];
switch (i) {
case 0:
okrety[j] = new Okret(identifier, tname, rand() % 11 + 15, rand() % 201 + 200, rand() % 4 + 1, rand() % 16 + 60, rand() % 100 + 300);
break;
case 1:
krazowniki[j] = new Krazownik(identifier, tname, rand() % 21 + 40, rand() % 176 + 200, rand() % 21 + 10, rand() % 31 + 45, rand() % 500 + 750, rand() % 3 + 1, rand() % 76 + 75);
break;
case 2:
lpodwodne[j] = new LodzPodwodna(identifier, tname, rand() % 11 + 35, rand() % 301 + 150, rand() % 3 + 2, rand() % 11 + 75, rand() % 250 + 600, 2, rand() % 101 + 150, rand() % 301 + 150, (rand() % 2 == 0) ? true : false);
break;
}
identifier++;
}
cout << "=== FLOTA ===\nOkretow: " << iloscOkretow << "\nKrazownikow: " << iloscKrazownikow << "\nLodzi podwodnych: " << iloscLodziPodwodnych << "\n=============\n";
for (int i = 0; i < ships[0]; i++)
okrety[i]->get();
for (int i = 0; i < ships[1]; i++)
krazowniki[i]->get();
for (int i = 0; i < ships[2]; i++)
lpodwodne[i]->get();
}
};
bool checkVictory(int hp1, int hp2, string nazwa1, string nazwa2, int id1, int id2) {
if (hp1 <= 0 && hp2 <= 0) {
cout << "[REMIS] Oba '" << nazwa1 << "' oraz '" << nazwa2 << "' leza na dnie basenu! (OVERKILL: " << hp1 << " hp i " << hp2 << " hp)!\n";
return true;
}
if (hp1 <= 0) {
cout << "[WYGRANA] '" << nazwa2 << " " << id2 << "' zwyciezyl '" << nazwa1 << " " << id2 << "' (OVERKILL: " << hp1 << " hp)!\n";
return true;
}
if (hp2 <= 0) {
cout << "[WYGRANA] '" << nazwa1 << " " << id1 << "' zwyciezyl '" << nazwa2 << " " << id1 << "' (OVERKILL: " << hp2 << " hp)!\n";
return true;
}
return false;
}
int rem(LodzPodwodna* statek1, LodzPodwodna* statek2) {
LodzPodwodna* statek[2] = { statek1, statek2 };
for (int i = 0; i < 2; i++) {
if (rand() % 101 <= statek[0 + i]->celnosc) {
statek[1 - i]->hp -= statek[0 + i]->moc * statek[0 + i]->iloscDzial - statek[1 - i]->glebokosc / 30;
cout << "'" << statek[0 + i]->nazwa << " " << statek[0 + i]->id << "' godzi '" << statek[1 - i]->nazwa << "' (" << statek[0 + i]->moc * statek[0 + i]->iloscDzial - statek[1 - i]->glebokosc / 30 << " hp)! ";
if (statek[1 - i]->hp > 0)
cout << "Pozostalo " << statek[1 - i]->hp << " hp.";
else if (statek[1 - i]->czyAtom) {
cout << "\n[BOMBA] Awaryjna orpeda atomowa zostala wystrzelona! ";
if (rand() % 101 < 13) {
statek[0 + i]->hp -= 9999;
cout << "Niezneutralizowana na czas, obraca cel w proch!";
}
else
cout << "Nie trafia!";
}
cout << "\n";
if (checkVictory(statek[0]->hp, statek[1]->hp, statek[0]->nazwa, statek[1]->nazwa, statek[0]->id, statek[1]->id))
return 0;
}
else
cout << "'" << statek[0 + i]->nazwa << "' chybił!\n";
}
return 0;
}
void walka(Flota* flota1, Flota* flota2) {
char dummy;
while (1) {
cout << "Oczekiwanie...\n>> ";
cin >> dummy;
Flota* args[2] = { flota1, flota2 };
int total = flota1->ships[0] + flota1->ships[1] + flota1->ships[2], tura = 1;
vector<vector<LodzPodwodna*>> floty(2, vector<LodzPodwodna*>(total));
for (int i = 0; i < 2; i++)
for (int j = 0; j < args[i]->ships[0]; j++) {
Okret* okret = args[i]->okrety[j];
floty[i][j] = new LodzPodwodna(okret->id, okret->nazwa, okret->moc, okret->celnosc, okret->zaloga, okret->celnosc, okret->hp, 1, 130, 1, false);
floty[i][j]->get();
}
for (int i = 0; i < 2; i++)
for (int j = 0; j < args[i]->ships[1]; j++) {
Krazownik* krazownik = args[i]->krazowniki[j];
floty[i][j] = new LodzPodwodna(krazownik->id, krazownik->nazwa, krazownik->moc, krazownik->celnosc, krazownik->zaloga, krazownik->celnosc, krazownik->hp, krazownik->iloscDzial, krazownik->zasieg, 1, false);
floty[i][j]->get();
}
for (int i = 0; i < 2; i++)
for (int j = 0; j < args[i]->ships[2]; j++)
floty[i][j] = args[i]->lpodwodne[j];
cout << "\n######################\n WALKA\n######################\n";
bool hasEnded = false;
while (!hasEnded) {
hasEnded = true;
cout << "\n--- TURA " << tura;
for (int i = 0; i < total; i++) {
cout << "\n";
if (checkVictory(floty[0][i]->hp, floty[1][i]->hp, floty[0][i]->nazwa, floty[1][i]->nazwa, floty[0][i]->id, floty[1][i]->id))
continue;
if (floty[0][i]->szybkosc >= floty[1][i]->szybkosc)
rem(floty[0][i], floty[1][i]);
else
rem(floty[1][i], floty[0][i]);
hasEnded = false;
}
tura++;
}
cout << "\n--- KONIEC\n\n";
}
}
int main()
{
srand(time(NULL));
int input[3] = { 1, 1, 0 };
Flota flota1(input[0], input[1], input[2]);
Flota flota2(input[0], input[1], input[2]);
walka(&flota1, &flota2);
return 0;
}
你好, 上述是我的海战模拟器。它对开始时给出的 3 个整数进行操作,每个整数定义参与的相应船舶类别的数量(全部属于母
Flota
类别)。它们之间的差异是统计数据,有些仅出现在后续子类中(如果可能的话,它们会被继承)。
通过 for get()
跳过类演示,生成另一个 Flota 对象,其中包含相同数量的对象。
然后模拟开始。每个对象都与相反数组元素中托管的另一个对象交互。
但是,当至少存在 2 种船舶时,当调用 check victory()
函数且参数是对对象数据的引用时,会发生 SIGSEGV。
这是为什么呢?调用属性本身会导致错误,这是
walka()
函数特有的错误。
请帮忙
编辑:为了复制,在第一个输入中使用,例如,1 1 0,并在下一个输入中输入任何内容(val并不重要)。
编辑2:将用户输入修复为上述组合。
问题在于 for 循环的初始化没有使起始 j 值等于占用槽数 + 1。该片段从 0 开始输入表中的对象,因此输入组合 1 1 0 的结果将导致表具有仅存在 1 个对象(根据上述解释,其中一个将被覆盖)。
这里地址消毒剂指向:
/app/example.cpp:163:33: runtime error: member access within null pointer of type 'struct LodzPodwodna'
AddressSanitizer:DEADLYSIGNAL
=================================================================
==1==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000020 (pc 0x000000407190 bp 0x7ffe87ac63e0 sp 0x7ffe87ac6160 T0)
==1==The signal is caused by a READ memory access.
==1==Hint: address points to the zero page.
#0 0x407190 in walka(Flota*, Flota*) /app/example.cpp:163
#1 0x408740 in main /app/example.cpp:184
#2 0x7fe283629d8f (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: c289da5071a3399de893d2af81d6a30c62646e1e)
#3 0x7fe283629e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: c289da5071a3399de893d2af81d6a30c62646e1e)
#4 0x403394 in _start (/app/output.s+0x403394) (BuildId: 671a5091a9969ac5e5067d77bcefc6c3ca93cbb5)
现在
example.cpp:163
是这一行:
if (checkVictory(floty[0][i]->hp, floty[1][i]->hp, floty[0][i]->nazwa, floty[1][i]->nazwa, floty[0][i]->id, floty[1][i]->id))
根据上面的代码,
floty
的索引范围是正确的:
vector<vector<LodzPodwodna*>> floty(2, vector<LodzPodwodna*>(total));
所以问题一定是指针本身。
这部分代码有可疑之处:
for (int i = 0; i < 2; i++)
for (int j = 0; j < args[i]->ships[0]; j++) {
Okret* okret = args[i]->okrety[j];
floty[i][j] = new LodzPodwodna(okret->id, okret->nazwa, okret->moc, okret->celnosc, okret->zaloga, okret->celnosc, okret->hp, 1, 130, 1, false);
floty[i][j]->get();
}
请注意,索引
j
的范围与 floty
初始化失败的位置不同。在那里,它取决于 total
值,而在有问题的代码中,它取决于 args[i]->ships[0]
。
注意它们之间的关系:
int total = flota1->ships[0] + flota1->ships[1] + flota1->ships[2];
所以
total
总是比 flota1->ships[0]
flota1->ships[1]
之一更大!
所以你取消引用
nullptr
的底线是因为total
值与floty
初始化不一致。
使用 valgrind 快速运行告诉我,您在此处的读取无效
if (checkVictory(floty[0][i]->hp, floty[1][i]->hp, floty[0][i]->nazwa, floty[1][i]->nazwa, floty[0][i]->id, floty[1][i]->id))
事实上,你可以验证元素
floty[0][1]
和 floty[1][1]
是 nullptr
。
但是这个错误的根本原因是你正在使用原始指针和手动内存管理