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