gpt4 book ai didi

c - 在 C 中操作 char* 数组时的奇怪行为

转载 作者:太空宇宙 更新时间:2023-11-04 12:11:29 25 4
gpt4 key购买 nike

我正在尝试为操作系统类创建命令行 shell。我们的任务之一是创建一个内置的“历史”命令,打印出在 shell 中执行的最后 10 个命令。这是我为“历史”命令编写的代码:

char* cmd_hsitory[10]; // This is a global variable

int add_history(char **args) {
cmd_history[9] = NULL;
for(int i = 8; i >= 0; i--) {
cmd_history[i+1] = cmd_history[i];
}
cmd_history[0] = *args;
return 1;
}

其中 char **args 参数是最后执行的命令。这是打印历史记录的函数:

int lsh_history(char **args) {
printf("Last 10 commands: \n");
for(int i = 0; i < 10; i++) {
printf("%s\n", cmd_history[i]);
}
return 1;
}

这段代码发生了一些奇怪的行为。例如,当我连续运行命令 [cd, cd, ls, history] ​​时,打印输出如下:

Last 10 commands:
ls
ls
cd
(null)
(null)
(null)
(null)
(null)
(null)
(null)

这里的第一个问题是我运行了两次 cd 命令,而只运行了一次 ls 命令。如果我再次运行“历史”命令,我会得到:

Last 10 commands:
history
ls
ls
cd
(null)
(null)
(null)
(null)
(null)
(null)

除了 2 个 ls 命令与 1 个 cd 命令之外,这似乎是正确的。

不过,这不是很一致,因为有时我会混淆命令,并且“历史记录”命令会出现多次。

如果有人告诉我我的代码有什么明显的错误,那会很有帮助。谢谢!

编辑:这是完整的源代码:附言大部分代码都来自互联网(Stephen Brennan),我正在构建它来学习。我不会将此代码作为我的作业提交。

#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/*
Function Declaration for history queue
*/
int add_history(char **args);

/*
Function Declarations for builtin shell commands:
*/
int lsh_cd(char **args);
int lsh_help(char **args);
int lsh_exit(char **args);
int lsh_history(char **args);

/*
List of builtin commands, followed by their corresponding functions.
*/
char *builtin_str[] = {
"cd",
"help",
"exit",
"history"
};

int (*builtin_func[]) (char **) = {
&lsh_cd,
&lsh_help,
&lsh_exit,
&lsh_history
};

char *cmd_history[10];

int lsh_num_builtins() {
return sizeof(builtin_str) / sizeof(char *);
}

int add_history(char **args) {
cmd_history[9] = NULL;
for(int i = 8; i >= 0; --i) {
cmd_history[i+1] = cmd_history[i];
}
cmd_history[0] = NULL;
cmd_history[0] = *args;
return 1;
}

/*
Builtin function implementations.
*/

/**
@brief Builtin command: command history.
@param args List of args. args[0] is "history".
@return Always returns 1 to continue executing.
*/
int lsh_history(char **args) {
printf("Last 10 commands: \n");
for(int i = 0; i < 10; i++) {
printf("%s\n", cmd_history[i]);
}
return 1;
}

/**
@brief Bultin command: change directory.
@param args List of args. args[0] is "cd". args[1] is the directory.
@return Always returns 1, to continue executing.
*/
int lsh_cd(char **args)
{
if (args[1] == NULL) {
chdir("/Users/Landon/");
} else {
if (chdir(args[1]) != 0) {
perror("lsh");
}
}
return 1;
}

/**
@brief Builtin command: print help.
@param args List of args. Not examined.
@return Always returns 1, to continue executing.
*/
int lsh_help(char **args)
{
int i;
printf("Stephen Brennan's LSH\n");
printf("Type program names and arguments, and hit enter.\n");
printf("The following are built in:\n");

for (i = 0; i < lsh_num_builtins(); i++) {
printf(" %s\n", builtin_str[i]);
}

printf("Use the man command for information on other programs.\n");
return 1;
}

/**
@brief Builtin command: exit.
@param args List of args. Not examined.
@return Always returns 0, to terminate execution.
*/
int lsh_exit(char **args)
{
return 0;
}

