C 将字符串写入文件会产生奇怪的字符

C 将字符串写入文件会产生奇怪的字符,c,file-io,C,File Io,我的家庭作业是使用历史函数(done)创建一个shell(done),然后将历史写入一个文件(这就是我遇到问题的地方),以便在下次运行时加载它 我通常是Java爱好者,所以我需要查找几乎所有的c函数。无论如何,我在将字符串数组写入文件时遇到了问题。出于某种原因,我不断地得到奇怪的符号,这取决于我使用的编码。 例如,如果我运行程序并立即退出,则历史文件包含: ??_? ls _? ??_? 如果运行ls然后退出,则历史文件包含: ??_? ls _? ls _? 我删除了不相关的程序。提前感谢您的

我的家庭作业是使用历史函数(done)创建一个shell(done),然后将历史写入一个文件(这就是我遇到问题的地方),以便在下次运行时加载它

我通常是Java爱好者,所以我需要查找几乎所有的c函数。无论如何,我在将字符串数组写入文件时遇到了问题。出于某种原因,我不断地得到奇怪的符号,这取决于我使用的编码。 例如,如果我运行程序并立即退出,则历史文件包含:

??_? ls _? ??_? 如果运行ls然后退出,则历史文件包含:

??_? ls _? ls _? 我删除了不相关的程序。提前感谢您的指点。这是拔头发的第三天。我束手无策

#include 
/*Had to use \ so that the includes would show here. */
#include \stdlib.h>
#include \signal.h>
#include \sys/types.h>
#include \unistd.h>
#include \string.h>
#include \errno.h>
/*
* Constant Declarations
*/
#define MAX_LINE 80
#define BUFFER_SIZE 50
#define HIST_SIZE 10

static char buffer[BUFFER_SIZE];
char history[HIST_SIZE][BUFFER_SIZE];
int count = 0;
int caught = 0;
char historyFileLoc[] = "./name.history";

void loadHistory() {
    int i;
    char histCommand[BUFFER_SIZE];

    i = 0;
    FILE *hisFile = fopen(historyFileLoc, "r");

    if( hisFile ) {
        /*If a user edits the history file, only the first ten entries will be loaded */
        while(!feof(hisFile)) {
            if(fscanf(hisFile, "%s\n", histCommand) == 1){
                strcpy(history[i], histCommand);
                i++;
                count++;
            }
        }
    }

    if(hisFile != NULL){
        if(fclose(hisFile) != 0) {
            perror("History file (r) was not closed correctly");
        }
    }
}

void saveHistory() {
    int i;
    char buffer[MAX_LINE];

    FILE *hisFile = fopen(historyFileLoc, "w");

    for(i=0; i < HIST_SIZE; i++){
        if(history[i] != '\0') {
            strcpy(buffer, history[i]);
        /*fwrite(history[i], 1, strlen(history[i]), hisFile);*/
        /*  fputs(history[i], hisFile);*/
            if(buffer != NULL) {
                fprintf(hisFile,"%s\n", buffer);
            }
        }
    }
    if(fclose(hisFile) != 0) {
    perror("History file was not closed correctly");
    }
}


