1

私は自分の質問に対する答えをどこでも探しましたが、私の問題に対する確かな答えはまだ見つかりません。

私は現在、特にUNIXコマンドラインを対象にCでプログラムを作成中です(開発環境としてLinuxを使用していますが、このプログラムを可能な限り移植可能にしたいと考えています)。現在、ユーザー入力を求める基本的なシェルがあります。次に、ユーザーがコマンドを入力すると、そのコマンドがそれに応じて処理されます。これが私がこれまでに持っているコードです:

/* Main.c */
int main(int argc, char **argv)
{
    while (TRUE)
    {
        display_prompt();
        get_command();
    }

    return 0;
}

/* Main.h */
void get_command()
{
    /*
     * Reads in a command from the user, outputting the correct response
     */

    int buffer_size = 20;   
    char *command = (char*) malloc(sizeof(char) * buffer_size);

    if (command == NULL)
    {
       return_error("Error allocating memory");
    }

    fgets(command, buffer_size, stdin);
    if (command[strlen(command) - 1] == '\n')
    {
        puts("It's inside the buffer.");
    }
    else
    {
        puts("It's not inside the buffer.");
    }

    free(command);
}

私の最初の考えは、\n文字をチェックして、それがの中に収まるかどうか、そして割り当てられたメモリを拡張するためのデータが収まらないかどうかを確認buffer_sizeすることでした。realloc()

ただし、文字列を入力した後、残りのデータをにrealloc()追加するにはどうすればよいですか?stdincommand

4

4 に答える 4

5

本当に必要な場合は、getline(3)を使用してください。POSIX.1-2008です。また、無制限の長さの行は、DOS攻撃(OOM)の簡単な攻撃ベクトルであることに注意してください。したがって、適切な行の長さの制限を作成し、fgets(3)を使用することを検討してください。

于 2012-08-11T21:02:39.660 に答える
2

再割り当てを行う必要はありません。\0の最大コマンド長より1バイト多く追加し、\nを忘れてください。\n常にユーザータイプを入力すると\n取得されないためです。ユーザー入力が長さを超える場合、文字列は\nなしで切り捨てられます。したがって、fgetsの後の状態は正しくなく、間違った仮定に基づいています。

何かのようなもの:

   int buffer_size = MAX_COMMAND_LENGTH + 1;

メモリ割り当てについて:この場合、malloc / freeを避けて、ヒープの代わりにスタックを使用する必要があります。したがって、コードはより単純になり、エラーが発生しにくくなります。

    char command[buffer_size];
    ...
    // free(command) <-- you dont need this anymore

関数が戻った後、コマンドが解放されることに注意してください。したがって、get_commandに処理する場合は問題ありませんが、呼び出し元に返したい場合は、呼び出し元からバッファーを受け取ります。

于 2012-08-11T20:17:02.807 に答える
2

コマンドの最大長を想定することについての答えは正しいと思います。通常、コマンドを妥当な長さの範囲内に収めたいと思うでしょう。

ただし、コマンドの最大長について実際に推測できない場合は、バッファリングする必要があります。

保つ:

  • buffer常にfgets同じ数の文字を入力するように修正されました。
  • command追加するa 、およびrealloc必要に応じて。

次のコードには、おそらくエラー処理が欠けています。

#define BUFFER_SIZE 20
#define COMMAND_BLOCK_SIZE 50

void get_command()
{
    char *buffer = malloc(sizeof(char) * (BUFFER_SIZE + 1));

    char *command = malloc(sizeof(char) * (COMMAND_BLOCK_SIZE + 1));
    int commandSize = 50;

    // tmp pointer for realloc:
    char *tmp = NULL;
    char *retval = NULL;

    if ((buffer == NULL) || (command == NULL))
        return_error("Error allocating memory");

    retval = fgets(buffer, BUFFER_SIZE, stdin);

    while (retval != NULL)
    {
        if (strlen(buffer) + strlen(command) > commandSize)
        {
            tmp = realloc(command, commandSize + (COMMAND_BLOCK_SIZE + 1));
            if (tmp == NULL)
                return_error("Error allocating memory");
            else
            {
                 command = tmp;
                 commandSize += COMMAND_BLOCK_SIZE;
            }
        }

        // not using strncat because the check above should guarantee that
        //    we always have more than BUFFER_SIZE more bytes in command 
        strcat(command, buffer);

        if (buffer[strlen(buffer) - 1] == '\n')
            break;

        retval = fgets(buffer, BUFFER_SIZE, stdin);
    }

    printf("COMMAND: %s\n", command);
    free(buffer);
}

また、次の点にも注意してください。

  • ここでは何も役に立ちません。おそらく、この関数から抜け出して、呼び出し元のコード(メインループなど)で解放できるようcommandに、を渡してください。char **command
  • '\ n'が保持されcommandていること:それを破棄することをお勧めします。
于 2012-08-11T20:40:55.997 に答える
2

gnuシステムを使用している場合は、cライブラリのgnugetline拡張機能を使用すると、すべての動的サイジングが自動的に行われます。

例(私はテストしていませんが)

void get_command()
{
    /*
     * Reads in a command from the user, outputting the correct response
     */

    size_t buffer_size = 0;   
    char *command = NULL;

    ssize_t len = getline(&command, &buffer_size, stdin);

    if(len < 0)
    {
        perror("Error reading input");
    }
    else if (command[len - 1] == '\n')
    {
        puts("It's inside the buffer.");
    }
    else
    {
        puts("It's not inside the buffer.");
    }

    free(command);
}
于 2012-08-11T20:55:06.593 に答える