2

我是 C 的新手,我一直在 Fedora 中测试我的程序,使用 gcc 和 gdb 进行调试。我有一个接受用户输入的程序。如果输入的第一个字符串是“create”,那么我看一下第二个命令,如果那是“object”,那么我继续执行 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 中的行为方式相同?

4

4 回答 4

3

你有代码说:

if(input[2] && strcmp(input[2], ""))

显然试图检测是否input[2]存在而不是空的。

但是,这行不通。没有保证缺少第三个参数将使input[2]NULL 或"".

input[2]那时可能会有一个垃圾值,但垃圾仍然会通过你的测试!

您有几个选项可以修复它。
要么,此函数的调用者需要保证未设置为有效数据的元素将改为设置为零/nil。

或者,我更喜欢的方法,您将函数签名更改为如下所示:

static void parseCmd(char **input, int num_inputs);

并将输入的数量与输入数组一起传递。

于 2012-08-03T21:55:49.000 回答
2

你在这一行有问题:

if(input[2] && strcmp(input[2], ""))

您测试中的input[2]不存在“创建对象”,这就是它崩溃的原因。

希望这有帮助。

问候。

于 2012-08-03T21:55:27.637 回答
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 函数-它使解析参数很多比滚动你自己的解析方法更容易)。

于 2012-08-03T21:55:14.653 回答
1

先生,您正在击中您无法访问的内存。

我推荐你

如何检查指针是否有效?

任何想知道他如何传递东西的人:

int main(void) 
{ 
    char* values[] = {"1", "2", "3"};
    parseCmd(values);
} 

当您尝试访问输入时会发生这种情况[2],但如果您不知道自己在接受什么,它可能随时发生。我建议您在获取输入时进行健全性检查。如果他们没有在 values[2] 中添加任何内容,请让您的函数意识到这一点或改变它处理它的方式。使用指针和指向指针的指针,您在分配值时不能忽略完整性检查。

于 2012-08-03T22:13:56.667 回答