我确实在做一些非法的事情,我想知道是什么。我尽可能地隔离了我的错误。如果我在主函数内部初始化 Items 数组,它不会出现,只有当它存储在 Bottom_Pannel 对象内部时才会出现。
这是代码:
文件主.cpp
#include "Windows.h"
#include "Bottom_Panel.h"
void Test2()
{
// Initializing new console screen_buffer
HANDLE Screen_Buffer_Handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CONSOLE_TEXTMODE_BUFFER, 0);
CONSOLE_SCREEN_BUFFER_INFO Screen_Buffer_Info{};
SetConsoleActiveScreenBuffer(Screen_Buffer_Handle);
GetConsoleScreenBufferInfo(Screen_Buffer_Handle, &Screen_Buffer_Info);
int screen_buffer_size = (int)Screen_Buffer_Info.dwSize.X * (int)Screen_Buffer_Info.dwSize.Y;
CHAR_INFO* Screen_Buffer = new CHAR_INFO[screen_buffer_size];
// Bug causing part:
AsBottom_Panel* Bottom_Panel = new AsBottom_Panel(Screen_Buffer, Screen_Buffer_Info.dwSize.X, 0, Screen_Buffer_Info.dwSize.Y - 1);
while (true)
{
Bottom_Panel->Draw();
Sleep(10);
}
}
int main()
{
Test2();
return 0;
}
文件Bottom_Panel.cpp:
#include "Bottom_Panel.h"
// ABottom_Panel_Item
ABottom_Panel_Item::ABottom_Panel_Item(std::wstring key, std::wstring name)
: Key(key), Name(name), Key_Size(key.size())
{
}
void ABottom_Panel_Item::Draw(CHAR_INFO* screen_buffer, unsigned short x_pos, unsigned short y_pos,
unsigned short screen_width, unsigned short limit)
{
for (int i = 0; i < Key_Size; ++i)
{
CHAR_INFO ch;
ch.Attributes = 0x07;
ch.Char.UnicodeChar = Key[i];
screen_buffer[y_pos * screen_width + x_pos + i] = ch;
}
for (int i = 0; i < limit; ++i)
{
CHAR_INFO ch;
ch.Attributes = 0xb0;
if (i < Name.size())
{
ch.Char.UnicodeChar = Name[i];
}
else
{
ch.Char.UnicodeChar = ' ';
}
screen_buffer[y_pos * screen_width + x_pos + i + Key_Size] = ch;
}
}
// AsBottom_Panel
AsBottom_Panel::AsBottom_Panel(CHAR_INFO* screen_buffer, unsigned short screen_width,
unsigned short x_pos, unsigned short y_pos)
: Screen_Buffer(screen_buffer), Screen_Width(screen_width), X_Pos(x_pos), Y_Pos(y_pos)
{
Items[0] = new ABottom_Panel_Item(L"1", L"Help");
Items[1] = new ABottom_Panel_Item(L"2", L"UserMenu");
Items[2] = new ABottom_Panel_Item(L"3", L"View");
Items[3] = new ABottom_Panel_Item(L"4", L"Edit");
Items[4] = new ABottom_Panel_Item(L"5", L"Copy");
Items[5] = new ABottom_Panel_Item(L"6", L"RenMov");
Items[6] = new ABottom_Panel_Item(L"7", L"MakeDir");
Items[7] = new ABottom_Panel_Item(L"8", L"Delete");
Items[8] = new ABottom_Panel_Item(L"9", L"Config");
Items[9] = new ABottom_Panel_Item(L"10", L"Quit");
}
void AsBottom_Panel::Draw()
{
int step = Screen_Width / 10; // Screen_Width = 120 on my PC
for (int i = 0; i < 10; i++)
{
Items[i]->Draw(Screen_Buffer, X_Pos, Y_Pos, Screen_Width, 8);
X_Pos += step;
}
}
文件Bottom_Panel.h:
#pragma once
class ABottom_Panel_Item
{
public:
ABottom_Panel_Item(std::wstring key, std::wstring name);
void Draw(CHAR_INFO* screen_buffer, unsigned short x_pos, unsigned short y_pos,
unsigned short screen_width, unsigned short limit);
private:
const std::wstring Key;
const std::wstring Name;
int Key_Size;
};
class AsBottom_Panel
{
public:
AsBottom_Panel(CHAR_INFO* screen_buffer, unsigned short screen_width, unsigned short x_pos,
unsigned short y_pos);
void Draw();
private:
unsigned short X_Pos, Y_Pos;
unsigned short Screen_Width;
CHAR_INFO* Screen_Buffer;
ABottom_Panel_Item* Items[10]{};
};
我遇到异常:
Exception thrown: read access violation.
std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >::operator[](...) returned 0xFFFFFFFFFFFFFFFF.
我在 Bottom_Panel 的构造函数中初始化的我的 Bottom_Panel_Item 对象已损坏。当我设置断点来查看发生的情况时,我看到的是
<error reading characters of string>
而不是我的变量。
我尝试使用预定义的字符数组 wchar_t Key[10]
和 wchar_t Name[10]
- 没有结果。
当我在 while 循环中第二次调用 Draw()
方法时,就会出现问题。我猜想在某些时候内存会被覆盖在某个地方。
我将主要解决至少一个代码问题及其发生位置。
但是,为了解决这个问题,我获取了您的代码并将其更改为使用
std::vector<CHAR_INFO>
而不是 CHAR_INFO*
。这使我能够轻松诊断越界访问。
执行此操作时,再加上在 Visual Studio 中以调试模式运行程序,我得到一个下标超出范围断言,恰好在
screen_buffer
访问范围内。
这是您的代码的重写:
#include <windows.h>
#include <string>
#include <vector>
using SBuffer = std::vector<CHAR_INFO>;
class ABottom_Panel_Item
{
public:
ABottom_Panel_Item(std::wstring key, std::wstring name);
void Draw(SBuffer& screen_buffer, unsigned short x_pos, unsigned short y_pos,
unsigned short screen_width, unsigned short limit);
private:
const std::wstring Key;
const std::wstring Name;
int Key_Size;
};
class AsBottom_Panel
{
public:
AsBottom_Panel(SBuffer& screen_buffer, unsigned short screen_width, unsigned short x_pos,
unsigned short y_pos);
void Draw();
private:
unsigned short X_Pos, Y_Pos;
unsigned short Screen_Width;
SBuffer Screen_Buffer;
ABottom_Panel_Item* Items[10]{};
};
ABottom_Panel_Item::ABottom_Panel_Item(std::wstring key, std::wstring name)
: Key(key), Name(name), Key_Size(key.size())
{
}
void ABottom_Panel_Item::Draw(SBuffer& screen_buffer, unsigned short x_pos, unsigned short y_pos,
unsigned short screen_width, unsigned short limit)
{
for (int i = 0; i < Key_Size; ++i)
{
CHAR_INFO ch;
ch.Attributes = 0x07;
ch.Char.UnicodeChar = Key[i];
screen_buffer[y_pos * screen_width + x_pos + i] = ch; // <-- Error here
}
for (int i = 0; i < limit; ++i)
{
CHAR_INFO ch;
ch.Attributes = 0xb0;
if (i < Name.size())
{
ch.Char.UnicodeChar = Name[i];
}
else
{
ch.Char.UnicodeChar = ' ';
}
screen_buffer[y_pos * screen_width + x_pos + i + Key_Size] = ch;
}
}
// AsBottom_Panel
AsBottom_Panel::AsBottom_Panel(SBuffer& screen_buffer, unsigned short screen_width,
unsigned short x_pos, unsigned short y_pos)
: Screen_Buffer(screen_buffer), Screen_Width(screen_width), X_Pos(x_pos), Y_Pos(y_pos)
{
Items[0] = new ABottom_Panel_Item(L"1", L"Help");
Items[1] = new ABottom_Panel_Item(L"2", L"UserMenu");
Items[2] = new ABottom_Panel_Item(L"3", L"View");
Items[3] = new ABottom_Panel_Item(L"4", L"Edit");
Items[4] = new ABottom_Panel_Item(L"5", L"Copy");
Items[5] = new ABottom_Panel_Item(L"6", L"RenMov");
Items[6] = new ABottom_Panel_Item(L"7", L"MakeDir");
Items[7] = new ABottom_Panel_Item(L"8", L"Delete");
Items[8] = new ABottom_Panel_Item(L"9", L"Config");
Items[9] = new ABottom_Panel_Item(L"10", L"Quit");
}
void AsBottom_Panel::Draw()
{
int step = Screen_Width / 10; // Screen_Width = 120 on my PC
for (int i = 0; i < 10; i++)
{
Items[i]->Draw(Screen_Buffer, X_Pos, Y_Pos, Screen_Width, 8);
X_Pos += step;
}
}
void Test2()
{
// Initializing new console screen_buffer
HANDLE Screen_Buffer_Handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CONSOLE_TEXTMODE_BUFFER, 0);
CONSOLE_SCREEN_BUFFER_INFO Screen_Buffer_Info{};
SetConsoleActiveScreenBuffer(Screen_Buffer_Handle);
GetConsoleScreenBufferInfo(Screen_Buffer_Handle, &Screen_Buffer_Info);
int screen_buffer_size = (int)Screen_Buffer_Info.dwSize.X * (int)Screen_Buffer_Info.dwSize.Y;
SBuffer Screen_Buffer(screen_buffer_size);
// Bug causing part:
AsBottom_Panel* Bottom_Panel = new AsBottom_Panel(Screen_Buffer, Screen_Buffer_Info.dwSize.X, 0, Screen_Buffer_Info.dwSize.Y - 1);
while (true)
{
Bottom_Panel->Draw();
Sleep(10);
}
}
int main()
{
Test2();
return 0;
}
发生错误是因为
screen_buffer
的大小为 3600,但在某些时候您正在访问 screen_buffer[y_pos * screen_width + x_pos + i]
,其中 y_pos * screen_width + x_pos + i
等于 3600。这是越界访问,因为 screen_buffer[3600]
超出了范围界限。