2017-03-09 106 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; 
}