我在尝试启动我的应用程序时遇到此错误,我已将问题隔离到此代码函数,但我不明白为什么会发生这种情况...
void checkDB()
{
sqlite3 *db;
int rc=0;
size_t i;
char *zErrMsg = 0;
HMODULE hModule = GetModuleHandleW(NULL);
WCHAR path[MAX_PATH];
char buffer[MAX_PATH*4];
int len;
GetModuleFileNameW(hModule, path, MAX_PATH);
len =lstrlenW(path);
path[len-13]='\0';
buffer[0]='\0';
wcscat_s(path,sizeof(path),L"test.db\0");
GetFileAttributes(path);
if(INVALID_FILE_ATTRIBUTES == GetFileAttributes(path) && GetLastError()==ERROR_FILE_NOT_FOUND)
{
wcstombs_s(&i,buffer,sizeof(buffer), path, wcslen(path) );
rc= sqlite3_open(buffer,&db);
rc=sqlite3_exec(db,"create table Recipe (Recipe_Num INTEGER PRIMARY KEY AUTOINCREMENT, Recipe_Image VARCHAR(30), Recipe_Name VARCHAR(200))",NULL,0,&zErrMsg);
sqlite3_free(zErrMsg);
rc=sqlite3_exec(db,"create table Recipe_Step (Recipe_Num INTEGER, Step_Num INTEGER, Description VARCHAR(2000))",NULL,0,&zErrMsg);
if(rc!=SQLITE_OK)
{
sqlite3_close(db);
}
else
{
sqlite3_close(db);
}
}
}
最佳答案
是否有可能您正在溢出一些原始 char
/WCHAR
缓冲区?
我建议您使代码现代化并使用健壮的字符串类,例如std::wstring
或CString[W]
运算符重载,而不是像 wcscat_s()
这样的原始数组和原始 C 字符串函数(你误用了:你应该传递 _countof(path)
而不是 sizeof( path)
,因为“大小”必须用 WCHAR
表示,而不是字节)。
要将 Unicode UTF-16 转换为 ANSI/MBCS,您可以使用 ATL helpers like CW2A
而不是 wcstombs_s()
。
例如:
// Assume Unicode builds, so GetModuleFileName is actually GetModuleFileNameW,
// CString is CStringW, etc.
CString strPath;
WCHAR* pszPath = strPath.GetBuffer(MAX_PATH);
GetModuleFileName(hModule, pszPath, MAX_PATH);
// check GetModuleFileName()'s return value...
strPath.ReleaseBuffer();
// Operate on strPath using operator+= to concatenate strings, etc.
strPath += L"test.db";
....
if(INVALID_FILE_ATTRIBUTES == GetFileAttributes(strPath) && GetLastError()==ERROR_FILE_NOT_FOUND)
{
// Convert from UTF-16 to ANSI
CW2A buffer(strPath);
rc = sqlite3_open(buffer, &db);
....
}
此外,您正在泄漏字符串内存,因为您在第二次调用 sqlite3_exec()
后没有调用 sqlite3_free(zErrMsg)
。我建议使用 RAII 模式和 C++ 析构函数的强大功能来尝试编写自动释放资源的代码。
您可以在这些字符串上编写一个简单的包装器,在析构函数中调用 sqlite3_free()
,例如:
class SqlLiteErrorMsg
{
public:
SqlLiteErrorMsg()
: errorMsg(nullptr)
{}
~SqlLiteErrorMsg()
{
sqlite3_free(errorMsg);
}
char** GetAddressOf()
{
return &errorMsg;
}
char* Get()
{
return errorMsg;
}
private:
// Ban copy
SqlLiteErrorMsg(const SqlLiteErrorMsg&);
SqlLiteErrorMsg& operator=(const SqlLiteErrorMsg&);
char* errorMsg;
};
可以围绕 sqlite3*
指针构建类似的包装器。
关于c++ - 运行时检查失败 #2 - 变量 'db' 周围的堆栈已损坏。 c++ (帮助),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15689888/