/*
* The main() function presents the prompt "sh>" and then invokes setup(), which waits for the
*  user to enter a command. The contents of the command entered by the user are loaded into the
*  args array. For example, if the user enters ls Ðl at the COMMAND-> prompt, args[0] will be set
*  to the string ls and args[1] will be set to the string Ðl. (By ÒstringÓ, we mean a
*  null-terminated, C-style string variable.)
*/
int main(void) {
    char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
    int background, status; /* equals 1 if a command is followed by '&' */
    char *args[MAX_LINE / 2 + 1]; /* command line arguments */
    pid_t pid; /* the process's id */
...
}
#包括
/*必须使用\以便在此处显示包含项*/
#包括\stdlib.h>
#include\signal.h>
#包括\sys/types.h>
#包括\unistd.h>
#include\string.h>
#包括\errno.h>
/*
*常量声明
*/
#定义最大行80
#定义缓冲区大小为50
#定义历史大小10
静态字符缓冲区[缓冲区大小];
字符历史[HIST_SIZE][BUFFER_SIZE];
整数计数=0;
int=0;
char historyFileLoc[]=“/name.history”;
void loadHistory(){
int i;
char histCommand[缓冲区大小];
i=0;
FILE*hisFile=fopen(historyFileLoc,“r”);
如果(他的文件){
/*如果用户编辑历史文件,则仅加载前十个条目*/
而(!feof(hisFile)){
如果(fscanf(hisFile,“%s\n”,histCommand)==1){
strcpy(历史[i],histCommand);
i++;
计数++;
}
}
}
if(hisFile!=NULL){
如果(fclose(hisFile)!=0){
perror(“历史文件(r)未正确关闭”);
}
}
}
void saveHistory(){
int i;
字符缓冲区[最大行];
FILE*hisFile=fopen(historyFileLoc,“w”);
对于(i=0;i”,然后调用setup(),等待
*用户输入命令。用户输入的命令内容将加载到
*args数组。例如,如果用户在命令->提示下输入lsÐl,则会设置args[0]
*对于字符串ls,args[1]将设置为字符串Ðl。(我们所说的“字符串”是指
*以null结尾的C样式字符串变量。)
*/
内部主(空){
char inputBuffer[MAX_LINE];/*用于保存输入命令的缓冲区*/
int background,status;/*如果命令后跟“&”,则等于1*/
char*args[MAX_-LINE/2+1];/*命令行参数*/
pid\u t pid;/*进程的id*/
...
}
历史记录转储[]:

./660_Lab04.c.out sh ->ls 660_Lab03_Tests.txt Lab 03 Documentation.docx 660_Lab04.c buffer.h 660_Lab04.c.out name.history 660__Lab01.c main.c 660__Lab03.c main_not_mine.c CSE_660Lab01Documentation.doc This is where the dump begins minus sh-> sh ->ls ls _? ??_? /660_Lab04.c.输出 sh->ls 660_Lab03_Tests.txt Lab 03 Documentation.docx 660_Lab04.c缓冲区h 660_Lab04.c.out name.history 660_uuuLab01.c主管道c 660_uuLab03.c主矿非矿矿c CSE_66001LabDocumentation.doc 这是转储开始的位置减去sh-> sh->ls ls _? ??_? 我的代码的其余部分。loadHistory和saveHistory在此之前:


void printHistory() {
    int i;
    int j = 0;
    int histcount = count;

    printf("\n");
    for (i=0; i < HIST_SIZE; i++) {
        printf("%d.   ",histcount); /* Used to print the correct hitory number */
        while (history[i][j] != '\n' && history[i][j] != '\0') {
            printf("%c",history[i][j]);
            j++;
        }
        printf("\n");
        j=0;

        histcount--;
        if(histcount == 0) {
            break;
        }
    }
    printf("\n");
    printf("sh -> ");
}

/* the signal handler function */
void handle_SIGINT() {
    write(STDOUT_FILENO,buffer,strlen(buffer));
    printHistory();
    caught = 1;
}

void setup(char inputBuffer[], char *args[], int *background) {
    int length, /* # of characters in the command line */
        i, /* loop index for accessing inputBuffer array */
        start, /* index where beginning of next command parameter is */
        ct, /* index of where to place the next parameter into args[] */
        k; /* Generic counter */

    ct = 0;

/* read what the user enters on the command line */
    length = read(STDIN_FILENO, inputBuffer, MAX_LINE);

    if(caught == 1) {
        length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
        caught = 0;
    }

/* checks to see if the command is a history retrieval command. If it isn't then add it to the history */
    if((strcmp(inputBuffer, "r\n\0") != 0) && (strncmp(inputBuffer, "r x", 2) != 0) ) {
        for(i= (HIST_SIZE - 1); i>0; i--) {
            strcpy(history[i], history[i-1]);
        }
        strcpy(history[0], inputBuffer);
        count++;
    }
    start = -1;
    if (length == 0) {
        saveHistory();
        exit(0); /* ^d was entered, end of user command stream */
    } else if ((length < 0) && (errno != EINTR)) {
        perror("error reading the command");
        saveHistory();
        exit(-1); /* terminate with error code of -1 */
    }

/* Checks to see if r was entered. If so, it copies the command most recently in the input buffer */
    if(strcmp(inputBuffer, "r\n\0") == 0) {
        strcpy(inputBuffer,history[0]);
        /* Checks to see if r x was entered. If so then it searches for the most recent command that begins with x */   
        } else if(strncmp(inputBuffer, "r x", 2) == 0) {
            for(k=0; k < 10; k++){
                if(inputBuffer[2] == history[k][0]) {
                    strcpy(inputBuffer,history[k]);
                    break;
                }
            }
        }

        length = strlen(inputBuffer);

/* examine every character in the inputBuffer */
        for (i = 0; i < length; i++) {
            switch (inputBuffer[i]) {
                case ' ':
                case '\t': /* argument separators */
                if (start != -1) {
                    args[ct] = &inputBuffer[start]; /* set up pointer */
                    ct++;
                }
                inputBuffer[i] = '\0';
                start = -1;
                break;

                case '\n': /* should be the final char examined */
                if (start != -1) {
                    args[ct] = &inputBuffer[start];
                    ct++;
                }
                inputBuffer[i] = '\0';
                args[ct] = NULL; /* no more arguments to this command */
                break;
                case '&':
                *background = 1;
                inputBuffer[i] = '\0';
                break;

                default: /* some other character */
                if (start == -1) {
                    start = i;
                }
            }
            args[ct] = NULL; /* just in case the input line was > 80 */
        }
    }


/* The main() function presents the prompt "sh->" and then invokes setup(), which waits for the user to enter a command. The contents of the command entered by the user are loaded into the args array. For example, if the user enters ls -l at the COMMAND-> prompt, args[0] will be set to the string ls and args[1] will be set to the string -l. (By string, we mean a null-terminated, C-style string variable.) */
int main(void) {
    char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
    int background, status; /* equals 1 if a command is followed by '&' */
    char *args[MAX_LINE / 2 + 1]; /* command line arguments */
    pid_t pid; /* the process's id */

/* set up the signal handler */
    struct sigaction handler;
    handler.sa_handler = handle_SIGINT;
    sigaction(SIGINT, &handler, NULL);

    loadHistory();

    while (1) {
        background = 0;

        printf("\nsh ->");
        fflush(0);
        setup(inputBuffer, args, &background); /* get next command */
        fflush(0);
        pid = fork(); /* assign the process id */
        if (pid < 0) {
            fprintf(stderr, "ERROR: Could not properly fork.");
            saveHistory();
            exit(-1); /* unsucessful exit because the fork could not be created */
        } else if (pid == 0) { /* PID was forked successfully */
            status = execvp(*args, args); /* execute the command */
            if (status < 0) {
                fprintf(stderr, "ERROR: Could not execute %s", args[0]);
                saveHistory();
                exit(1);
            }
        } else if (background == 0) { /* if the fork is run in the foreground */
            wait(NULL);
        }
    }

    return EXIT_SUCCESS;
}

作废打印历史(){
int i;
int j=0;
int histcount=计数;
printf(“\n”);
对于(i=0;i”);
}
/*信号处理函数*/
无效句柄_SIGINT(){
写入(STDOUT_文件号、缓冲区、strlen(缓冲区));
打印历史();
捕获=1;
}
无效设置(字符输入缓冲区[],字符*参数[],整数*背景){
命令行中字符的整数长度,/*#*/
i、 /*用于访问inputBuffer数组的循环索引*/
start,/*索引,其中下一个命令参数的开头为*/
ct,/*将下一个参数放入args[]的位置索引*/
k、 /*通用计数器*/
ct=0;
/*阅读用户在命令行上输入的内容*/
长度=读取(标准输入文件号、输入缓冲区、最大行);
如果(捕获==1){
长度=读取(标准输入文件号、输入缓冲区、最大行);
捕获=0;
}
/*检查该命令是否为历史记录检索命令。如果不是,则将其添加到历史记录中*/
if((strcmp(inputBuffer,“r\n\0”)!=0)和&(strncmp(inputBuffer,“r x”,2)!=0)){
对于(i=(历史大小-1);i>0;i--){
strcpy(历史[i],历史[i-1]);
}
strcpy(历史[0],inputBuffer);
计数++;
}
开始=-1;
如果(长度==0){
保存历史();
退出(0);/*^d已输入,用户命令流结束*/
}如果((长度小于等于0)和((错误号!=EINTR))为else{
perror(“读取命令时出错”);
保存历史();
退出(-1);/*终止,错误代码为-1*/
}
/*检查是否输入了r。如果输入了r,则会在输入缓冲区中复制最近的命令*/
if(strcmp(inputBuffer,“r\n\0”)==0){
strcpy(输入缓冲区,历史[0]);
/*检查是否输入了rx。如果输入了,则搜索以x*/开头的最新命令
}else if(strncmp(输入缓冲区,“rx”,2)==0){
对于(k=0;k<10;k++){
if(inputBuffer[2]==历史[k][0]){
strcpy(输入缓冲区,历史[k]);
打破
}
}
}
长度=strlen(输入缓冲区)