我一直在创建一个应该打开文件(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;
}
}
提前感谢您提供的任何见解。
答案 0 :(得分:5)
对此代码的完整解释需要一段时间。
简要版本是:
FILE *openCatalog(char catalogname[])
{
FILE *fp = fopen(catalogname, "r");
return(fp);
}
这将打开命名文件以进行读取并返回文件流指针。
另一个简短版本检查是否可以打开文件:
int openCatalog(char catalogname[])
{
FILE *fp = fopen(catalogname, "r");
if (fp != 0)
{
fclose(fp);
return 1;
}
else
{
return 0;
}
}
原始代码是:
FILE* openCatalog(char catalogname[])
{
catalogname = fopen ("*catalogname", "r");
if(fopen != 0)
{
return 1;
}
else
{
return 0;
}
}
我们没有“打开文件”之外的规范。给定函数签名,您似乎希望返回打开文件的FILE *
(文件流指针)。所以,让我们在此基础上批评代码。
功能原型线正常;可能char const catalogname[]
强调该函数不会修改文件名,但这是一个改进,而不是修复错误。
函数中catalogname
的类型为char *
。在函数的参数列表中,数组与指针松散等价。我通常会写FILE *openCatalog(char const *catalogname)
来强调在函数中,它是一个char const *
变量。尽管如此,使用您使用的数组符号是100%合法的;对于我来说,使用指针符号纯粹是一种风格偏好。
下一个可执行行有几个问题。对fopen()
的函数调用在技术上并没有错,但它会打开一个具有固定名称*catalogname
的文件,而不是变量catalogname
中指定的文件。要解决此问题,您需要删除引号。 *
会给你一个字符而不是一个字符串,它将是文件名的第一个字符。因此,也请删除*
。
这会让您fopen()
返回一个值,实际上是FILE *
,并将其分配给catalogname
,char *
。这是类型不匹配,编译器警告。如第一次重写所示,处理此问题的更常用方法是:
FILE *fp = fopen(catalogname, "r");
这说明了您的错误消息:
a3.c:20: warning: assignment from incompatible pointer type
我们不知道您的目录是文本文件还是二进制文件。如果它是一个二进制文件,那么你应该使用"rb"
来打开它,如果你在Windows上(它真的很重要),并且它也可以在类Unix系统上正常工作(文本之间没有区别)和二进制文件)。
代码中的下一行是条件:
if (fopen != 0)
这实际上检查函数fopen()
的函数指针是否为空。并且C标准保证在托管环境(您正在使用)中,没有函数指针为空。因此编译器可以优化该测试以假设条件始终为真。
您实际需要的是对结果的测试:
if (fp != 0)
然后你有两个return语句,一个返回1,一个返回0.返回1返回1引发一个关于将整数转换为指针的警告,因为该函数被定义为返回FILE *
和1是一个整数。
这说明了您的其他警告信息:
a3.c:22: warning: return makes pointer from integer without a cast
返回0不会生成警告,因为0是空指针常量,并且这是要返回的函数的有效值。
代码应该只是从fopen()
返回值。在此函数或调用函数中测试某处的值是正确的,以确保打开成功。你可以在这里测试它:
if (fp == 0)
err_report_and_exit("Failed to open file %s (%d: %s)\n",
catalogname, errno, strerror(errno));
使用errno
和strerror()
意味着您还应该包含标题:
#include <errno.h>
#include <string.h>
代码应返回fopen()
的文件流:
return fp;
总的来说,这导致:
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);
}
如果该功能旨在检查文件是否可以打开以供阅读,则上述问题大致相同。我首先展示的修订代码略显冗长。由于推测的目的是检查文件是否可以打开,因此调用代码应负责处理“它无法打开的情况”;它知道要生成什么样的诊断。这是一个稍微复杂的修订版本,但是这个和上面的对象代码是相同的。
int openCatalog(char catalogname[])
{
FILE *fp = fopen(catalogname, "r");
if (fp != 0)
{
fclose(fp);
return 1;
}
return 0;
}
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);
}
“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 */
特定于GCC的位意味着您可以获得与您直接使用printf()
相同级别的格式错误报告。
(此代码以更大的包为模型,系统地使用err_
作为函数前缀。在该包中,此函数将为err_error()
。这就是为什么它是err_
而不是error_
stderr.c
- 尽管解释所需的时间比解决它的时间要长。大包装包含在文件stderr.h
和std
中,尽管有一个论点是它正在踩着薄冰使用{{1}}前缀。但是,它是我的标准错误报告包。)
答案 1 :(得分:1)
指针类型不兼容
catalogname = fopen ("*catalogname", "r");
catalogname
是一个字符数组(char catalogname[]
),而fopen()
返回一个文件指针(FILE*
)。当然,将文件指针赋给char数组(这是一种不同类型的指针 - 更重要的是,不可分配)没有任何意义。
return
从没有强制转换
您声明您的函数在此处返回FILE*
:FILE* openCatalog(...)
。但是,您的退货声明为return 1;
和return 0;
。在那里,编译器认为你想要返回值为1(或0)的文件指针,因此响应。
答案 2 :(得分:1)
FILE* openCatalog(char catalogname[])
这会更好char *catalogname
,因为你实际上没有通过数组 - 你得到一个指向角色的指针。 (这是C的一个有趣的小怪癖。)虽然这有效,但我发现提醒您只有非常欢迎指针。
catalogname = fopen ("*catalogname", "r");
fopen(3)
会返回FILE*
个对象。您无法将FILE*
分配给char []
变量。
如果您想在catalogname
电话中使用fopen(3)
变量,只需使用它:
FILE *f = fopen(catalogname, "r");
if(fopen != 0)
在此上下文中, fopen
是函数指针。您不是将之前的fopen()
调用的返回值与0
进行比较,而是将函数指针与0
进行比较。那不是你想要的。
return 1;
你声明你的函数返回FILE *
,这就是你应该返回的 - 而不是整数。
重写版本如下:
FILE* openCatalog(char *catalogname) {
FILE *f = fopen(catalogname, "r");
if (!f)
perror("Unable to open file");
return f;
}
答案 3 :(得分:0)
实际上,你有很多错误,其中一些是被掩盖的
首先:
catalogename = fopen("*catalogname", "r");
错了。我想你想要的是:
FILE *fPtr = fopen(catalogname, "r");
然后,在那之后,你的函数的身体发生了很大的变化:
if (fPtr == NULL || ferror(fPtr) != 0) // if the file isn't NULL or if there is no errors with opening the file...
{
if (fPtr != NULL) // never try to close a NULL file ...
fclose(fPtr);
return NULL; // best way to report an error in C - return NUL or set errno
}
else
{
return fPtr; // return the file we just made.
}
答案 4 :(得分:0)
第一个警告:
您要将FILE*
(fopen
返回的内容)分配给catalogname
char []
。
第二个警告:
当您返回整数FILE*
或0
1
你还想要别的东西吗?像:
FILE* openCatalog(char catalogname[])
{
FILE* file = fopen (catalogname, "r");