簡體   English   中英

嘗試在UNIX中通過用戶輸入使用C中的execvp()

[英]Trying to use execvp() in C with user input in unix

我正在嘗試制作一個程序,該程序將提示用戶輸入命令,然后使用exec執行該命令。

例如,如果他們給我“ ls -la”,我將必須執行該命令。 我嘗試了以下代碼:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{

    int ret, num_args;

    printf("Enter number of arguments (Example: \"ls -la\" has 1 argument): ");
    scanf("%d", &num_args);

    char *cmd[num_args];

    printf("Enter command name: ");
    scanf("%s", &cmd[0]);

    int i;
    for (i = 0; i < num_args; i++)
    {
            printf("Enter parameter: ");
            scanf("%s", &cmd[i]);
    }

    execvp(cmd[0], cmd);
}

但是,當我嘗試以下運行時,它給了我一個“分段錯誤”

$ ./a.out 
Enter number of arguments (Example: "ls -la" has 1 argument): 2
Enter command name: ls
Enter parameter: -la
Enter parameter: .
Segmentation fault
$

有任何想法嗎?

您需要為字符串分配內存。 以下行僅分配了num_args char指針:

char *cmd[num_args];

首先,您將獲得num_args + 1字符串(不要忘記命令本身是cmd[0] )。 最簡單的方法是將內存靜態分配為字符緩沖區數組:

const unsigned int MAX_LEN = 512; // Arbitrary number
char cmd[num_args + 1][MAX_LEN];

但是,現在您不能使用scanf讀取行,因為用戶可以輸入比字符緩沖區長的字符串。 相反,您必須使用fgets ,它可以限制用戶可以輸入的字符數:

fgets(cmd[i], MAX_LEN, stdin);

請記住, fgets還會讀取換行符,因此請確保刪除出現的所有雜散字符(但不要假定它們在那里)。

如果您的實現支持它,則應該在scanf()fgets()上使用更安全的getline() fgets() getline()將安全地處理長行和NULL字符。 它將分配足夠的內存以適合整行。 getline()可以分配內存,因此稍后您必須自己釋放內存。

這是glibc getline()文檔

這是使用getline的快速修改方法(它仍然需要工作,進行錯誤檢查,並且我還沒有完全檢查它的正確性):

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{

    printf("Enter number of arguments (Example: \"ls -la\" has 1 argument): \n");

    char *num = NULL;
    size_t sz = 0;
    getline(&num, &sz, stdin);

    int num_args;
    sscanf(num, "%d", &num_args);

    char *cmd[num_args+2];
    memset(cmd, 0, sizeof(char*) * (num_args+2));

    printf("Enter command name: \n");


    int len = getline(&cmd[0], &sz, stdin); 

    cmd[0][len-1] = '\0';

    int i;
    for (i = 1; i < num_args+1; i++)
    {
        printf("Enter parameter: \n");
        sz = 0;
        len = getline(&cmd[i], &sz, stdin);
        cmd[i][len-1] = '\0';
    }

    return execvp(cmd[0], cmd);

}

另外,您還需要在傳遞給execvpargv另一個條目,該條目必須為(char *)NULL才能使其知道已到達列表的末尾。

您實際上並未為cmd數組所指向的字符串分配任何內存。

看一下scanf()的手冊頁。 它可以做的最巧妙的事情之一是自動動態分配字符串緩沖區,您需要提供一個指向字符串的指針,而不是僅僅傳遞字符串並提供%as格式。

char *my_string;
scanf("%as", &my_string);

這樣,您就不必為預分配而煩惱,也不必為緩沖區溢出而煩惱,等等。只需記住在完成操作后將其釋放()即可。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM