分段错误:ANSI C中的11(C89)

时间:2016-11-09 00:24:54

标签: c segmentation-fault

所以我有一个项目,我在ANSI C(C89)课堂上工作。我陷入了困境。我得到了一个

分段错误:11

问题,无论我怎么看,我似乎无法解决问题。有人可以看看我的代码并指出我正确的方向吗?

/* CS315 Lab 3: C data types */

#include <stdio.h>
#include <stdlib.h> /*added this to provide a declaration for malloc*/

#define TENMB 1048576 /*1024 kilobytes or 10 megabytes */
#define ONEB 1

FILE * fp = NULL;

End(FILE * fp)/*made END a function */
{ 
    fclose(fp);             /* close and free the file */
    exit(EXIT_SUCCESS);     /* or return 0; */
}

initialize(int argc, char ** argv)
{
    /* Open the file given on the command line */
    if( argc != 2 )
    {
        printf( "Usage: %s filename.mp3\n", argv[0] );
        return(EXIT_FAILURE);
    }
    FILE * fp = fopen(argv[1], "rb");
    if( fp == NULL )
    {
        printf( "Can't open file %s\n", argv[1] );
        return(EXIT_FAILURE);
    }
    return 0; /*this might need to change */
}

readFile(FILE * fp)
{
    /* How many bytes are there in the file?  If you know the OS you're
    on you can use a system API call to find out.  Here we use ANSI
    standard function calls. */
    long size = 0;
    fseek(fp, 0, SEEK_END );        /* go to 0 bytes from the end */
    size = ftell(fp);               /* how far from the beginning? */
    rewind(fp);                     /* go back to the beginning */

    if( size < ONEB || size > TENMB ) 
    {
        printf("File size is not within the allowed range\n"); 
        End(fp); /* switched from goto END:*/
    }

    printf( "File size: %.2ld MB\n", size/TENMB );  /* change %d to %ld, added .2 to print to 2 decimal places (maybe use f instead) */
    /* Allocate memory on the heap for a copy of the file */
    unsigned char * data = (unsigned char *)malloc(size); 
    /* Read it into our block of memory */
    size_t bytesRead = fread( data, sizeof(unsigned char), size, fp );
    free(data); /* deallocation */
    if( bytesRead != size )
    {
        printf( "Error reading file. Unexpected number of bytes read:     %zu\n",bytesRead ); /* changed from %d to %zu */
        End(fp); /* switched from goto END:*/
        return 0;
     }
    return 0;
}

int main( int argc, char ** argv )
{
    initialize(argc, argv);

    readFile(fp);

    /* We now have a pointer to the first byte of data in a copy of the      file, have fun
    unsigned char * data    <--- this is the pointer */
}

感谢您的帮助!

2 个答案:

答案 0 :(得分:0)

您说这应该是C89代码,但此代码的某些方面不符合C89。我在下面包含了一个修改过的代码,修复了这些内容,编译时没有警告,似乎运行正常。作为免责声明,我从不用C89写作,所以其他人可能会在这里提出问题。

