关于c程序中的myfopen()

我的问题是关于这个问题: c K&R fopen和fillbuf上的分段错误 。

  1. 在这个问题中,在myfopen()函数中,有一个for循环; 我不明白的是,fp将具有从_iob开始的值,但是我没有得到fp-> flag在前三个值(已经修复)之后取的值。 他们是否会采用零值,还有一个问题是在答案中(参见代码下方)他们说我们必须使用malloc为fp提供内存空间,但fp已经提供了内存空间,因为_iob数组有空格和fp将继续获取数组元素的地址,那么malloc的需求是什么?如果所有元素都为零,那么for循环总是会在fp = _iob + 3处中断吗?
  2. 其次在main()函数中,提到的模式是“r”但是后面使用的系统调用是write()虽然它没有显示错误,但为什么这可能呢?
  3. 第三,编译器在编译此代码时不显示错误或警告,但显示一个对话框,指出“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初始化为前三个元素; 其余的都是零。

可能是麻烦的原因

导致此程序崩溃的最可能原因是:

  1. 没有为文件名提供参数。
  2. 提供的名称无法打开阅读。

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()中直接或间接调用的函数中。