2017-03-09 100 views
-3

我用C编写了一个cmd提示符(不是C++),该程序已经编译,但是当我运行它时,我输入了几次命令,程序错误并中止 我认为这是应该的内存分配: 所以这是源代码:C中的内存管理(分配)

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

char* Execute(char*); 

HANDLE readIN = NULL; 
HANDLE writeIN = NULL; 
HANDLE readOUT = NULL; 
HANDLE writeOUT = NULL; 



int 
main(int argc, char** argv) 
{ 
    SECURITY_ATTRIBUTES saAttr; 
    STARTUPINFO si; 
    PROCESS_INFORMATION pi; 

    char cmd[12]; 
    char* out = NULL; 
    ZeroMemory(cmd,sizeof(cmd)); 


    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saAttr.bInheritHandle = TRUE; 
    saAttr.lpSecurityDescriptor = NULL; 

    CreatePipe(&readOUT, &writeOUT, &saAttr, 0); 
    CreatePipe(&readIN, &writeIN, &saAttr, 0); 

    ZeroMemory(&si, sizeof(si)); 
    ZeroMemory(&pi, sizeof(pi)); 
    GetStartupInfo(&si); 

    si.cb = sizeof(STARTUPINFO); 
    si.hStdError = writeOUT; 
    si.hStdOutput = writeOUT; 
    si.hStdInput = readIN; 
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; 
    si.wShowWindow = SW_HIDE; 

    CreateProcess(NULL, 
       "cmd.exe", 
        NULL, 
        NULL, 
        TRUE, 
        CREATE_NEW_CONSOLE, 
        NULL, 
        NULL, 
        &si, 
        &pi 
       ); 

    while (TRUE) 
    { 
     out = Execute(cmd); 
     printf("%s\n", out); 
     scanf("%s", cmd); 
     strcat(cmd,"\n"); 
    } 
    free(out); 
    return 0; 
} 


char* 
Execute(char* cmd) 
{ 
    DWORD bwritten = 0; 
    DWORD buffersize = 0; 
    int outputsize = 0; 
    DWORD breaden = 0; 
    char* output = NULL; 
    char* buffer = NULL; 
    DWORD n_buffersize; 
    WriteFile(writeIN, cmd, strlen(cmd), &bwritten, NULL); 
    while (TRUE) 
    { 
     Sleep(2000); 
     PeekNamedPipe(readOUT, NULL, NULL, NULL,&buffersize, NULL); 
     n_buffersize = buffersize; 
     if (n_buffersize) 
     { 
      buffer = (char*)malloc(n_buffersize + 1); 
      ZeroMemory(buffer,sizeof(buffer)); 
      ReadFile(readOUT, buffer, n_buffersize, &breaden, NULL); 
     } 
     else 
      break; 

     if (breaden) 
     { 
      outputsize += n_buffersize + 1; 
      output = (char*)realloc(output, outputsize); 
      strcat(output, buffer); 
      free(buffer); 
     } 
    } 
    return output; 
} 
+3

*程序错误并中止*是完全无用的问题说明。您发布的代码具有哪些**特定的问题?调试器告诉你什么时候你通过代码? –

+0

调试器msg:mycmd.exe中的0x77BF62AC(ntdll.dll)的未处理异常:0xC0000374:内存段已损坏(参数:0x77C26480)。已经发生 –

回答

4

如果您有:

buffer = (char*)malloc(n_buffersize + 1); 
ZeroMemory(buffer,sizeof(buffer)); 

注意,最初n_buffersize = 0,所以你只分配1个字节。 但是,您可以将sizeof(char*)字节数(在32位系统上是4个字节,在64位系统上是8个字节)清零。

您可以将您分配的字节数减少到零,即n_buffersize + 1。或者使用calloc()而不是malloc()

0

Execute()内部的内存管理可以简化。使用两个缓冲区,尤其是strcat(),效率不高。但更重要的是,main()中的循环正在泄漏Execute()输出的内存,而不管它如何分配。

