首先,我需要用system()执行两个命令,例如,我收到一个字符串并用文本编辑器打开这个字符串,如下所示:
$ ./myprogram string1
输出应该是这样的命令:
$ vim string1
但是,我找不到像这个伪代码那样做的方法:
system("vim %s",argv[1]); //Error:
test.c:23:3: error: too many arguments to function 'system'
system("vim %s",argv[1]);
因此,我的解决方案是将argv [1]存储在已经用四个字符初始化的char数组中,如下所示:
char command[strlen(argv[1])+4];
command[0] = 'v'; command [1] = 'i'; command[2] = 'm'; command[3] = ' ';
将argv [1]分配给我的新char数组:
for(int i = 0; i < strlen(argv[1]) ; i++)
command[i+4] = argv[1][i];
最后:
system(command);
但是,如果给我的程序的参数少于3个字符,它的工作正常,但如果没有,我不期望的一些奇怪的字符出现在输出中,如下所示:
./myprogramg 1234
输出是:
$ vim 12348�M�
我该如何解决这个错误,为什么会这样?
完整的代码是:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc,char **argv) {
char command[strlen(argv[1])+4];
command[0] = 'v'; command [1] = 'i'; command[2] = 'm'; command[3] = ' ';
for(int i = 0; i < strlen(argv[1]) ; i++)
command[i+4] = argv[1][i];
system(command);
return 0;
}
答案 0 :(得分:4)
您需要NUL
终止您的C风格字符串,其中包括分配足够的内存来保存NUL
。
你的数组是一个字节短(必须char command[strlen(argv[1])+4+1];
为NUL
留出空间),你应该只使用像sprintf
这样的东西来填充它,例如:
sprintf(command, "vim %s", argv[1]);`
这比手动循环更简单,它也为你填写NUL
。
你看到的垃圾是由于搜索NUL
字节(终止字符串)而导致在缓冲区之后发生的不相关(和未定义的)内存引起的。
答案 1 :(得分:3)
您遇到问题的原因是您没有使用command
终止NULL
字符串。但你真的想用sprintf
(甚至更好地使用snprintf
)来做这样的事情。它与printf
的工作方式类似,但输出到内存而不是stdout
,并为您处理终止NULL
。 E.g:
char cmd[80];
snprintf(cmd, 80, "vim %s", argv[1])
system(cmd);
正如@VTT指出的那样,这个简化的代码假定argv[1]
中的值小于75个字符(对于“vim”,减去4减去4,对于NULL字符减去1)。一个更安全的选择是首先验证这个假设,如果不是这样,则抛出错误。为了更灵活,您可以动态分配cmd
缓冲区:
char *cmd = "vim ";
char *buf = malloc(strlen(argv[1]) + strlen(cmd) + 1);
sprintf(buf, "%s%s", cmd, argv[1]);
system(buf);
free(buf);
当然你也应该检查以确保argc&gt; 1。
答案 2 :(得分:0)
我知道这里已经有了很好的答案,但我想稍微扩展一下。
我经常看到这种代码
system("vim %s",argv[1]); //Error:
初学者经常想知道,为什么这不起作用。
原因是"%s", some_string
不是C的一个功能
语言,字符序列%s
没有特殊含义,实际上它是
与序列mickey mouse
一样有意义。
这与printf
(和其他成员)一起使用的原因
printf
- 家庭)是因为printf
被设计为来替换像
%s
,其值作为参数传递。使printf
特殊的%s
,
不是C语言。
正如您可能已经注意到的那样,"hallo" + " world"
没有做字符串
级联。 C没有像C ++那样的本机字符串类型
std::string
或Python String
。在C中,字符串只是一个序列
碰巧在末尾有一个值为0的字节的字符(也称为
'\0'
- 终止字节。)
这就是为什么你传递printf
格式作为第一个参数的原因。它说
printf
除非找到%
,否则应逐个字符打印,
告诉printf
下一个字符 1 是特殊的
必须用作为printf
的后续参数传递的值替换它们。
%x
被称为转化说明符和documentation of printf
将列出所有这些以及如何使用它们。
scanf
家族等其他功能使用了类似的策略,但并非如此
意味着C中所有期望字符串的函数都将以相同的方式工作。在
事实上绝大多数期望字符串的C函数都不起作用
方式。
man system
#include <stdlib.h> int system(const char *command);
在这里,您可以看到system
是一个只需要一个参数的函数。
这就是你的编译器抱怨这样一行的原因:system("vim %s",argv[1]);
。
那些像sprintf
或snprintf
这样的功能可以派上用场。
1 如果您查看printf
文档,您会看到它
转换说明符和长度修饰符可以长于1
字符。
答案 3 :(得分:-1)
您需要处理缓冲区分配,不要忘记终止null:
char const * const psz_original_command = argv[1];
size_t const original_command_length = strlen(psz_original_command);
char const * const psz_prefix = "vim ";
size_t const prefix_length = strlen(psz_prefix);
char * new_command = (char *) malloc(prefix_length + original_command_length + 1); /* +1 for terminating null */
if(new_command)
{
memcpy(new_command, psz_prefix, prefix_length);
memcpy(new_command + prefix_length, psz_original_command, original_command_length + 1); /* +1 for terminating null */
system(new_command);
free(new_command);
new_command = NULL;
}
return 0;