/**
@brief Launch a program and wait for it to terminate.
@param args Null terminated list of arguments (including program).
@return Always returns 1, to continue execution.
*/
int lsh_launch(char **args)
{
pid_t pid;
int status;

pid = fork();
if (pid == 0) {
// Child process
if (execvp(args[0], args) == -1) {
perror("lsh");
}
exit(EXIT_FAILURE);
} else if (pid < 0) {
// Error forking
perror("lsh");
} else {
// Parent process
do {
waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}

return 1;
}

/**
@brief Execute shell built-in or launch program.
@param args Null terminated list of arguments.
@return 1 if the shell should continue running, 0 if it should terminate
*/
int lsh_execute(char **args)
{
int i;

if (args[0] == NULL) {
// An empty command was entered.
return 1;
}

for (i = 0; i < lsh_num_builtins(); i++) {
if (strcmp(args[0], builtin_str[i]) == 0) {
return (*builtin_func[i])(args);
}
}

return lsh_launch(args);
}

#define LSH_RL_BUFSIZE 1024
/**
@brief Read a line of input from stdin.
@return The line from stdin.
*/
char *lsh_read_line(void)
{
int bufsize = LSH_RL_BUFSIZE;
int position = 0;
char *buffer = malloc(sizeof(char) * bufsize);
int c;

if (!buffer) {
fprintf(stderr, "lsh: allocation error\n");
exit(EXIT_FAILURE);
}

while (1) {
// Read a character
c = getchar();

if (c == EOF) {
exit(EXIT_SUCCESS);
} else if (c == '\n') {
buffer[position] = '\0';
return buffer;
} else {
buffer[position] = c;
}
position++;

// If we have exceeded the buffer, reallocate.
if (position >= bufsize) {
bufsize += LSH_RL_BUFSIZE;
buffer = realloc(buffer, bufsize);
if (!buffer) {
fprintf(stderr, "lsh: allocation error\n");
exit(EXIT_FAILURE);
}
}
}
}

#define LSH_TOK_BUFSIZE 64
#define LSH_TOK_DELIM " \t\r\n\a"
/**
@brief Split a line into tokens (very naively).
@param line The line.
@return Null-terminated array of tokens.
*/
char **lsh_split_line(char *line)
{
int bufsize = LSH_TOK_BUFSIZE, position = 0;
char **tokens = malloc(bufsize * sizeof(char*));
char *token, **tokens_backup;

if (!tokens) {
fprintf(stderr, "lsh: allocation error\n");
exit(EXIT_FAILURE);
}

token = strtok(line, LSH_TOK_DELIM);
while (token != NULL) {
tokens[position] = token;
position++;

if (position >= bufsize) {
bufsize += LSH_TOK_BUFSIZE;
tokens_backup = tokens;
tokens = realloc(tokens, bufsize * sizeof(char*));
if (!tokens) {
free(tokens_backup);
fprintf(stderr, "lsh: allocation error\n");
exit(EXIT_FAILURE);
}
}

token = strtok(NULL, LSH_TOK_DELIM);
}
tokens[position] = NULL;
return tokens;
}

/**
@brief Loop getting input and executing it.
*/
void lsh_loop(void)
{
char *line;
char **args;
int status;

do {
printf("> ");
line = lsh_read_line();
args = lsh_split_line(line);
status = lsh_execute(args);

add_history(args);
free(line);
free(args);
} while (status);
}

/**
@brief Main entry point.
@param argc Argument count.
@param argv Argument vector.
@return status code
*/
int main(int argc, char **argv)
{
// Load config files, if any.

// Run command loop.
lsh_loop();

// Perform any shutdown/cleanup.

return EXIT_SUCCESS;
}

最佳答案

您需要将 arg 字符串 strdup() 到您的 cmd_history 指针,而不仅仅是让您的 cmd_history 指针引用原始命令字符串。当你 free(line) 时,你将把你的 cmd_history 指针引用的内存放回空闲池中。在循环的下一次迭代中,您可能会也可能不会覆盖该数据。

关于c - 在 C 中操作 char* 数组时的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48752442/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com