捕获来自在C命令行的可变长度的字符串(Capturing a variable length str

2019-06-26 23:29发布

我到处找一个回答我的问题,但我还没有找到一个坚实的回答我的问题。

我目前在用C编写一个程序,专门针对UNIX命令行的过程中(我使用Linux作为我的开发环境,但我想这个计划,以尽可能便携式)。 现在,我有一个提示用户输入一个基本的shell。 然后,用户将在一个命令输入,并且该命令将被相应地处理。 这里是我到目前为止的代码:

/* 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

Answer 1:

使用函数getline(3)如果你真的需要。 这是POSIX.1-2008。 而且要知道,无限长度线是DOS攻击(OOM)一个简单的攻击向量。 因此,考虑制定一个合理的线路长度的限制,并使用与fgets(3)。



Answer 2:

我想假设最大命令长度的答案是正确的:通常你要保持一个合理的长度内的命令。

但如果你真的不能对命令的最大长度的假设,那么你就需要缓冲。

保持:

  • 一个固定的buffer ,你总是fgets相同数目的字符进去,
  • 一个command ,你追加到,和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 :你可能想要放弃。


Answer 3:

你不需要做任何的realloc,只需添加1个字节超过最大命令长度多为\ 0,而忘记\ N,因为你不会得到一个\ n始终在用户类型输入。 如果用户输入超过长度那么你的字符串将是无\ n截断。 因此,与fgets后你的条件是不正确的,总部设在一个错误的假设。

就像是:

   int buffer_size = MAX_COMMAND_LENGTH + 1;

关于内存分配:你应该使用堆栈,而不是堆避免这种情况下的malloc /免费。 所以,你的代码会更简单,更容易出错:

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

请注意,您的命令将在函数返回时被释放。 所以,如果你将其处理成GET_COMMAND其确定,但如果你希望它返回到呼叫者你们从主叫接收缓冲区。



Answer 4:

如果您使用的是GNU系统,请使用GNU getline延伸到C库,它所有的动态调整大小为您服务。

例如,(虽然我没有测试过)

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);
}


文章来源: Capturing a variable length string from the command-line in C
标签: c stdin