You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从函数返回char数组至main后,printf输出乱码问题排查

解决函数返回局部数组导致的乱码问题

Hey, I see exactly what's going on here—you're hitting a classic C memory management pitfall with local stack variables. Let me break this down for you:

问题根源

你在run_cmd()里定义的output[2000]是栈上的局部变量。在C语言中,局部变量的内存会在函数执行完毕返回时被销毁(栈帧被清理)。虽然你返回了指向这个数组的指针,但等到main()尝试打印它时,这块栈内存已经被后续代码(比如main里的printf调用)覆盖了。这就是为什么你看到乱码——指针地址看起来正确,但指向的内存已经无效了。

修复方案

根据你的需求,这里有三种可靠的解决方式:

1. 使用静态数组

把output声明为static变量,这样它会从栈转移到全局数据段,函数返回后不会被销毁。注意:静态变量是全局共享的,如果多次调用run_cmd(),之前的结果会被覆盖。

修改后的run_cmd()片段:

char * run_cmd(char * cmd ) {
    static char output[2000]; // 添加static关键字
    // 其余代码基本不变...
    
    // 记得把Sleep替换成下文提到的进程等待逻辑!
}

2. 使用动态内存分配

用malloc()在堆上分配内存,这块内存会一直存在直到你显式调用free()释放。需要注意在main()中释放内存,避免内存泄漏。

完整修改代码:

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h> // 引入malloc/free的头文件

char * run_cmd(char * cmd ) {
    char *output = malloc(2000); // 在堆上分配内存
    if (output == NULL) { // 务必检查malloc是否成功
        fprintf(stderr, "内存分配失败\n");
        return NULL;
    }
    
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    HANDLE hFile;
    hFile = CreateFileA("out.log", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, &sa,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    
    PROCESS_INFORMATION pi;
    STARTUPINFO si;
    BOOL ret = FALSE;
    DWORD flags = CREATE_NO_WINDOW;
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdInput = NULL;
    si.hStdError = NULL;
    si.hStdOutput = hFile;
    
    ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);
    
    // 替换Sleep(2000)为可靠的进程等待
    if (ret) {
        WaitForSingleObject(pi.hProcess, INFINITE); // 等待进程执行完毕
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
    }
    
    CloseHandle(hFile);
    DWORD lpNumberOfBytesRead;
    hFile = CreateFileA("out.log", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD dwBytesToRead = GetFileSize(hFile, NULL);
    
    // 防止缓冲区溢出
    if (dwBytesToRead > 1999) {
        dwBytesToRead = 1999;
    }
    
    ReadFile(hFile, (void *)output, dwBytesToRead, &lpNumberOfBytesRead, NULL);
    output[lpNumberOfBytesRead] = '\0';
    CloseHandle(hFile);
    
    printf("%s\n", output);
    printf("------------------------------------------------------------------------");
    return output;
}

int main(void) {
    char *result = run_cmd("ipconfig");
    if (result != NULL) {
        printf("%s\n", result);
        free(result); // 记得释放堆内存!
    }
    return 0;
}

3. 让调用者提供缓冲区

不在run_cmd()内分配内存,而是让main()传入一个缓冲区和它的大小。这样调用者拥有内存的所有权,完全避免内存管理问题。

完整修改代码:

#include <Windows.h>
#include <stdio.h>

// 返回写入缓冲区的字节数,出错返回-1
int run_cmd(char * cmd, char *output, size_t output_size) {
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    HANDLE hFile;
    hFile = CreateFileA("out.log", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, &sa,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    
    PROCESS_INFORMATION pi;
    STARTUPINFO si;
    BOOL ret = FALSE;
    DWORD flags = CREATE_NO_WINDOW;
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdInput = NULL;
    si.hStdError = NULL;
    si.hStdOutput = hFile;
    
    ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);
    
    if (ret) {
        WaitForSingleObject(pi.hProcess, INFINITE); // 等待进程执行完毕
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
    }
    
    CloseHandle(hFile);
    DWORD lpNumberOfBytesRead;
    hFile = CreateFileA("out.log", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD dwBytesToRead = GetFileSize(hFile, NULL);
    
    // 预留空间给字符串结束符
    if (dwBytesToRead >= output_size) {
        dwBytesToRead = output_size - 1;
    }
    
    ReadFile(hFile, (void *)output, dwBytesToRead, &lpNumberOfBytesRead, NULL);
    output[lpNumberOfBytesRead] = '\0';
    CloseHandle(hFile);
    
    printf("%s\n", output);
    printf("------------------------------------------------------------------------");
    return lpNumberOfBytesRead;
}

int main(void) {
    char output[2000];
    run_cmd("ipconfig", output, sizeof(output));
    printf("%s\n", output);
    return 0;
}

额外修复:替换Sleep为可靠的进程等待

你当前用的Sleep(2000)是个临时方案——无法保证进程会在2秒内执行完毕。改用WaitForSingleObject(pi.hProcess, INFINITE)可以确保等到命令完全执行结束后再读取输出文件,这样每次都能获取完整的结果。

内容的提问来源于stack exchange,提问作者user1720897

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 12:32:36