难以打印字符指针数组

时间:2017-02-03 02:55:20

标签: c arrays linux pointers

我一整天都在努力解决这个问题,看着类似的例子并没有让我走得太远,所以我希望你能帮忙!如果有人想知道上下文的话,我正在编写操作系统概念CH 3末尾的编程作业1。

所以问题是基本上在c中创建一个命令提示符,允许用户输入命令,fork并执行它,并将命令保存在历史记录中。用户可以输入命令'history'来查看打印出的10个最新命令。本书指示我将当前命令存储为参数的char指针数组,然后我将使用execvp(args[0], args)执行当前命令。我的教授为此添加了其他要求,因此如此单独访问每个参数对于这些部分也是有用的。

我决定使用一系列char指针以类似的方式存储命令的历史记录。因此,例如,如果第一个命令是ls -la而输入的第二个命令是cd..,那么我们将history[0] = "ls -la"history[1] = "cd.."。我真的很难让这个工作起来,而且我很确定我在某个地方搞砸指针,但我无法理解它。

在主要内容中,我可以使用ls打印第一个命令中的第一个单词(ls -la arg_history[0]),但实际上无法弄清楚整个内容的打印。但是我知道那里的数据,并且在我添加它(通过add_history函数)时验证它并且它是正确的!更糟糕的是,当我将它传递给用于打印历史记录的get_history函数时,它会打印出一堆乱码。我非常感谢任何帮助,了解它为什么这样做!现在我有预感,这与在函数之间错误地传递指针有关,但根据我一直在看的东西,我无法发现问题!

/**
 * Simple shell interface program.
 *
 * Operating System Concepts - Ninth Edition
 * Copyright John Wiley & Sons - 2013
 */

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



#define MAX_LINE        80 /* 80 chars per line, per command */
#define HIST_LENGTH     10

void get_input(char *args[], int *num_args, char *history[], int *hist_index);
void get_history(char *history[], int hist_index);
void add_history(char *history[], char *added_command, int *hist_index);

int main(void)
{
    char *args[MAX_LINE/2 + 1]; /* command line (of 80) has max of 40 arguments */
    char *arg_history[HIST_LENGTH];

    int num_args;
    int hist_index;

    int should_run = 1;
    int i;

    while (should_run){   
        printf("osh>");
        fflush(stdout);

        get_input(args, &num_args, arg_history, &hist_index);

        //printf("%s\n", arg_history[0]); //incorrectly prints up to the first space
        //printf("%s\n", args[0]) //prints the correct arg from the last command (eg. for 'ls -la' it prints ls for args[0] and -la for args[1])

        if (strcmp(args[0], "history") == 0) {
            get_history(arg_history, hist_index);
        }        
    }

    return 0;
}

void get_input(char *args[], int *num_args, char *history[], int *hist_index) {
    char input[MAX_LINE];
    char *arg;

    fgets(input, MAX_LINE, stdin);
    input[strlen(input) - 1] = NULL; // To remove new line character - the compiler doesn't like how I'm doing this

    add_history(history, input, hist_index);

    arg = strtok(input, " ");

    *num_args = 0;
    while(arg != NULL) {
        args[*num_args] = arg;
        *num_args = *num_args + 1;
        arg = strtok(NULL, " ");
    }
}

void get_history(char *history[], int hist_index) {
    int i;
    for (i = 0; i < HIST_LENGTH; i++) {
        printf("%d %s\n",  hist_index, *history);
        // prints gibberish
        hist_index = hist_index - 1;
        if (hist_index < 1) {
            break;
        }
    }
}

void add_history(char *history[], char *added_command, int *hist_index) {
    int i;
    for (i = HIST_LENGTH-1; i > 0; i--) {
            history[i] = history[i-1];
    }

    history[0] = added_command;
    *hist_index = *hist_index + 1;
    //printf("%s\n", history[0]); prints correctly
}

更新: 我做了一些解决方案建议的更改,包括将指针移到函数的input(我把它放在main中),并使用strcpy作为add_history函数。我之前使用此问题的原因是因为我正在通过数组“向上”旋转项目,但是在历史记录满了所有10个元素之前我访问了未初始化的位置。虽然我现在能够从main打印arg_history[0],但我仍然无法打印任何其他内容(例如arg_history [1])。但更重要的是,我无法打印get_history函数,这是我实际需要解决的问题。仔细观察后,我意识到hist_index在用于访问数组之前从未给出过值。感谢大家的帮助。

2 个答案:

答案 0 :(得分:3)

input[strlen(input) - 1] = NULL; // To remove new line character - the compiler doesn't like how I'm doing this

当然不是。这有很多问题。想象一下,如果strlen(input)为0,那么strlen(input) - 1为-1,并且您正在访问数组的第-1项...更不用说NULL是一个指针, 字符值。您可能意味着input[strlen(input) - 1] = '\0';,但更安全的解决方案是:

input[strcspn(input, "\n")] = '\0';
history[0] = added_command;
*hist_index = *hist_index + 1;
//printf("%s\n", history[0]); prints correctly

这打印正确,因为您指定给added_command并指向history[0]input的指针值get_command仍然有效。一旦get_command返回,指针指向的对象就不再存在,因此history[0]指针也不存在。

如果您正在阅读一本书(例如K&amp; R2E),您应该知道现在需要使用strcpy来指定字符串。在此之前,您需要创建一个合适大小的新对象(例如,使用malloc)...

对于没有读书的人来说,这是一个常见的问题......你正在读哪本书?

    printf("%d %s\n",  hist_index, *history);
    // prints gibberish

嗯,是的,它打印出乱码,因为*history返回之前get_command曾指向的对象在get_command返回时被销毁。一本书会教你这个。

另请参阅Returning an array using C以获得类似的解释......

答案 1 :(得分:0)

以下是strtok()的一些描述。因为您只是将输入的指针放在历史列表中而不是放置副本,所以您只打印出第一个单词。

char *strtok(char *str, const char *delim)
Parameters
str -- The contents of this string are modified and broken into smaller strings (tokens).

delim -- This is the C string containing the delimiters. These may vary from one call to another.