VS2017 C++控制台程序连接SQL Server 2017出现SQL_ERROR报错
Let’s walk through the most likely issues causing that vague memory-address error and fix them one by one:
1. Fix the Connection String Type Mismatch (Biggest Culprit!)
Right now, you’re casting a regular char string to SQLWCHAR* directly—and that’s a huge problem. ODBC’s wide-character functions (like the one you’re calling) expect UTF-16 wide strings, not forced casts from single-byte chars. This mangles the connection string into garbage data, which leads to those unpredictable memory-address errors.
Quick Fix:
Use wide-string literals (prefix with L) for your connection string, no casts needed:
SQLWCHAR connStr[] = L"DRIVER={SQL Server};SERVER=myServer,1433;DATABASE=testing;UID=user;PWD=password;Trusted_Connection=True;"; retCode = SQLDriverConnectW(SQLConnectionHandle, NULL, connStr, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
Or if you prefer sticking with regular char strings, call the ANSI-specific version of the function explicitly:
char connStr[] = "DRIVER={SQL Server};SERVER=myServer,1433;DATABASE=testing;UID=user;PWD=password;Trusted_Connection=True;"; retCode = SQLDriverConnectA(SQLConnectionHandle, NULL, connStr, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
Pro tip: Don’t mix ANSI and wide-character ODBC functions—pick one set (all A suffix or all W suffix) and stick with it to avoid weird bugs.
2. Make Sure You’re Initializing ODBC Handles Correctly
You didn’t show the code for setting up SQLEnvHandle and SQLConnectionHandle—if these aren’t properly allocated with SQLAllocHandle, your connection will fail before it even starts. Here’s the mandatory initialization code you need:
// Step 1: Allocate environment handle retCode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &SQLEnvHandle); if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO) { // Handle init failure here return -1; } // Step 2: Set ODBC version to 3.0 (required for modern SQL Server) retCode = SQLSetEnvAttr(SQLEnvHandle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO) { SQLFreeHandle(SQL_HANDLE_ENV, SQLEnvHandle); return -1; } // Step 3: Allocate connection handle retCode = SQLAllocHandle(SQL_HANDLE_DBC, SQLEnvHandle, &SQLConnectionHandle); if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO) { SQLFreeHandle(SQL_HANDLE_ENV, SQLEnvHandle); return -1; }
3. Get Real Error Messages (Not Just Memory Addresses)
Your showSQLError function probably isn’t pulling the actual error details from ODBC. Instead of seeing a useless memory address, let’s modify it to fetch meaningful error codes and messages using SQLGetDiagRec:
void showSQLError(SQLSMALLINT handleType, SQLHANDLE handle) { SQLWCHAR sqlState[6], message[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER nativeError; SQLSMALLINT textLength; SQLRETURN ret; int diagCount = 1; ret = SQLGetDiagRecW(handleType, handle, diagCount, sqlState, &nativeError, message, SQL_MAX_MESSAGE_LENGTH, &textLength); while (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) { wprintf(L"ODBC Error [%d]: State = %s, Code = %d, Message = %s\n", diagCount, sqlState, nativeError, message); diagCount++; ret = SQLGetDiagRecW(handleType, handle, diagCount, sqlState, &nativeError, message, SQL_MAX_MESSAGE_LENGTH, &textLength); } }
Now when you hit SQL_ERROR, you’ll get specific info like "invalid credentials", "server not reachable", or "driver not found"—way more helpful than a memory address.
4. Clean Up Your Connection String
- Remove extra spaces around commas/semicolons:
SERVER=myServer, 1433should beSERVER=myServer,1433(spaces can break string parsing). - Pick one auth method: If you use
Trusted_Connection=True, you don’t needUIDandPWD—they conflict. Either use Windows Auth (Trusted_Connection=True) or SQL Server Auth (keepUID/PWDand remove theTrusted_Connectionline).
内容的提问来源于stack exchange,提问作者Sergio Martinez

