如何在C语言中清除数组指针?

3
我正在尝试使用系统调用进行基本的bash,但是我在指针数组方面遇到了一些小问题。
简要概括我的代码,我使用read()从stdin读取命令到缓冲区,然后使用strsep()将命令与参数以及所有参数分离成一个数组。然后我使用fork()创建一个新进程,并使用execvp()执行该命令和相关参数。
所有这些都进入一个无限循环,直到用户键入“quit”(尚未编码)。问题是,在第一次迭代之后,我需要*pArgs为空,以便进行下一个命令和参数。而我不知道该怎么做......
以下是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv) {
    char bBuffer[BUFSIZ], *pArgs[10], *aPtr = NULL, *sPtr;
    int aCount;
    pid_t pid;

    while(1) {
        write(1, "\e[1;31mmyBash \e[1;32m# \e[0m", 27);
        read(0, bBuffer, BUFSIZ);

        sPtr = bBuffer;
        aCount = 0;

        do {
            aPtr = strsep(&sPtr, " ");
            pArgs[aCount++] = aPtr;
        } while(aPtr);

        pArgs[aCount-2][strlen(pArgs[aCount-2])-1] = '\0';

        // Debug code to output pArgs content
        write(1, "|>", 2);
        write(1, pArgs[0], strlen(pArgs[0]));
        write(1, "<|", 2);

        if(strlen(pArgs[0]) > 1) {
            pid = fork();

            if(pid == -1) {
                perror("fork");
                exit(1);
            }

            if(pid == 0) {
                execvp(pArgs[0], pArgs);
                exit(0);
            }
        }
    }

    return 0;
}

P.S:很抱歉目前无法提供输入和输出测试用例。希望这不是太难理解和修复,您们不需要它。如果需要的话,我稍后会发布。

仅为澄清:
我知道我曾经询问如何清除数组,并且我得到了答案。但现在我明显意识到我的问题并不在于此,而是在于缓冲区收集的垃圾,正如litb所指出的。使用空字符终止字符串比清除数组更有意义。这就是为什么我将litb的答案标记为正确答案的原因。

2个回答

9
int i;
for (i = 0; i < 10; i++)
   pArgs[i] = NULL;

2
我用memset()回答了,然后删除了我的答案,因为很难解释为什么在这种情况下sizeof(pArgs) 是可以的,但在另一种情况下可能不合适(例如当pArgs的类型是char**时)。'for'循环加1,memset在这种情况下减1。 - undefined
你应该把它留下来。当速度成为问题时,memset仍然是正确且更好的选择。(参见:http://www.cppreference.com/wiki/c/string/memset)一个不错的编译器可能会将这个循环优化为memset。 - undefined
2
我同意,最好移除memset。它并不总是正确的。循环总是有效的。如果你知道空指针由空字节组成,你可以这样做,但绝对不会在那个shell中注意到速度差异! - undefined
1
没有保证memset()会将指针的表示设置为NULL。"ptr = NULL;"与"memset(&ptr, 0, sizeof(ptr))"不是同一回事。 - undefined
我刚刚重新阅读了C FAQ,Dingo似乎是对的。虽然NULL必须等于((void *)0),但“零指针”的位模式可能与“零整数”的不同。我将删除memset,因为在某些体系结构上无效。 - undefined

3

您的问题在于读取数据后没有添加空字符。因此,strsep调用不知道在哪里停止。在C中,字符串必须以空字符(即终止空字符)结尾。

// don't forget to add error handling at some point (s == -1)
ssize_t s = read(0, bBuffer, BUFSIZ-1);
bBuffer[s] = '\0';

有了这个设置,我不认为现在需要清除数组,因为execvp将读取参数直到第一个空指针。然而,do循环已经添加了那个空指针,也就是最后一次调用strsep返回的空指针。

当然,问题也可以通过清除bBuffer(即在扫描第一个命令之后指向*pArgs的数据)来解决。请注意,在第一次扫描之前,您还必须这样做,因为您不能假设bBuffer数组中的字符已初始化为任何合理的值。

memset(bBuffer, 0, sizeof bBuffer);

read调用之前放置它(但无论如何,只读取最大的BUFSIZE-1,因为终止空字符也必须有空间!)。

但正如我上面所示,您不需要此memset调用。只需手动添加终止空字符即可。


我不明白为什么我的答案被踩。显然,他的问题并不是由于没有清除指针数组而产生的,而是问题出在其他地方。所以简单地展示正确清除该数组的方法是好的,但至少同样重要的是展示如何修复这个错误! - undefined
我认为他的“无限循环”是有意为之的,而你误读了问题。但我会点赞这个回答,因为这是提交者应该注意的重要信息。 - undefined
我并不打算打破无限循环,当然了。看一下读取的情况,我们假设BUFSIZ为255。你输入"echo hello",缓冲区将包含[echo helloblahblusomerandomdata.......]。strsep怎么可能正常运行呢?仅仅清除指针数组是不够的。他真正想要的是清除bBuffer数组。但是根据我的回答,这并非必需。 - undefined
然而,我建议他可以在do-while循环之后去掉"= '\0'"这一行当然是错误的。他这样做是为了摆脱'\n'字符。我恐怕完全忽视了那行代码的目的。 - undefined
1
如果我按照你的建议,将bBuffer[s] = '\0' 改为 bBuffer[s-1] = '\0',我仍然可以去掉那行代码来清除 '\n' 字符。而且既然我必须清除它,用 s-1 比使用 strlen() 来清除 '\n' 字符更好,因为那样的代码会变得冗长和混乱。 :) - undefined
确实,这也是我对此的想法。很高兴看到我还没有变疯 :) - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接