我到处寻找我的问题的答案,但我还没有找到解决问题的可靠答案。
我目前正在用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()
数据来扩展分配的内存。< / p>
但是,在我realloc()
我的字符串后,如何将stdin
中的剩余数据添加到command
?
答案 0 :(得分:5)
如果确实需要,请使用getline(3)。这是POSIX.1-2008。请注意,无限长度行是DOS攻击(OOM)的简单攻击向量。因此,请考虑使用fgets(3)来构成合理的行长度限制。
答案 1 :(得分:2)
你不需要做任何realloc,只需要为\ 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_command就可以了,但是如果你想将它返回给调用者你将从调用者那里收到一个缓冲区。
答案 2 :(得分: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
并释放它在调用代码中,例如在你的主循环中。command
中:您可能想放弃它。答案 3 :(得分:2)
如果您使用的是gnu系统,请使用gnu getline
extension到c库,它会为您完成所有动态调整。
e.g。 (虽然我没有测试过)
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);
}