我是C的新手,我一直在Fedora中测试我的程序,使用gcc和gdb进行调试。我有一个程序,可以从用户那里获取输入。如果输入的第一个字符串是“create”,那么我看看第二个命令,如果那是“对象”,那么我将继续使用createObject函数。
希望我的代码能让这一点更加清晰:
static void parseCmd(char **input) {
if(!strcmp(input[0], "create")) {
if(!strcmp(input[1], "object")) {
if(input[2] && strcmp(input[2], ""))
createObject(input[2]);
else
printf("Object needs a name\n");
}
else
printf("Command needs more parameters\n");
}
else
printf("Command not recognized\n");
}
当我测试只输入“创建对象”(对象之后没有空格,只有ENTER键)
在Linux中,它打印“对象需要名称”
但在Windows中程序崩溃,它只是挂起。我怎么能改变代码使其行为与在Linux中的行为相同?
答案 0 :(得分:3)
您的代码中包含:
if(input[2] && strcmp(input[2], ""))
显然是在尝试检测input[2]
是否存在而非空。
但是,这不起作用。没有承诺缺少第三个参数会使input[2]
为NULL或""
。
input[2]
此时可能会有垃圾值,但垃圾仍然会通过您的测试!
你有几个方法可以解决它
或者,此函数的调用者需要保证未设置为有效数据的元素将被设置为零/零。
或者,我更喜欢的方法,您将函数签名更改为某些内容像这样:
static void parseCmd(char **input, int num_inputs);
并将输入数与输入数组一起传递。
答案 1 :(得分:2)
您在此行中遇到问题:
if(input[2] && strcmp(input[2], ""))
你测试中的输入[2] 不存在"创建对象",它解释了它崩溃的原因。
希望得到这个帮助。
问候。
答案 2 :(得分:1)
您已进入潜在访问冲突或未定义行为的领域(以及未定义的值):
input[2] && strcmp(input[2], "")
如果input
的长度仅为2,那么这是读取超过可接受的读数点。最糟糕的情况是这将导致段错(如Windows所做),最好的情况是操作系统会让它发生,你会得到一个随机值。 (Linux似乎将它或* input [2]视为0。)
无论如何,不是阅读你不允许访问的内容,而是传入输入的长度并检查它。
static void parseCmd( char **input, size_t num) { //or just int if size_t isn't already defined
//compare num
}
- 编辑 -
正如Daniel Fischer所指出的,显然argv[argc]
确实是一个有效的读取,并且它保证是一个空指针。
假设您确实将argv
传递给函数,这意味着您可以依赖此行为。你的另外两个if语句不会检查这个,并且为了概括函数,它仍然更好地传递长度(或者,正如paulsm4所说,你应该查看getopt函数 - 它使得parses参数更多比滚动自己的解析方法更容易。)
答案 3 :(得分:1)
你先生正在打击你无法击中的记忆。
我推荐你
How to check if a pointer is valid?
任何想知道他如何传递信息的人:
int main(void)
{
char* values[] = {"1", "2", "3"};
parseCmd(values);
}
当你试图访问输入[2]时会发生这种情况,但是如果你不知道你正在接受什么,它就会发生。当你得到输入时我会建议进行健全性检查。如果他们没有把任何东西放在值[2]中,让你的功能意识到这一点或改变它处理它的方式。使用指针和指针指针,在分配值时,不能忽视完整性检查。