所以我有一个项目,我在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 */
}
感谢您的帮助!
答案 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_t
值bytesRead
投射到(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
。您最初在此处拥有size
值fileSize
,这是新bytesRead
变量的一个原因。以下行对size_t
size
和fileSize
进行了比较。这应该生成编译器警告(你确实有它们,不是吗?)因为在同一个表达式中使用有符号和无符号类型会导致困难,所以我在这里再次使用了return
变量。 / p>
您错过了main()
末尾的initialize()
语句,并且您的函数定义缺少其返回类型说明符,因此我也添加了这些语句。我还注意到,在没有参数的情况下调用时,你的程序是segfaulting。这是因为在return
函数中出现错误时,您readFile()
调用了调用函数,调用函数随后使用NULL
指针调用exit()
。您应该从程序中End()
。我已对修改后的代码中的所有文件错误陷阱进行了这些更改。
您的代码还存在其他一些问题。我不想使用NULL
函数。它不会在关闭文件时测试错误,如果传入"Unexpected number of bytes read"
指针则会出现段错误。此外,readFile()
中的End()
错误最终会成功退出,因为EXIT_SUCCESS
始终会以long
退出。
我不喜欢我从size_t
到ftell()
的投射,而其他人可能会有更好的方法。我在这里尝试管理的是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,也无需使用标准来处理坏事。例如。使用返回类型正确声明函数。