C语言 在分析由管道(|)

eivgtgni  于 2023-04-19  发布在  其他
关注(0)|答案(1)|浏览(132)

我正在用C写一个shell。这个shell max接收并执行由20个管道分隔的命令(|)。这些命令运行得很顺利,但是当我用Valgrind进行内存检查时,我得到的输出如下:

==64422== HEAP SUMMARY:
==64422==     in use at exit: 24 bytes in 1 blocks
==64422==   total heap usage: 9 allocs, 13 frees, 4,156 bytes allocated
==64422== 
==64422== 24 bytes in 1 blocks are definitely lost in loss record 1 of 1
==64422==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==64422==    by 0x491260E: strdup (strdup.c:42)
==64422==    by 0x1098C5: split_commands (in /home/furkan/Masaüstü/hw02/my)
==64422==    by 0x109C93: main (in /home//Masaüstü/hw02/my)
==64422== 
==64422== LEAK SUMMARY:
==64422==    definitely lost: 24 bytes in 1 blocks
==64422==    indirectly lost: 0 bytes in 0 blocks
==64422==      possibly lost: 0 bytes in 0 blocks
==64422==    still reachable: 0 bytes in 0 blocks
==64422==         suppressed: 0 bytes in 0 blocks
==64422== 
==64422== For lists of detected and suppressed errors, rerun with: -s
==64422== ERROR SUMMARY: 11 errors from 8 contexts (suppressed: 0 from 0)

在这部分代码中,我解析了用管道分隔的命令(|).然后我删除了在开始时发现的间隙,并以strtrim结束。Valgrind说这部分存在内存泄漏。然而,我无法弄清楚为什么strdup()函数会产生内存泄漏以及如何阻止此泄漏。

char *strtrim(char *str) {
char *end;

// Trim leading space
while (isspace(*str)) {
    str++;
}

if (*str == 0) {  // All spaces?
    return str;
}

// Trim trailing space
end = str + strlen(str) - 1;
while (end > str && isspace(*end)) {
    end--;
}

// Write new null terminator
*(end+1) = 0;

return str;
}

void split_commands(char *input, char **commands, int *num_commands) {
    int count = 0;
    const char delimiter[] = "|";
    char *token;
   

    // Count the number of commands
    for (int i = 0; input[i]!= '\0'; i++) {
        if(input[i] == '|')
           count++;
    }
    *num_commands = count + 1;

   

    // Split input into commands
    token = strtok(input, delimiter);
    for (int i = 0; i < *num_commands; i++) {
        (commands)[i] = strtrim(strdup(token));

        token = strtok(NULL, delimiter);
    }
}
2w2cym1i

2w2cym1i1#

另一种方法是“就地编辑”字符串缓冲区以不更改指针值。
下面是你的函数的一个替代:

char *strtrim( char *str ) {
    char *d = str, *s = str;

    // Trim leading space
    while( isspace(*s) ) s++;

    // copy
    while( ( *d = *s++ ) != '\0' ) d++;

    // trim trailing space
    while( d > str && isspace( d[-1] ) ) *--d = '\0';

    return str;
}

你可以决定这是否变成void strtrim() ...
而且,你可以节省对字符串进行标记的代码:

// Split input into commands
    for( char *cp = input; ( cp = strtok(cp, "|") ) != NULL; cp = NULL )
        commands[i] = strtrim(strdup(cp));

有很多人相信**commands足够大,可以存储所有的指针,也许你可以考虑使用链表而不是数组来存储每个子字符串。

相关问题