C语言调用HeapReAlloc扩充内存块,调用_tcscat_s拼接字符串出错
本帖最后由 mxwawaawxm 于 2022-8-29 07:24 编辑大致的功能:修改环境变量path的值,在后面附加新的路径(变量名是szEnvNewValue,我添加的路径是d:\\Program Files\\learn\\C)
第1步,调用GetEnvironmentVariable函数GetEnvironmentVariable(lpName, NULL, 0),获取path值的长度,然后调用HeapAlloc函数分配内存块szMemEnv。
第2步,计算原有path的值加上分隔符;和新路径的长度,再调用HeapReAlloc函数动态扩充内存块。然后,在内存块上,调用_tcscat_s函数依次附加分隔符、待添加的新路径。
_tcscat_s(szMemEnv, dwEnvNewChars, ";");
这里添加分隔符,我特意调用_tprintf函数,打印内存块的大小、字符串的长度及字符串,正确无误
但在_tcscat_s(szMemEnv, dwEnvNewChars, szEnvNewValue)出错
我调用_tprintf函数,打印字符串的长度为0,字符串显示为空字符串。
请问大佬们,是哪里出错了。
代码如下
#include <windows.h>
#include <tchar.h>
#define PATHFILENAME "path"
LPTSTR GetEnvValue(LPCTSTR lpName);
void AppendEnv(LPTSTR szMemEnv, LPCTSTR lpName, LPCTSTR szEnvNewValue);
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
// 环境变量“path”的值
LPTSTR szMemEnv;
// 获取环境变量“path”的值
szMemEnv = GetEnvValue(PATHFILENAME);
// 在环境变量path后添加新路径
AppendEnv(szMemEnv, "path", "d:\\Program Files\\learn\\C");
HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv);
return 1;
}
/* 获取环境变量“path”的值 */
LPTSTR GetEnvValue(LPCTSTR lpName)
{
// GetEnvironmentVariable结果标志
DWORD dwGetEnvFlag;
LPTSTR szMemEnv;
// 获取环境变量“path”的值的字符数(包含结束\0空字符)
DWORD dwSize = GetEnvironmentVariable(lpName, NULL, 0);
// 分配内存
szMemEnv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize*sizeof(TCHAR));
if (szMemEnv==NULL) {
_tprintf(TEXT("HeapAlloc分配内存%s失败:%lu。\n"), lpName, GetLastError());
exit(1);
}
dwGetEnvFlag = GetEnvironmentVariable(lpName, (LPTSTR)szMemEnv, dwSize*sizeof(TCHAR));
if (dwGetEnvFlag==0) {
_tprintf(TEXT("GetEnvironmentVariable获取环境变量%s失败:%lu。\n"), lpName, GetLastError());
HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv);
exit(1);
}
_tprintf(TEXT("\n\n----------------------系统环境变量%s---------------------\n"), lpName);
_tprintf(TEXT("环境变量%s的值:%s\n"), lpName, (LPTSTR)szMemEnv);
_tprintf(TEXT("----------------------系统环境变量%s---------------------\n\n"), lpName);
return szMemEnv;
}
/* 在环境变量path后添加新路径 */
void AppendEnv(LPTSTR szMemEnv, LPCTSTR lpName, LPCTSTR szEnvNewValue)
{
// 新字符数:szMemEnv + ; + szEnvNewValue
DWORD dwEnvNewChars = _tcslen(szMemEnv)+_tcslen(szEnvNewValue)+_tcslen(";");
// 新字节数:szMemEnv + ; + szEnvNewValue + \0
DWORD dwEnvNewBytes = (dwEnvNewChars+1) *sizeof(TCHAR);
// SetEnvironmentVariable函数执行结果标志
BOOL bSetEnvFlag;
szMemEnv = (LPTSTR)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv, dwEnvNewBytes);
if (szMemEnv == NULL) {
_tprintf(TEXT("HeapReAlloc扩充内存失败:%lu。\n"), GetLastError());
HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv);
} else {
_tprintf(TEXT("\n%I64u %I64u %s\n"), HeapSize(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv), _tcslen(szMemEnv), szMemEnv);
// 附加分隔符
_tcscat_s(szMemEnv, dwEnvNewChars, ";");
_tprintf(TEXT("\n%I64u %I64u %s\n"), HeapSize(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv), _tcslen(szMemEnv), szMemEnv);
// 附加新路径
_tcscat_s(szMemEnv, dwEnvNewChars, szEnvNewValue);
_tprintf(TEXT("\n%I64u %I64u %s\n"), HeapSize(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv), _tcslen(szMemEnv), szMemEnv);
bSetEnvFlag = SetEnvironmentVariable(lpName, szMemEnv);
if (bSetEnvFlag==0) {
_tprintf(TEXT("SetEnvironmentVariable设置环境变量失败:%lu。\n"), GetLastError());
} else {
_tprintf(TEXT("\n\n成功在环境变量\"%s\"后添加新值\"%s\"。\n"), lpName, szEnvNewValue);
}
}
} _tprintf(TEXT("\n%I64u %I64u %s\n"), HeapSize(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv), _tcslen(szMemEnv), szMemEnv);
// 附加新路径
_tcscat_s(szMemEnv, dwEnvNewChars, szEnvNewValue);
_tprintf(TEXT("\n%I64u %I64u %s\n"), HeapSize(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv), _tcslen(szMemEnv), szMemEnv);
_tcscat_s(szMemEnv, dwEnvNewChars+1, ";");
_tprintf(TEXT("\n%I64u %I64u %s\n"), HeapSize(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv), _tcslen(szMemEnv), szMemEnv); 你既然用了TCHAR,那源码里的每个字符串常量都得加上TEXT()
还有其他问题,我放到VS里一大堆报错,不知道你是用哪个编译器编译的 本帖最后由 Eaglecad 于 2022-8-25 14:57 编辑
前面长度再扩大一个字节 DWORD dwEnvNewChars = _tcslen(szMemEnv) + _tcslen(szEnvNewValue) + _tcslen(";") + 1;
因为你 “;” 占用了一字节。
_tcscat_s必须有'\0'的结束的字符空间 crack5 发表于 2022-8-25 12:15
_tprintf(TEXT("\n%I64u %I64u %s\n"), HeapSize(GetProcessHeap(), HEAP_ZERO_MEMORY, szMemEnv), _tcsl ...
请问,为什么这一句得加1。
_tcscat_s(szMemEnv, dwEnvNewChars+1, ";");
_tcscat_s函数第二个参数numberOfElements是Size of the destination string buffer.
这里按我的理解是要写字符个数
请问,这个字符个数是要加上\0字符吗
hrpzcf 发表于 2022-8-25 13:20
你既然用了TCHAR,那源码里的每个字符串常量都得加上TEXT()
还有其他问题,我放到VS里一大堆报错,不知 ...
我用gcc编译的。
字符常量要加上TEXT(),这个是我忘了。
vs报错,可能是%I64u格式要换成%llu Eaglecad 发表于 2022-8-25 14:36
前面长度再扩大一个字节 DWORD dwEnvNewChars = _tcslen(szMemEnv) + _tcslen(szEnvNewValue) + _tcslen("; ...
其实,新的字节数那里,我有加上1的。
// 新字符数:szMemEnv + ; + szEnvNewValue
DWORD dwEnvNewChars = _tcslen(szMemEnv)+_tcslen(szEnvNewValue)+_tcslen(";");
// 新字节数:szMemEnv + ; + szEnvNewValue + \0
DWORD dwEnvNewBytes = (dwEnvNewChars+1) *sizeof(TCHAR);
这样看起来,主要出错应该是_tcscat_s第2个参数要写拼接后的缓冲区元素总个数(包括\0)
请问,这样理解对吗。 本帖最后由 Eaglecad 于 2022-8-25 16:16 编辑
mxwawaawxm 发表于 2022-8-25 15:37
其实,新的字节数那里,我有加上1的。
// 新字符数:szMemEnv + ; + szEnvNewValue
DWORD dwEnvNewChar ...
使用 dwEnvNewChars 是需要包含 '\0'的。
还可以不加1,改成 使用 dwEnvNewBytes:
_tcscat_s(szMemEnv, dwEnvNewBytes, ";");
_tcscat_s(szMemEnv, dwEnvNewBytes, szEnvNewValue); 不需要加1 mxwawaawxm 发表于 2022-8-25 15:34
我用gcc编译的。
字符常量要加上TEXT(),这个是我忘了。
vs报错,可能是%I64u格式要换成%llu
// 新字符数:szMemEnv + ; + szEnvNewValue + \0
SIZE_T dwEnvNewChars =
_tcslen(szMemEnv) + _tcslen(szEnvNewValue) + _tcslen(TEXT(";")) + 1;
// 新字节数:szMemEnv + ; + szEnvNewValue + \0
SIZE_T dwEnvNewBytes = dwEnvNewChars * sizeof(TCHAR)
+1 要放在 dwEnvNewChars 这里,否则:虽然分配了 +1 的内存,但是你告诉 _tcscat_s 的是 + 1 之前的长度, _tcscat_s 认为长度不够 Eaglecad 发表于 2022-8-25 15:49
使用 dwEnvNewChars 是需要包含 '\0'的。
还可以不加1,改成 使用 dwEnvNewBytes:
_tcscat_s( ...
我感觉,_tcscat_s函数的第2个参数应该是字符数。不是字节总数。
我测试了下,定义宽字符数组WCHAR szStringDest和宽字符串常量PCWSTR szString = L"string";
调用wcscpy_s(szStringDest, 7, szString);和wcscat_s(szStringDest, 9, L"ch");两个函数
中间的参数写7和9,就能成功。如果是字节数,那应该要写14和18。
#include <windows.h>
#include <tchar.h>
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
PCWSTR szString = L"string";
WCHAR szStringDest;
_tprintf(TEXT("wcslen(szString) = %I64u(字符数)\n"), wcslen(szString));
_tprintf(TEXT("sizeof(*szString) = %I64u(单个字符字节数)\n"), sizeof(*szString));
wcscpy_s(szStringDest, 7, szString);
_tprintf(TEXT("szStringDest = %ls\n"), szStringDest);
wcscat_s(szStringDest, 9, L"ch");
_tprintf(TEXT("szStringDest = %ls\n"), szStringDest);
return 1;
}
页:
[1]
2