用C语言标记用户输入(存储在** arg中)?

时间:2013-02-22 01:42:05

标签: c pointers tokenize argv getc

我正在尝试编写一个类似于接口的简单shell,它接受用户输入(通过char)并通过指向指针*的指针存储它(确切地说argv是如何工作的)。这是我的代码:

char input[100];
char **argvInput;
char ch;
int charLoop = 0;
int wordCount = 0;

argvInput = malloc(25 * sizeof(char *));

while((ch = getc(stdin))) {
    if ((ch == ' ' || ch == '\n') && charLoop != 0) {
        input[charLoop] = '\0';
        argvInput[wordCount] = malloc((charLoop + 1) * sizeof(char));
        argvInput[wordCount] = input;
        charLoop = 0;
        wordCount++;

        if (ch == '\n') {
            break;
        }

    } else if (ch != ' ' && ch != '\n') {
          input[charLoop] = ch;
          charLoop++;
        } else {
            break;
        }
    }

如果我通过:

循环遍历argvInput
int i = 0;
for (i = 0; i < wordCount; i++)
    printf("Word %i: %s\n", i, argvInput[i]);

argvInput [i]的所有值都是最后一次输入赋值。所以,如果我输入: “快乐的日子即将来临”,循环的输出是:

Word 0: soon
Word 1: soon
Word 2: soon
Word 3: soon
Word 4: soon

我很茫然。很明显,每个循环都会覆盖之前的值,但我正盯着屏幕,无法弄清楚原因......

3 个答案:

答案 0 :(得分:4)

这条线是你的祸根:

    argvInput[wordCount] = input;

如果您要用另一个替换指针(即input),则分配新空间无关紧要。

相反,使用strncpyinput的部分内容提取到argvInput[wordCount]

答案 1 :(得分:2)

argvInput[wordCount] = input;仅使argvInput[wordCount]的指针指向input的内存,而不是将输入内容复制到新分配的内存中。您应该使用memcpy或strcpy来更正您的程序。

指针分配后,内存状态如下图所示。由malloc((charLoop + 1) * sizeof(char));分配的内存(图中为灰色内存)无法再被您的程序访问,这将导致内存泄漏问题。请注意这一点。

enter image description here

答案 2 :(得分:0)

我建议使用%p而不是%s打印argvInput指针来识别此问题:printf("Word %i: %p\n", i, (void *) argvInput[i]);

你对它打印的价值有什么看法?这与argv的行为有何不同?尝试打印argv:for (size_t x = 0; x < argc; x++) { printf("Word %zu: %p\n", x, (void *) argv[x]); }

的指针

现在您已经发现了问题,解释它可能会变得更容易。

此代码分配内存,并在argvInput [wordCount]中存储指向该内存的指针:argvInput[wordCount] = malloc((charLoop + 1) * sizeof(char));(顺便说一下,sizeof char 总是 1在C中,所以你是不必要地乘以1。

此代码用指向输入的指针替换指向已分配内存的指针:argvInput[wordCount] = input; ...因此,所有项目都包含指向同一数组的指针:输入,并且因为丢失引用而导致分配的内存泄漏它。显然,这是有问题的路线;它没有按照你最初的想法做到。

有人建议您使用strdup调用替换malloc调用,并删除有问题的行。我不喜欢这个建议,因为strdup不符合C标准,因此不需要存在。

strncpy会起作用,但它不必要地复杂。 strcpy保证也能正常工作,因为目标数组的大小足以存储字符串。因此,我建议用strcpy(argvInput[wordCount], input);替换有问题的行。

另一个未详细解释的选项是strtok。现在看来这是最好的,因为它需要对你的代码进行太多的修改。

我有一个用这个代码挑选的骨头:char ch; ch = getc(stdin);错了。 getc返回一个int是有原因的:任何成功的字符读取都将以unsigned char值的形式返回,该值不可能是负数。如果getc遇到EOF或错误,它将返回负值。将返回值分配给ch后,如何区分错误和成功?

如果第一个角色是'',你有没有想过会发生什么?目前,您的代码将突破循环。如果您的代码是模仿常见的argv解析行为,这似乎是一个错误。调整此代码以解决您的问题可能是一个好主意:

for (int c = getc(stdin); c >= 0; c = getc(stdin)) {
    if (c == '\n') {
        /* Terminate your argv array and break out of the loop */
    }
    else if (c != ' ') {
        /* Copy c into input */
    }
    else if (charLoop != 0) {
        /* Allocate argvInput[wordCount] and copy input into it,
         * reset charLoop and increment wordCount */
    }
}