为什么fgets() 会把字符串末尾的换行符视为单独的一行?
我在操作系统课程里要用C 写一个简单的shell。为了读取给定的输入命令,我在一个while循环中使用 fgets(),然后逐行解析。每个输入都被格式化为 "some_string\n",随后我把它存入缓冲区并去掉末尾的换行符。
#define MAX_LINE_SIZE 4096
char* buff = (char*) malloc(MAX_LINE_SIZE * sizeof(char));
while(fgets(buff, MAX_LINE_SIZE, stdin) != NULL) {
*strchr(buff, '\n') = '\0';
// without this check, the program later results in a segmentation fault
// when the last '\n' character is read on its own.
if(strlen(buff) == 0) {
break;
}
// parse and execute the command
}
free(buff);
在下面的测试用例中,我发现最后一个字符串末尾的换行被当作独立的一行读取,导致得到长度为0 的字符串,并且在没有进行 if(strlen(buff) == 0) 检查的情况下会导致段错误:
debug\n
debug 1\n
debug\n
debug off\n
debug\n
最后的 "debug" 被作为独立的一行读取,而这一行缺少 '\n'' 字符,随后在下一次循环迭代中又被单独读取。
为什么会这样呢?我很难理解这种行为,因为根据手册,fgets() 应该把整个字符串读到(包括)'\n',或者(不包括)EOF,之后将其存储并返回字符串。
解决方案
我无法用你问题中给出的输入重现你的问题。下面的程序在运行时没有任何错误。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_SIZE 4096
int main( void )
{
char buff[MAX_LINE_SIZE];
const char testdata[] =
"debug\n"
"debug 1\n"
"debug\n"
"debug off\n"
"debug\n";
FILE *fp = fopen( "testfile.bin", "w+" );
if ( fp == NULL )
{
fprintf( stderr, "Error opening file!\n" );
exit( EXIT_FAILURE );
}
fprintf( fp, "%s", testdata );
rewind( fp );
// This is the code from the question
while(fgets(buff, MAX_LINE_SIZE, fp) != NULL) {
*strchr(buff, '\n') = '\0';
if(strlen(buff) == 0) {
break;
}
}
fclose( fp );
}
我唯一的解释是,你在问题中贴出的输入并非你实际使用的确切输入。例如,如果我在输入末尾再加一个空格,使输入不是以换行符结尾,那么就会产生段错误。例如,以下对 testdata 的定义就会导致段错误。
const char testdata[] =
"debug\n"
"debug 1\n"
"debug\n"
"debug off\n"
"debug\n"
" ";
为了确定到底哪里出了问题,我建议你对输入文件创建一个 十六进制转储(hexdump)。在Linux上,可以使用下面的命令。
hd inputfile
如果你在其他平台,可以编写一个简单的程序来打印输入文件的十六进制转储,例如下面这个程序。
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char **argv )
{
FILE *fp;
int c;
int column;
// make sure that program was invoked correctly
if ( argc != 2 )
{
char *program_name;
if ( argc >= 1 && argv[0][0] != '\0' )
program_name = argv[0];
else
program_name = "programname";
printf( "Usage: %s inputfile\n", program_name );
exit( EXIT_FAILURE );
}
// attempt to open input file
fp = fopen( argv[1], "rb" );
if ( fp == NULL )
{
fprintf( stderr, "Error opening file!\n" );
exit( EXIT_FAILURE );
}
// print content of input file as hexadecimal
column = 0;
while ( ( c = fgetc( fp ) ) != EOF )
{
printf( "%02X", (unsigned char)c );
column++;
if ( column % 16 == 0 )
{
printf( "\n" );
column = 0;
}
else
{
printf( " " );
}
}
// print a newline character, if appropriate
if ( column != 0 )
{
printf( "\n" );
}
// if an error occurred, print an appropriate error message
if ( ferror( fp ) )
{
fprintf( stderr, "read error\n" );
exit( EXIT_FAILURE );
}
// cleanup
fclose( fp );
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。