我一直在创建一个应该打开文件的函数(catalogname []).但是每当我编译时,我都会得到这两个我无法弄清楚的错误.
a3.c:在函数'openCatalog'中:
a3.c:20:警告:从不兼容的指针类型分配
a3.c:22:警告:return在没有强制转换的情况下从整数生成指针
这是我的代码:
FILE* openCatalog(char catalogname[])
{
catalogname = fopen ("*catalogname", "r");
if(fopen != 0)
{
return 1;
}
else
{
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
提前感谢您提供的任何见解.
对此代码的完整解释将需要一段时间.
简要版本是:
FILE *openCatalog(char catalogname[])
{
FILE *fp = fopen(catalogname, "r");
return(fp);
}
Run Code Online (Sandbox Code Playgroud)
这将打开命名文件以进行读取并返回文件流指针.
另一个简短版本检查文件是否可以打开:
int openCatalog(char catalogname[])
{
FILE *fp = fopen(catalogname, "r");
if (fp != 0)
{
fclose(fp);
return 1;
}
else
{
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
原始代码是:
FILE* openCatalog(char catalogname[])
{
catalogname = fopen ("*catalogname", "r");
if(fopen != 0)
{
return 1;
}
else
{
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
我们没有"打开文件"之外的规范.给定函数签名,似乎您希望FILE *返回打开文件的(文件流指针).所以,让我们在此基础上批评代码.
功能原型线是可以的; 可能是char const catalogname[]要强调该函数不会修改文件名,但这是一个改进,而不是修复错误.
catalogname函数的类型是char *.在函数的参数列表中,数组与指针松散等价.我通常会写FILE *openCatalog(char const *catalogname)一下,强调在函数中,它是一个char const *变量.尽管如此,使用您使用的数组符号是100%合法的; 对于我来说,使用指针符号纯粹是一种风格偏好.
下一个可执行行有几个问题.函数调用在fopen()技术上并没有错,虽然它打开一个具有固定名称*catalogname的文件而不是变量中指定的文件catalogname.要解决此问题,您需要删除引号.该*会给你一个角色,而不是一个字符串,这将是文件名的第一个字符.所以,删除它*.
这使您fopen()返回一个值,实际上是a FILE *,并将其分配给catalognamea char *.这是类型不匹配,编译器警告.如第一次重写所示,处理此问题的更常用方法是:
FILE *fp = fopen(catalogname, "r");
Run Code Online (Sandbox Code Playgroud)
这会导致您的错误消息:
a3.c:20: warning: assignment from incompatible pointer type
Run Code Online (Sandbox Code Playgroud)我们不知道您的目录是文本文件还是二进制文件.如果它是一个二进制文件,那么你应该使用"rb"它来打开它,如果你在Windows(真正重要的地方),并且它也可以在类Unix系统上正常工作(文本和二进制文件之间没有区别).
代码中的下一行是条件:
if (fopen != 0)
Run Code Online (Sandbox Code Playgroud)
这实际上检查函数的函数指针是否fopen()为null.并且C标准保证在托管环境(您正在使用)中,没有函数指针为空.因此编译器可以优化该测试以假设条件始终为真.
你真正需要的是对结果的测试:
if (fp != 0)
Run Code Online (Sandbox Code Playgroud)然后你有两个return语句,一个返回1,一个返回0.返回1返回1引发一个关于将整数转换为指针的警告,因为该函数被定义为返回a FILE *而1是一个整数.
这会解释您的其他警告消息:
a3.c:22: warning: return makes pointer from integer without a cast
Run Code Online (Sandbox Code Playgroud)返回0不会生成警告,因为0是空指针常量,并且这是要返回的函数的有效值.
代码应该只是简单地返回值fopen().在此函数或调用函数中测试某处的值是正确的,以确保打开成功.你可以在这里测试它:
if (fp == 0)
err_report_and_exit("Failed to open file %s (%d: %s)\n",
catalogname, errno, strerror(errno));
Run Code Online (Sandbox Code Playgroud)
使用errno和strerror()意味着您还应该包含标题:
#include <errno.h>
#include <string.h>
Run Code Online (Sandbox Code Playgroud)代码应从以下位置返回文件流fopen():
return fp;
Run Code Online (Sandbox Code Playgroud)总的来说,这会导致:
FILE *openCatalog(char catalogname[])
{
FILE *fp = fopen(catalogname, "r");
if (fp == 0)
err_report_and_exit("Failed to open file %s (%d: %s)\n",
catalogname, errno, strerror(errno));
return(fp);
}
Run Code Online (Sandbox Code Playgroud)
如果该函数旨在检查文件是否可以打开以供阅读,则上述问题大致相同.我首先展示的修订代码略显冗长.由于推测的目的是检查文件是否可以打开,因此调用代码应负责处理"它无法打开的情况"; 它知道要生成什么样的诊断.这是一个稍微复杂的版本,但是这个和上面的对象代码是相同的.
int openCatalog(char catalogname[])
{
FILE *fp = fopen(catalogname, "r");
if (fp != 0)
{
fclose(fp);
return 1;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
一个简单的实现err_report_and_exit()是:
#include "errreport.h"
#include <stdio.h>
#include <stdlib.h>
#include <starg.h>
void err_report_and_exit(char const *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(EXIT_FAILURE);
}
Run Code Online (Sandbox Code Playgroud)
"errreport.h"标题可能是:
#ifndef ERRREPORT_H_INCLUDED
#define ERRREPORT_H_INCLUDED
#ifdef __GNUC__
#define PRINTFLIKE(n,m) __attribute__((format(printf,n,m)))
#define NORETURN() __attribute__((noreturn))
#else
#define PRINTFLIKE(n,m) /* If only */
#define NORETURN() /* If only */
#endif /* __GNUC__ */
extern void err_report_and_exit(char const *format, ...) PRINTFLIKE(1,2) NORETURN();
#endif /* ERRREPORT_H_INCLUDED */
Run Code Online (Sandbox Code Playgroud)
特定于GCC的位意味着您可以获得与printf()直接使用相同级别的格式错误报告.
(这段代码是在一个更大的包上建模的,系统地err_用作函数前缀.在这个包中,这个函数就是err_error().这就是为什么它err_不是error_- 尽管解释需要的时间比修复它要长.包含在文件stderr.c和stderr.h,虽然有它如履薄冰使用踏入参数std前缀.它是,但是,我的标准错误报告包).