C语言 malloc on (char**)



好吧,我正试图用C为linux编写一个shell。使用函数fork()和execl(),我可以执行每个命令,但现在我无法读取参数:

char * command;
char ** c_args = NULL;
bytes_read = getline (&command, &nbytes, stdin);
command = strtok(command, "n ");
int arg = 0;
c_arg = strtok(NULL, "n ");
while( c_arg != NULL ) {
if( c_args == NULL ) {
c_args = (char**) malloc(sizeof(char*));
}
else {
c_args = (char**) realloc( c_args, sizeof(char*) * (arg + 1) );
}
c_args[arg] = (char*) malloc( sizeof(char)*1024 );
strcpy( c_args[arg], c_arg );
c_arg = strtok(NULL, "n ");
arg++;
}
...
pid_t pid = fork()
...
...
execl( <path>, command, c_args, NULL)
...
...

这样,当我试图传递参数时,我会从命令中得到错误,例如:

ls -l

给我:

ls: cannot access p��: No such file or directory

我知道问题出在c_args分配上。它怎么了?

干杯。

不能将execl()用于参数的变量列表;您需要使用execv()或其变体之一(execve()execvp()等)。只有当您知道编译时将出现的所有参数时,才能使用execl()。在大多数情况下,一般的shell不会知道这一点。一个例外是当你做这样的事情时:

execl("/bin/sh", "/bin/sh", "-c", command_line, (char *)0);

在这里,您调用shell来运行一个字符串作为命令行(没有其他参数)。然而,当你在一个完整的外壳中处理人们在键盘上键入的内容时,你将无法奢侈地知道他们在编译时键入了多少参数。

最简单地说,您应该使用:

execvp(c_args[0], c_args);

第零个参数,即命令名,应该是传递给execvp()的参数。如果这是一个简单的文件名(没有/),那么它将在$PATH环境变量的目录中查找该命令。如果命令名包含斜杠,则它将查找指定的(相对或绝对)文件名,如果存在,则执行该文件名;如果不存在,则失败。其他参数都应该在以null结尾的列表c_args中。

现在,还可能存在其他内存分配问题;我没有仔细检查代码。不过,您可以通过诊断打印参数列表来检查它们:

char **pargs = c_args;
while (*pargs != 0)
puts(*pargs++);

它将每个参数打印在单独的一行上。注意,它不会停止,直到它遇到一个空指针;至关重要的是,null终止指向参数字符串的指针列表。

这部分代码:

c_args[arg] = (char*) malloc( sizeof(char)*1024 );
strcpy( c_args[arg], c_arg );

在通常的情况下,这看起来有些过头了,而在极端情况下,内存分配不足。复制字符串时,请分配足够的长度。我看到您正在使用strtok()来分解一个字符串——这对shell的早期版本来说是可行的,但当您处理像ls -l>$tmp这样的命令行时,您会发现strtok()在读取分隔符之前对其进行践踏的倾向成为了一个主要的负担。然而,当你使用它时,你可能不必复制这样的论点;您只需设置c_args[arg++] = result_from_strtok;即可。当您确实需要复制时,您可能应该使用strdup();例如,它不会忘记为后面的''分配足够的空间,既不会过度分配也不会不足分配。

Jonathan有一个很好的答案,我只想再添加一些内容。

可以使用popensystem直接由shell执行。它们通常不受欢迎,因为它们可以很容易地注射,但如果你在写一个开放的外壳,我看不出使用它们有什么害处。

如果您想要一个有限的shell(它接受类似sh的语法),请查看wordexp。它做了很多,但根据我的经验,它做得太多了,尤其是当你试图编写一个适度安全的解释器时(它会做一些愚蠢的事情,比如波浪号扩展和变量替换)。

相关内容

  • 没有找到相关文章

最新更新