您报告的段错是由于fp的双重声明,正如@BLUEPIXY在您的问题的评论中所指出的那样。您首先在文件范围声明此文件指针(即fp是&#34;全局&#34;变量),然后在函数initialize()内的块范围内。第二个声明隐藏了块中的第一个声明,因此您在initialize()中打开一个文件,并将结果指针分配给块范围fp(具有自动存储持续时间) 。当main()然后调用readFile()时,传递的文件范围fp会被fp初始化为NULL。因此在fseek(fp, 0, SEEK_END)指针上调用NULL,这会导致段错误。将第二个声明更改为赋值可以解决此问题:

fp = fopen(argv[1], "rb");

您无法在C89中混合变量声明和代码,因此您需要将声明移动到函数的开头。此外,C89不支持%zu变量的size_t格式说明符。相反,请使用%lu并将size_tbytesRead投射到(unsigned long)

我添加了一个定义:ONEMB 1048576,并删除了TENMB定义。在计算文件大小时,你将字节数除以10MB而不是1MB,我认为你实际上是在尝试计算MB的数量。

我在调用ftell()时添加了错误检查。由于ftell()返回long,我添加了size_t fileSize变量并将size的值转换为size_t,然后再将其分配给fileSize。我将printf()语句更改为:

printf( "File size: %.2f MB\n", (fileSize * 1.0)/ONEMB );

以便更精确地报告文件大小;这样,小于1 MB的文件将不会报告为大小为0 MB。

malloc()来自bytesRead,因为在C中绝对不需要。

fread()调用size_t的分配,其中第三个参数的long参数不是long。您最初在此处拥有sizefileSize,这是新bytesRead变量的一个原因。以下行对size_t sizefileSize进行了比较。这应该生成编译器警告(你确实有它们,不是吗?)因为在同一个表达式中使用有符号和无符号类型会导致困难,所以我在这里再次使用了return变量。 / p>

您错过了main()末尾的initialize()语句,并且您的函数定义缺少其返回类型说明符,因此我也添加了这些语句。我还注意到,在没有参数的情况下调用时,你的程序是segfaulting。这是因为在return函数中出现错误时,您readFile()调用了调用函数,调用函数随后使用NULL指针调用exit()。您应该从程序中End()。我已对修改后的代码中的所有文件错误陷阱进行了这些更改。

您的代码还存在其他一些问题。我不想使用NULL函数。它不会在关闭文件时测试错误,如果传入"Unexpected number of bytes read"指针则会出现段错误。此外,readFile()中的End()错误最终会成功退出,因为EXIT_SUCCESS始终会以long退出。

我不喜欢我从size_tftell()的投射,而其他人可能会有更好的方法。我在这里尝试管理的是long返回fread(),您用它来计算文件大小,而size_t都会获取并返回readFile()值。

我所做的大部分工作都在#include <stdio.h> #include <stdlib.h> /*added this to provide a declaration for malloc*/ #define ONEMB 1048576 #define ONEB 1 FILE * fp = NULL; void End(FILE * fp)/*made END a function */ { fclose(fp); /* close and free the file */ exit(EXIT_SUCCESS); /* or return 0; */ } int initialize(int argc, char ** argv) { /* Open the file given on the command line */ if( argc != 2 ) { printf( "Usage: %s filename.mp3\n", argv[0] ); exit(EXIT_FAILURE); } fp = fopen(argv[1], "rb"); if( fp == NULL ) { printf( "Can't open file %s\n", argv[1] ); exit(EXIT_FAILURE); } return 0; /*this might need to change */ } int readFile(FILE * fp) { long size = 0; unsigned char *data; size_t fileSize, bytesRead; fseek(fp, 0, SEEK_END ); if ((size = ftell(fp)) == -1) { fprintf(stderr, "ftell() error\n"); exit(EXIT_FAILURE); }; rewind(fp); if( size < ONEB || size > 10 * ONEMB ) { printf("File size is not within the allowed range\n"); End(fp); } fileSize = (size_t) size; printf( "File size: %.2f MB\n", (fileSize * 1.0)/ONEMB ); data = malloc(fileSize); bytesRead = fread( data, sizeof(unsigned char), fileSize, fp ); free(data); if( bytesRead != fileSize ) { printf( "Error reading file. Unexpected number of bytes read: %lu\n", (unsigned long) bytesRead ); End(fp); exit(EXIT_FAILURE); } return 0; } int main( int argc, char ** argv ) { initialize(argc, argv); readFile(fp); /* We now have a pointer to the first byte of data in a copy of the file, have fun unsigned char * data <--- this is the pointer */ End(fp); return 0; } 函数中,我从此函数中删除了您的注释,以便更容易查看更改内容。

我编译:

  

gcc -std = c89 -Wall -Wextra -pedantic

copy /b header.txt + body.txt destfile.txt

答案 1 :(得分:0)

在您的代码中,您已声明fp两次,包括全局和本地

FILE * fp = NULL;

End(FILE * fp)/*made END a function */
{ 
    fclose(fp);             /* close and free the file */
    exit(EXIT_SUCCESS);     /* or return 0; */
}

initialize(int argc, char ** argv)
{
...
    FILE * fp = fopen(argv[1], "rb");
...

即使您正在编写C89,也无需使用标准来处理坏事。例如。使用返回类型正确声明函数。