在C中从命令行捕获可变长度字符串

在C中从命令行捕获可变长度字符串,c,stdin,C,Stdin,我到处寻找我的问题的答案,但我还没有找到我的问题的可靠答案 我目前正在用C编写一个程序,专门针对UNIX命令行。我使用Linux作为我的开发环境,但我希望这个程序尽可能可移植。现在,我有一个提示用户输入的基本shell。然后,用户将输入一个命令,并相应地处理该命令。以下是我目前掌握的代码: /* Main.c */ int main(int argc, char **argv) { while (TRUE) { display_prompt();

我到处寻找我的问题的答案,但我还没有找到我的问题的可靠答案

我目前正在用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字符,看看它是否适合缓冲区大小,以及它是否没有重新锁定数据以扩展分配的内存


但是,在我重新定义字符串后,我将如何将stdin中的剩余数据添加到命令中?

您不需要执行任何重新定义,只需为\0添加超过最大命令长度的1个字节,然后忘记\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_命令,它是ok的,但若你们想把它返回给调用者,你们将从调用者那个里收到一个缓冲区

您不需要执行任何realloc操作,只需为\0添加超过最大命令长度的1个字节,然后忘记\n,因为您不会在用户键入enter时得到\n。如果用户输入超过长度,则字符串将被截断,而不带\n。因此,您在fgets后的情况是不正确的,并且基于错误的假设

比如:

   int buffer_size = MAX_COMMAND_LENGTH + 1;
关于内存分配:在这种情况下,应该使用堆栈而不是堆来避免malloc/free。因此,您的代码将更简单,更不容易出错:

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

请注意,在函数返回后,您的命令将被释放。所以,若你们将它处理成get_命令,它是ok的,但若你们想把它返回给调用者,你们将从调用者那个里收到一个缓冲区

我认为假设最大命令长度的答案是正确的:通常,您希望将命令保持在合理的长度内

但是,如果您确实无法对命令的最大长度进行假设,那么您需要缓冲区

保持:

一个固定的缓冲区,您总是将相同数量的字符放入其中,并且 附加到的命令,并在必要时使用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);
}
还请注意:

我们在这里不使用命令做任何有用的事情,您可能希望传入一个字符**,这样您就可以从这个函数中获取命令,并在调用代码中释放它,例如在主循环中。 “\n”保留在命令中:您可能希望放弃它。
我认为假设最大命令长度的答案是正确的:通常,您希望将命令保持在合理的长度内

但是,如果您确实无法对命令的最大长度进行假设,那么您需要缓冲区

保持:

一个固定的缓冲区,您总是将相同数量的字符放入其中,并且 附加到的命令,并在必要时使用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);
}
还请注意:

我们在这里不使用命令做任何有用的事情,您可能希望传入一个字符**,这样您就可以从这个函数中获取命令,并在调用代码中释放它,例如在主循环中。 “\n”保留在命令中:您可能希望放弃它。
如果您使用的是gnu系统,请使用c库的,它会为您进行所有的动态调整

e、 虽然我还没有测试

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

如果您使用的是gnu系统,请使用c库的,它会为您进行所有的动态调整

e、 虽然我还没有测试

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

如果确实需要,请使用getline3。这是POSIX.1-2008。并且知道无限长的线是一个简单的攻击向量,用于DoS攻击OOM。因此,考虑制定一个合理的线路长度限制,如果需要的话,使用FGETS3.

< P>使用GETLIL3。这是POSIX.1-2008。并且知道无限长的线是一个简单的攻击向量,用于DoS攻击OOM。因此,考虑制定一个合理的行长度限制,并使用FGETS3../P>看一下这一点——可能有助于记住:在命令行上输入的PARM。/MyExe ARG1 ARG2 ARG3与您可以从STDIN/MyExe < SoMeDATA读取的数据不一样。txt@paulsm4:正式注明。我将更新我的问题以反映这一点。看看这个-可能有助于记住:您在命令行上输入的参数。/myexe arg1 arg2 arg3与您可以从stdin读取的数据不同。/myexe这是一个内置宏吗?还是我必须自己定义?另外,对于原始代码中的条件检查,我知道换行符可能不存在。我使用它作为检查,因为用户每次想要发送命令时都需要按ENTER键。如果换行符不存在,我想扩展字符串以允许添加更多字符。我只是不知道该怎么做。你需要自己定义最大长度,或者如果你愿意的话,输入一个文字。我只是尽可能的清楚,它可能是一个用户定义的宏,至少我从来没有听说过它是内置的。不管怎么说,用户定义更有意义。我也这么认为,但我对C还是很陌生,所以我不知道我是否忽略了像这样简单的东西。另外,为了对上次编辑进行评论,我不希望它存在于堆栈中,因为最终我将把捕获的字符串返回主循环。出于测试目的,它现在返回void。当然,您可以假设最大命令长度,因为您知道或应该知道我们期望的命令。如果您使用的是linux或某些unix,请尝试在bash中获取bash的最大命令长度:getconf ARG_MAXIs command_MAX_length内置宏?还是我必须自己定义?另外,对于原始代码中的条件检查,我知道换行符可能不存在。我使用它作为检查,因为用户每次想要发送命令时都需要按ENTER键。如果换行符不存在,我想扩展字符串以允许添加更多字符。我只是不知道该怎么做。你需要自己定义最大长度,或者如果你愿意的话,输入一个文字。我只是尽可能的清楚,它可能是一个用户定义的宏,至少我从来没有听说过它是内置的。不管怎么说,用户定义更有意义。我也这么认为,但我对C还是很陌生,所以我不知道我是否忽略了像这样简单的东西。另外,为了对上次编辑进行评论,我不希望它存在于堆栈中,因为最终我将把捕获的字符串返回主循环。出于测试目的,它现在返回void。当然,您可以假设最大命令长度,因为您知道或应该知道我们期望的命令。如果您正在使用linux或某些unix,请尝试在bash中获取bash的最大命令长度:getconf ARG_MAXHuh,我认为它还不是POSIX标准。令人惊叹的这让我的生活轻松多了!非常感谢。哈,我还没想到这是POSIX标准。令人惊叹的这让我的生活轻松多了!非常感谢。