3

ユーザーにコマンドを要求し、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
$

何か案は?

4

5 に答える 5

3

文字列にメモリを割り当てる必要があります。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。そのため、表示される迷子になっているものは必ず削除してください (ただし、そこにあるとは限りません)。

于 2009-08-24T00:39:52.613 に答える
3

実装がそれをサポートしている場合は、より安全なonまたはのgetline()代わりに使用する必要があります。 長い行と NULL 文字を安全に処理します。行全体に収まる十分なメモリを割り当てます。 メモリを割り当てることができるので、後で自分で解放する必要があります。scanf()fgets()getline()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);

}
于 2009-08-24T00:59:18.453 に答える
2

また、リストの最後に到達したことを知らせるために、 argvyou pass toにもう 1 つのエントリが必要です。execvp(char *)NULL

于 2009-08-24T00:37:00.647 に答える
1

cmd 配列が指す文字列に実際にはメモリを割り当てていません。

于 2009-08-24T00:27:22.280 に答える
-1

scanf() の man ページを見てください。実行できる最も優れた機能の 1 つは、文字列バッファーをオンザフライで自動的に割り当てることです。文字列を渡すだけでなく、文字列へのポインターを指定して %as 形式を指定する必要があります。

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

次に、事前割り当てを気にする必要はなく、バッファオーバーフローなどを気にする必要もありません。作業が終わったら、忘れずに free() してください。

于 2009-08-24T04:32:47.487 に答える