通过管道分离数组

时间:2012-09-26 19:11:09

标签: c

自从上一个问题以来,我做了很多工作,所以我认为开始一个新问题以获得一个清晰的答案是合适的。如果这是错误的方法,请告诉我。 (我是新人!)

这是我的代码:

int do_command(char **args){

    // In the end, this function should take an array of args
    // and separate them into UNIX commands that lie before and after
    // pipes that are entered and put them into an array called
    // arrayOfCommands.
    // For example, if the char array args comes in 
    // with {"ls", "-1", "|", "wc"}, there would be two commands
    // which would be "ls -l" and "wc"

    // The following number is in my real program, 
    // but using the contents of args above, there will be two
    // commands ("ls -l" and "wc" separated by a pipe)
    // The number is found dynamically by looking for the number
    // of pipes earlier (in our examples so far, just one) and 
    // simply adding one since there has to be a command on either
    // side of the pipe or an error is thrown.
    const int commands = 2;

    // I want to create an array that is 2 wide (int commands)
    // and 5 tall (just a constant number because I don't know
    // how many flags a user will enter after each UNIX command
    //
    //  0 1 
    // 0[][]
    // 1[][]
    // 2[][]
    // 3[][]
    // 4[][]
    //
    // Each column holds a UNIX command (Ex: "ls -s")
    // In this example, "ls" would be stored in arrayOfCommands[0][0];
    // And "-l" would be stored in arrayOfCommands[0][1];
    //
    // If there are more than one command (Ex: "ls -s | wc")
    // They would be stored like this:
    // "ls" in arrayOfCommands[0][0];
    // "-l" in arrayOfCommands[0][1];
    // "wc" in arrayOfCommands[1][0];

    char arrayOfCommands[commands][5]; //!!! (Declaration)

    //counts which column in arrayOfCommands we are on
    int commandNum = 0;

    //Counts which part of a command we are on
    int count = 0;

    //Array Counters
    int i = 0;
    int j;

    //Go through args until we reach the end
    while (args[i] != NULL){
        //if we find something that's not a pipe...
        if(strcmp(args[i], "|")){
            //put it into the array of commands
            arrayOfCommands[commandNum][count] = args[i]; \\!!! (Copying)
            count++;
        }
        //otherwise if we find a pipe...
        else if (!strcmp(args[i], "|")) {
            //we know we are done with that command
            count = 0;
            commandNum++;
        }
        //Looking at the next value in args
        i++;
    }

    //Print the new arrayOfCommands
    int col=0;
    int row=0;
    for (col=0;col<commands;col++){
        printf("Command #%d: ",col);
        for (row=0;row<10;row++){
            printf("%c ",arrayOfCommands[col][row]); \\!!! (Printing)
        }
        printf("\n");
    }
}

我已疯狂地评论代码,以帮助每个人理解我的代码。为了进一步解释,我正在使用C创建一个UNIX Shell。我的程序以用户输入的形式接收UNIX命令,并将它们放入一个名为“args”的数组中,用空格分隔。

上面的代码专门用于管道,并寻求进一步将代码分成管道(“|”)之前和之后的命令。来吧问问题,我会尽力帮助解释我的思考过程。

我认为我的编码部分有点正确,但是当我尝试打印arrayOfCommands时,我得到的结果如下:

命令0:%#! ## $
命令1:* ^ @ @!
(当然,这些是实际的符号)

我说“// !!!”在我认为导致问题的线后面。

2 个答案:

答案 0 :(得分:2)

如果你看一下:

char arrayOfCommands[commands][5]; //!!! (Declaration)
...
arrayOfCommands[commandNum][count] = args[i]; \\!!! (Copying) 

您正在为char*分配char

C字符串是字符数组。这意味着您有一个指向由char字符终止的一系列NUL的指针。 args[i]将返回的是该起始字符的内存地址。因此,您的“副本”只是将unsigned int 内存地址分配到指定为字符的数组中的元素中。它会将unsigned int(32位)截断为`字符(8位)。这可能是你看到奇怪价值的原因。

如果您想按照指示存储命令,则必须将arrayOfCommands从二维char数组更改为二维char *数组。此外,如果您想实际复制字符串,而不只是为args[]数组中的每个字符串创建指针别名,则必须分配二维数组的每个元素使用malloc()(然后在完成后释放内存,使用free())或选择固定的最大大小并将其分配到堆栈上。在这样的程序中,我可能会简单地使用后者:

char arrayOfCommands[2][5][256];  // 5 rows, 2 columns, maximum command length of 255 characters + NUL character

然后,当您进行复制时,您将不得不使用字符串复制功能:

strcpy(arrayOfCommands[row][column], args[i]); // Copy string at args[i] into arrayOfCommands[row][column]

这应该可以解决您遇到的问题。

答案 1 :(得分:0)

想通了。我决定采用一维阵列而不是2D方式。代码现在采用args,之前被拆分为“ls”“ - l”“|” “wc”并根据是否存在一个名为“arrayOfCommands”的新数组的管道来分隔它们。然后,一旦这样,arrayOfCommands的内容就是“ls -l”和“wc”。这是代码:

int do_command(char **args,) {
const int commands = 2;
int i = 0;

int commandNum = 0;
int firstCommand = 1;

char *arrayOfCommands[commands];

//Go through args until we reach the end
while (args[i] != NULL){
    //First case            
    if(firstCommand){
        arrayOfCommands[commandNum] = args[i];
        firstCommand = 0;
    }
    //Rest of the cases
    else{
        //if we find something that's not a pipe...
        if(strcmp(args[i], "|")){
            //Add a space to what was a previous part of the same command
            arrayOfCommands[commandNum] = strcat(arrayOfCommands[commandNum]," ");
            arrayOfCommands[commandNum] = strcat(arrayOfCommands[commandNum],args[i]);
        }
        //But if we do find a pipe...
        else if (!strcmp(args[i], "|")) {
            //We know it's time for a new command
            commandNum++;
            firstCommand = 1;
        }               
    }
    //Looking at the next value in args
    i++;
}

for(i = 0; i < commands; i++)
    printf("Command #[%d]: %s\n", i, arrayOfCommands[i]);
}