为什么我的解析函数没有返回所有预期的令牌?

时间:2017-01-07 14:30:26

标签: c string strtok

我编写了一个程序,它从标准输入中读取命令行,并将其传递给应该将其解析为标记的函数。

这是解析功能:

char** parse_cmdline(char* cmdline) {
    char ** arr = malloc(10 * sizeof(char*));
    for (int i =0 ; i < 10; ++i)
        arr[i] = malloc(30 * sizeof(char));
    char * token = strtok(cmdline, " ");
    int i = 0;
    while(token != NULL) {
        if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*) );
        arr[i] = token;
        token = strtok(NULL, " ");
        i++;
    }
    printf("flag1");
    return arr;
}

这就是我使用它的方式main()

int main() {
    int status;
    pid_t pid;
    pid = fork();

    while(1) {      
        if(pid < 0) {
            status = -1;
            perror("Fork");
        } else if(pid == 0) {
            char* cmd;
            printf("$");
            if(fgets(cmd, sizeof cmd, stdin) == NULL) break;
            parse_cmdline(cmd);
        } else {
            if( waitpid(pid, &status, 0) != pid ) {
                status = -1;
            }
            break;
        }
    }


    return 0;
}

这是我提供给我的程序的输入示例:

ls l a

预期输出应为:

l

(即第二个参数,由我的解析函数打印)

字面上没有任何反应。甚至不是printf(&#34; flag1&#34;);打印。但是如果我删除char ** commands并将printf("%s", commands[0]);放在parse_cmdline函数中,一切都会正常工作,除非我不指定返回。为什么以及如何解决它?

根据要求,这是我的全部代码:

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

char** parse_cmdline(char* cmdline) {
    char ** arr = malloc(10 * sizeof(char*));
    for (int i =0 ; i < 10; ++i)
        arr[i] = malloc(30 * sizeof(char));
    char * token = strtok(cmdline, " ");
    int i = 0;
    while(token != NULL) {
        if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*) );
        arr[i] = token;
        token = strtok(NULL, " ");
        i++;
    }
    printf("%s\n", arr[1]);
    return arr;
}

2 个答案:

答案 0 :(得分:1)

这部分看起来很奇怪 - 见内联评论:

char ** arr = malloc(10 * sizeof(char*));
for (int i =0 ; i < 10; ++i)
    arr[i] = malloc(30 * sizeof(char));     // Here you allocate memory
                                            // for holding a part of the command

char * token = strtok(cmdline, " ");
int i = 0;
while(token != NULL) {
    if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*) );

    arr[i] = token;             // But here you overwrite the pointer value and
                                // and thereby create a memory leak

    token = strtok(NULL, " ");
    i++;
}

也许你想要做一个字符串复制 - 比如:

strcpy(arr[i], token);   // Instead of arr[i] = token;

此行似乎很奇怪:

if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*) );

您增加arr以便它可以容纳更多char*,但这次您不像最初那样为新字符串分配内存。

答案 1 :(得分:0)

首先,您没有为命令分配空间。将cmd的声明更改为以下内容:

char cmd[100];

不分配内存导致未定义的行为,这(以及正确使用fgets修复了这一点)。但是你也应该从fgets()检查100个字符是否足够:

if (strstr(cmd, "\n") == NULL) {
    /* the user typed more than 100 characters */
}

因为如果它们还不够,那么你将解析一个不完整的命令行,下次你的循环遍历输入数据时,它将解析更多不完整的命令。

最后,strtok返回指向 cmd中的标记的指针,因此您在解析函数开头分配的所有字符数组都是内存泄漏,因为您已更换它们来自循环中strtok的指针:

arr[i] = token;
/* this throws away the address of the 10-character array you allocated
 * at the beginning of the function. You can't free() that memory
 * anymore. Your program is "leaking" memory. */

严格地说,顺便说一下,您应该检查realloc是否返回了有效地址或NULLmalloc也是。在这么小的程序中你不太可能遇到这个问题,但这是正确的做法。

使用后,您还应该处理已解析的命令。您分配了一个包含mallocrealloc的指针数组,但您的程序中永远不会free它们。即使程序很快结束,程序运行时,内存也会泄漏。 (同样,你不太可能会看到一个小程序的问题,但这是一个很好的做法。)