我正在尝试创建一个程序,提示用户输入命令,然后使用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
$
有什么想法吗?
答案 0 :(得分: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
也会读取换行符,因此请务必删除所有出现的错误字符(但不要假设它们存在)。
答案 1 :(得分:3)
如果您的实施支持,则应使用更安全的getline()
代替scanf()
或fgets()
。 getline()
将安全地处理长行和NULL字符。它将分配足够的内存以适应整条线路。 getline()
可以分配内存,因此您必须在以后自行释放内存。
这是glibc getline()
documentation。
这是使用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);
}
答案 2 :(得分:2)
此外,您需要在传递给argv
的{{1}}中再输入一个条目,该条目必须为execvp
才能让它知道它已到达列表末尾。
答案 3 :(得分:1)
您实际上没有为cmd数组指向的字符串分配任何内存。
答案 4 :(得分:-1)
查看scanf()的手册页。它可以做的最重要的事情之一就是自动分配字符串缓冲区,你需要提供一个指向字符串的指针,而不是只传递字符串并提供%作为格式。
char *my_string;
scanf("%as", &my_string);
然后你不需要打扰预分配,不需要打扰缓冲区溢出等等。只需记住在你完成它之后释放()它。