您还没有以下有关STD(IN|OUT|ERR)重定向是在MSDN上记录所有的准则:

Creating a Child Process with Redirected Input and Output

也就是说,你继承你不应该继承控点,您不关闭句柄您正在使用cmd.exe正在运行。

尝试一些更喜欢这个:

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

char* Execute(char*); 

HANDLE readIN = NULL; 
HANDLE writeIN = NULL; 
HANDLE readOUT = NULL; 
HANDLE writeOUT = NULL; 

int 
main(int argc, char** argv) 
{ 
    SECURITY_ATTRIBUTES saAttr; 
    STARTUPINFO si; 
    PROCESS_INFORMATION pi; 

    char cmd[256]; 
    char* out = NULL; 
    ZeroMemory(cmd, sizeof(cmd)); 

    ZeroMemory(&saAttr, sizeof(saAttr)); 
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saAttr.bInheritHandle = TRUE; 
    saAttr.lpSecurityDescriptor = NULL; 

    if (!CreatePipe(&readOUT, &writeOUT, &saAttr, 0)) { 
     // error handling... 
    } 
    if (!SetHandleInformation(readOUT, HANDLE_FLAG_INHERIT, 0)) { 
     // error handling... 
    } 

    if (!CreatePipe(&readIN, &writeIN, &saAttr, 0)) { 
     // error handling... 
    } 
    if (!SetHandleInformation(writeIN, HANDLE_FLAG_INHERIT, 0)) { 
     // error handling... 
    } 

    ZeroMemory(&si, sizeof(si)); 
    ZeroMemory(&pi, sizeof(pi)); 

    si.cb = sizeof(STARTUPINFO); 
    si.hStdError = writeOUT; 
    si.hStdOutput = writeOUT; 
    si.hStdInput = readIN; 
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; 
    si.wShowWindow = SW_HIDE; 

    if (!CreateProcess(NULL, 
       "cmd.exe", 
        NULL, 
        NULL, 
        TRUE, 
        CREATE_NEW_CONSOLE, 
        NULL, 
        NULL, 
        &si, 
        &pi 
       )) 
    { 
     // error handling... 

     CloseHandle(readIN); 
     CloseHandle(writeIN); 
     CloseHandle(readOUT); 
     CloseHandle(writeOUT); 
    } 
    else 
    { 
     CloseHandle(pi.hThread); 
     CloseHandle(pi.hProcess); 

     CloseHandle(readOUT); 
     CloseHandle(writeIN); 

     do 
     { 
      if (scanf("%254s", cmd) != 1) 
       break;  
      strcat(cmd,"\n"); 

      out = Execute(cmd); 
      if (!out) { 
       printf("ERROR!\n"); 
       break; 
      } 

      printf("%s\n", out); 
      free(out); 
     } 
     while (TRUE); 

     CloseHandle(writeOUT); 
     CloseHandle(readIN); 
    } 

    return 0; 
}  

char* 
Execute(char* cmd) 
{ 
    DWORD bwritten = 0; 
    DWORD buffersize = 0; 
    int outputsize = 0; 
    DWORD bread = 0; 
    char* buffer = NULL; 
    char* output = NULL; 

    buffersize = strlen(cmd); 
    while (buffersize > 0) 
    { 
     if (!WriteFile(writeIN, cmd, buffersize, &bwritten, NULL)) 
      return NULL; 
     cmd += bwritten; 
     buffersize -= bwritten; 
    } 

    do 
    { 
     Sleep(2000); 
     if (!PeekNamedPipe(readOUT, NULL, NULL, NULL, &buffersize, NULL)) 
      break; 

     if (buffersize == 0) 
      break; 

     buffer = (char*) realloc(output, outputsize + buffersize + 1); 
     if (!buffer) { 
      free(output); 
      return NULL; 
     } 

     output = buffer; 

     if (!ReadFile(readOUT, output + outputsize, buffersize, &bread, NULL)) 
      bread = 0; 

     outputsize += bread; 
     output[outputsize] = '\0'; 
    } 
    while (bread > 0); 

    return output; 
}