0

我一直在创建一个应该打开文件的函数(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;
    }
}

提前感谢您提供的任何见解。

4

5 回答 5

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 *返回打开文件的(文件流指针)。因此,让我们在此基础上批评代码。

  • 函数原型行OK;可能是char const catalogname[]强调该函数不会修改文件名,但这是一种改进,而不是修复错误的更改。

  • catalogname函数中的类型是char *。在函数的参数列表中,数组大致等同于指针。我通常会写信FILE *openCatalog(char const *catalogname)强调在函数中,它是一个char const *变量。尽管如此,使用您使用的数组表示法是 100% 合法的;对我来说,使用指针符号纯粹是一种风格偏好。

  • 下一个可执行行有几个问题。函数调用在fopen()技术上并没有错,尽管它打开的是一个具有固定名称的文件,*catalogname而不是变量中指定的文件catalogname。要解决这个问题,您需要删除引号。会给你一个字符而*不是字符串,它将是文件名的第一个字符。所以,*也删除。

  • 这让您fopen()返回一个值,实际上是 a FILE *,然后您将它分配给catalogname, a 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)
    
  • 然后有两个返回语句,一个返回 1,一个返回 0。返回 1 的一个会引发关于将整数转换为指针的警告,因为该函数被定义为返回 a 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));
    

    使用errnoandstrerror()意味着您还应该包含标题:

    #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);
}

如果该函数旨在检查文件是否可以打开以进行读取,则上述问题大致相同。我首先展示的修改后的代码有点冗长。由于假定的目的是检查文件是否可以打开,所以调用代码应该负责处理“无法打开的情况”;它知道要生成什么样的诊断。这是修订版的稍微紧凑的版本,但是 this 和上面的目标代码是相同的。

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_- 尽管输入的解释比修复它需要更长的时间。大包包含在 filesstderr.cstderr.h中,尽管有一个论点是它使用前缀如履薄冰std。然而,它是我的标准错误报告包。)

于 2012-05-06T01:35:59.050 回答
1
  • 不兼容的指针类型

    catalogname = fopen ("*catalogname", "r");
    

    catalogname是一个字符数组 ( char catalogname[]),同时fopen()返回一个文件指针 ( FILE*)。自然,将文件指针分配给 char 数组(这是一种不同类型的指针——而且,更重要的是,不可分配)没有任何意义。

  • return从整数生成指针而不进行强制转换

    您声明您的函数FILE*在此处返回:FILE* openCatalog(...). 但是,您的 return 语句是return 1;and return 0;。在那里,编译器认为您想要返回值为 1(或 0)的文件指针,因此是响应。

于 2012-05-06T01:33:53.467 回答
1
FILE* openCatalog(char catalogname[])

这会更好char *catalogname,因为你实际上并没有传递一个数组——你得到的是一个指向字符的指针。(这是 C 的一个有趣的小怪癖。)虽然这很有效,但我发现提醒您只得到一个指针是非常受欢迎的。

catalogname = fopen ("*catalogname", "r");

fopen(3)返回一个FILE*对象。您不能将 a 分配FILE*char []变量。

如果要catalogname在调用中使用变量fopen(3),只需使用它:

FILE *f = fopen(catalogname, "r");
if(fopen != 0)

fopen是此上下文中的函数指针。您不是将前一个fopen()调用的返回值与 进行比较0,而是将函数指针0. 那不是你想要的。

    return 1;

你声明你的函数返回 a FILE *,这就是你应该返回的——而不是一个整数。

重新编写的版本如下所示:

FILE* openCatalog(char *catalogname) {
    FILE *f = fopen(catalogname, "r");
    if (!f)
        perror("Unable to open file");
    return f;
}
于 2012-05-06T01:36:40.230 回答
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.
}
于 2012-05-06T01:34:15.523 回答
0

第一个警告:

您正在分配FILE*fopen返回的内容)到catalognamewhich is char []

第二个警告:

该函数FILE*在您返回整数时返回类型01

你想要别的东西吗?像:

FILE* openCatalog(char catalogname[])
{
   FILE* file = fopen (catalogname, "r");
于 2012-05-06T01:34:34.337 回答