【问题标题】:Parsing command-line entries in C: implementing a shell在 C 中解析命令行条目:实现 shell
【发布时间】:2015-09-29 12:40:37
【问题描述】:

我正在用 C 实现一个 shell,但在解析命令行条目时遇到了一些问题。我希望我的解析器方法能够分隔由空格字符分隔的命令行条目,并将结果作为双字符指针返回。即,假设我有“ls -l >ls.txt”,我的解析器应该返回一个带有 r[0]="ls"、r[1]="-l" 和 r[2]= 的 char **r ">ls.txt"。

这是我当前的解析方法的代码,顺便说一下,是段错误,我不知道如何解决这个问题:

 char **parser(int *argc, char *s)
 {
     char **r;
     char *t, *m;
     int i,n,size;

     t = malloc(strlen(s)); // firs i used this instead of *r, but i run 
                            // into trouble when i have more than two
                            // argc. ( You see why, right?)
    //strcpy(t,s);
    i = 0;
    size = 5;
    r = malloc(size*sizeof(char *));
    while (( m = strchr(s, ' '))) {
        n = ((int)m) - ((int)s);
        if (i==0) {
          *r = malloc(n);
        } else {
           *r = realloc(*r, n);
        }
        strncpy(*r, s, n);
        *r[n]= '\0';
        s = (char*)(s+n+1);
        if (i == size)
            r = realloc(r, (size = 2*size)*sizeof(char*));
        i++;
        r = (char **)(r + sizeof(char*));
   }

   s[strlen(s)-1] = '\0';
   if ((i<1) || (strlen(s)>1)) {
       *r = s;
   }
   *argcp = ++i;
   return r;
}

我知道我的代码并不理想。使用 strsep 可以做得更好,但我主要关心的是如何管理我想要返回的双字符指针的内存。

感谢您的帮助!

【问题讨论】:

  • 注意,在普通的shell中,你可以写&gt; file或&gt;file,并且都将标准输出重定向到file。你也可以写ls -l|wc-l或ls -l | wc -l(或者混合'n'match管道符号周围的间距。也就是说,大多数shell对于空白的位置非常灵活。(事实上,&gt;file ls -l发送@的输出987654328@ 到 file;ls &gt;file -l 也是如此!)
  • 在演示方面,如果代码有系统的缩进,你的代码会更容易阅读,并且不会沉迷于像if (...) a = ...; 这样的无端技巧都在一行上。它只是让你很难阅读你的代码。如果您需要帮助,您需要确保您的代码易于其他人阅读。
  • n = ((int)m) - ((int)s); if(i==0){ *r = malloc(n); }else{ *r = realloc(*r, n); } 的行中有一个麻烦的世界第一行应该是n = (int)(m - s);(或者你可以省略演员表)。 malloc() 或 realloc() 在 r 中的空间应该是 char * 值的数组(这就是你使用 char **r 声明它的原因)。分配的空间需要是char *值的个数,大小需要按sizeof(*r)缩放。然后,您对字符串处理的管理不善。是时候重做第一原则了。
  • 感谢您的第一条评论!我现在要在解析器中解决这个问题!
  • 您需要一个由char ** 指向的(不断增长的)char * 值数组(因此r 可以作为变量定义)。对于数组中的每个条目,您需要一个长度足以容纳字符的字符串加上一个空终止符。该字符串将由r 数组中的一个条目指向:r[i] = malloc(strlen(str) + 1); 或类似的。或者,更好的是,使用或实现strdup()。

标签: c shell command-line command-line-arguments


【解决方案1】:

这是一个快速的刺。

我的 C 太生锈了,所有的铰链都卡住了,所以。

前提是你最终会得到一个指向指针数组的指针。然而,关键细节在指针列表的末尾,是参数数据本身。所以当你完成后,你只需要释放返回的指针。

未经测试。这里很可能会出现一次性错误。

编辑,我编译并快速测试了它。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


char **parser(int *argc, char *s) {
    char **r, **rp;
    char *t, *p, *w;
    void *vp;
    int l;

    l = strlen(s); // size of cmd line
    vp = malloc(l + (*argc * sizeof(char *))); // total buffer size
    t = (char *)(vp + (*argc * sizeof(char *))); // offset into buffer for argument copy
    r = (char **)vp;  // start of buffer, start of pointer array to arguments
    strcpy(t, s);  // copy arguments in to buffer
    p = t;  // parsing pointer
    w = t;  // word pointer for each argument
    rp = r;  // storage for first pointer

    while(*p) {  // while not at end of string
        if (*p == ' ') {  // if we find a space
            if (w) {  // if we have a word pointer assigned
                *rp++ = w;  // store the word pointer
                w = NULL;  // set word pointer to null
                *p = '\0';  // terminate argument with a 0
            } // else do nothing continue to skip spaces
        } else {
            if (w == NULL) {  // If we haven't got a new arg yet
                w = p;  // set it
            }  // otherwise, just keep scanning
        }
        p++;  // move along the string
    }
    if (w) {  // clean up at the end if we have an arg
        *rp++ = w;
        w = NULL;  // no reason to set 0 at the end, it's already there from strcpy
    }

    return r;
}

int main() {
    char *cmd = "arg1 arg2";
    int argc = 2;

    char **r = parser(&argc, cmd);

    printf("%s\n",r[0]);
    printf("%s\n",r[1]);
}

【讨论】:

    猜你喜欢
    • 2011-12-11
    • 1970-01-01
    • 2022-11-13
    • 2012-04-24
    • 2013-11-18
    • 1970-01-01
    • 2013-03-07
    • 1970-01-01
    相关资源
    最近更新 更多