关于c程序中的myfopen()
我的问题是关于这个问题: c K&R fopen和fillbuf上的分段错误 。
- 在这个问题中,在myfopen()函数中,有一个for循环; 我不明白的是,fp将具有从_iob开始的值,但是我没有得到fp-> flag在前三个值(已经修复)之后取的值。 他们是否会采用零值,还有一个问题是在答案中(参见代码下方)他们说我们必须使用malloc为fp提供内存空间,但fp已经提供了内存空间,因为_iob数组有空格和fp将继续获取数组元素的地址,那么malloc的需求是什么?如果所有元素都为零,那么for循环总是会在fp = _iob + 3处中断吗?
- 其次在main()函数中,提到的模式是“r”但是后面使用的系统调用是write()虽然它没有显示错误,但为什么这可能呢?
-
第三,编译器在编译此代码时不显示错误或警告,但显示一个对话框,指出“f_open.exe已停止工作”,即使我们编写malloc行(或没有),或者即使有,也保持相同“r”模式或“w”模式。 那有什么不对?
#include #include #include #define PERM 0644 #define EOF (-1) #define BUFSIZE 1024 #define OPEN_MAX 20 typedef struct _iobuf{ int cnt; char *ptr; char *base; int flag; int fd; } myFILE; enum _flags { _READ = 01, _WRITE = 02, _UNBUF = 04, _EOF = 010, _ERR = 020 }; myFILE _iob[OPEN_MAX]={ {0, (char *) 0, (char *) 0, _READ, 0 }, {0, (char *) 0, (char *) 0, _WRITE, 1 }, {0, (char *) 0, (char *) 0, _WRITE | _UNBUF, 2 } }; #define stdin (&_iob[0]) #define stdout (&_iob[1]) #define stderr (&_iob[2]) #define getc(p) ( --(p)->cnt>=0 ? (unsigned char) *(p)->ptr++ : _fillbuf(p) ) int _fillbuf(myFILE *fp) { int bufsize; if((fp->flag & (_READ|_EOF|_ERR))!=_READ) return EOF; bufsize=(fp->flag & _UNBUF)? 1 : BUFSIZE; if(fp->base==NULL) if((fp->base=(char *)malloc(bufsize))==NULL) return EOF; fp->ptr=fp->base; fp->cnt=read(fp->fd, fp->ptr, bufsize); if(--fp->cntcnt == -1) fp->flag |= _EOF; else fp->flag |= _ERR; return EOF; } return (unsigned char) *fp->ptr++; } myFILE *myfopen(char *name, char *mode) { int fd; myFILE *fp; if(*mode!='r' && *mode!='w' && *mode!='a') return NULL; for(fp=_iob; fpflag & (_READ | _WRITE))==0) break; if(fp>=_iob+OPEN_MAX) return NULL; if(*mode=='w') fd=creat(name, PERM); else if(*mode=='a'){ if((fd=open(name, O_WRONLY, 0))==-1) fd=creat(name, PERM); lseek(fd, 0L, 2); } else fd=open(name, O_RDONLY, 0); if(fd==-1) return NULL; fp->fd = fd; fp->cnt = 0; fp->base = NULL; fp->flag = (*mode=='r')? _READ : _WRITE; return fp; } int main(int argc, char *argv[]) { myFILE *fp; int c; if((fp=myfopen(argv[1], "r"))!=NULL) write(1, "opened\n", sizeof("opened\n")); while((c=getc(fp))!=EOF) write(1, &c, sizeof(c)); return 0; }
解决方案是:
myFILE *fp; if(*mode!='r' && *mode!='w' && *mode!='a') return NULL; for(fp=_iob; fpflag & (_READ | _WRITE))==0) // marked line break;
当您到达标记的行时,您尝试取消引用fp指针。 由于它(可能但不一定)初始化为零(但我应该说为NULL),因此您将取消引用空指针。 繁荣。 段错误。
这是你需要改变的。
myFILE *fp = (myFILE *)malloc(sizeof(myFILE));
一定要#include使用malloc。
此外,您的关闭函数应该稍后释放()您的myFILE以防止内存泄漏。
正如您所看到的,上面是链接问题的答案: c K&R fopen和fillbuf上的分段错误
其他问题的诊断是假的
正如评论中所指出的, 另一个问题的诊断是虚假的。 特别是, myfopen()
中的循环读取:
for (fp =_iob; fp <_iob + OPEN_MAX; fp++) if ((fp->flag & (_READ | _WRITE)) == 0) break;
是完全正确的。 它遍历数组_iob
的元素,并且永远不会遇到声明的空指针。 缓冲区_iob
初始化为前三个元素; 其余的都是零。
可能是麻烦的原因
导致此程序崩溃的最可能原因是:
- 没有为文件名提供参数。
- 提供的名称无法打开阅读。
main()
显示的代码是:
int main(int argc, char *argv[]) { myFILE *fp; int c; if((fp=myfopen(argv[1], "r"))!=NULL) write(1, "opened\n", sizeof("opened\n")); while((c=getc(fp))!=EOF) write(1, &c, sizeof(c)); return 0; }
代码不会检查这些常见问题。 它应该更像是:
int main(int argc, char *argv[]) { myFILE *fp; int c; if (argc != 2) { static const char usage[] = "Usage: mystdio filename\n"; write(2, usage, sizeof(usage)-1); return 1; } if ((fp = myfopen(argv[1], "r")) == NULL) { static const char filenotopened[] = "mystdio: failed to open file "; write(2, filenotopened, sizeof(filenotopened)-1); write(2, argv[1], strlen(argv[1])); write(2, "\n", 1); return 1; } write(1, "opened\n", sizeof("opened\n")); while ((c = getc(fp)) != EOF) write(1, &c, sizeof(c)); return 0; }
您必须添加#include
因为它使用strlen()
。 通过文件描述符I / O报告错误是笨拙的,但是此代码排除了使用
中的常规函数。 该程序包含
因此可以编写exit(EXIT_FAILURE);
而不是return 1;
,但是当当前函数是main()
时,最终结果是相同的 – 尽管不是在main()
中直接或间接调用的函数中。