我一整天都在努力解决这个问题,看着类似的例子并没有让我走得太远,所以我希望你能帮忙!如果有人想知道上下文的话,我正在编写操作系统概念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
在用于访问数组之前从未给出过值。感谢大家的帮助。
答案 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.