吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 806|回复: 10
收起左侧

[已解决] C语言调用HeapReAlloc扩充内存块,调用_tcscat_s拼接字符串出错

[复制链接]
mxwawaawxm 发表于 2022-8-25 11:42
本帖最后由 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,字符串显示为空字符串。
请问大佬们,是哪里出错了。

2022-08-25_113839.png
代码如下
[C] 纯文本查看 复制代码
#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);
        }
    }
}

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

crack5 发表于 2022-8-25 12:15
                _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);

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

hrpzcf 发表于 2022-8-25 13:20
你既然用了TCHAR,那源码里的每个字符串常量都得加上TEXT()

还有其他问题,我放到VS里一大堆报错,不知道你是用哪个编译器编译的
Eaglecad 发表于 2022-8-25 14:36
本帖最后由 Eaglecad 于 2022-8-25 14:57 编辑

前面长度再扩大一个字节 DWORD dwEnvNewChars = _tcslen(szMemEnv) + _tcslen(szEnvNewValue) + _tcslen(";") + 1;
因为你 “;” 占用了一字节。
_tcscat_s必须有'\0'的结束的字符空间

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| mxwawaawxm 发表于 2022-8-25 15:33
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字符吗

 楼主| mxwawaawxm 发表于 2022-8-25 15:34
hrpzcf 发表于 2022-8-25 13:20
你既然用了TCHAR,那源码里的每个字符串常量都得加上TEXT()

还有其他问题,我放到VS里一大堆报错,不知 ...

我用gcc编译的。
字符常量要加上TEXT(),这个是我忘了。
vs报错,可能是%I64u格式要换成%llu
 楼主| mxwawaawxm 发表于 2022-8-25 15:37
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 15:49
本帖最后由 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
hrpzcf 发表于 2022-8-25 16:01
mxwawaawxm 发表于 2022-8-25 15:34
我用gcc编译的。
字符常量要加上TEXT(),这个是我忘了。
vs报错,可能是%I64u格式要换成%llu

[C] 纯文本查看 复制代码
// 新字符数: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 认为长度不够

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
mxwawaawxm + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| mxwawaawxm 发表于 2022-8-26 10:14
Eaglecad 发表于 2022-8-25 15:49
使用 dwEnvNewChars 是需要包含 '\0'的。
还可以不加1,改成 使用 dwEnvNewBytes:
        _tcscat_s( ...

我感觉,_tcscat_s函数的第2个参数应该是字符数。不是字节总数。
我测试了下,定义宽字符数组WCHAR szStringDest[20]和宽字符串常量PCWSTR szString = L"string";
调用wcscpy_s(szStringDest, 7, szString);和wcscat_s(szStringDest, 9, L"ch");两个函数
中间的参数写7和9,就能成功。如果是字节数,那应该要写14和18。

[C] 纯文本查看 复制代码
#include <windows.h>
#include <tchar.h>

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    PCWSTR szString = L"string";
    WCHAR szStringDest[20];

    _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;
}


您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 07:31

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表