C 标准缓冲问题

C 标准缓冲问题,c,stdout,C,Stdout,我已经写了这个代码 #include<stdio.h> #include<assert.h> #include<stdlib.h> char *list[20],*story[100]; FILE*listfile; FILE*infile; FILE*outfile; int check(char*string) { int i=0; while(list[i]!=NULL) { if(strcmp(string,list[

我已经写了这个代码

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

char *list[20],*story[100];

FILE*listfile;
FILE*infile;
FILE*outfile;

int check(char*string)
{
  int i=0;
  while(list[i]!=NULL)
    {
      if(strcmp(string,list[i])==0){return 1;};
      i++;
    };
  return 0;
};

void print_d(int d){ printf(" debug %d ",d);};

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

  assert(argc==4);
  printf("hello \n");
  //assigning the file pointers in their respective modes
  printf("%s %s %s ",argv[1],argv[2],argv[3]);
  listfile=fopen(argv[1],"r");
  print_d(12);
  infile=fopen(argv[2],"r");
  outfile=fopen(argv[3],"w");
  print_d(0);
  int i=0; /* the infamous 'i' */

  while(1)
    {

      if(feof(listfile)!=0)
        { break;};
      list[i]=malloc(sizeof(char [15]));
      fscanf(listfile,"%s[^\n]",list[i]);
      i++;


    }
  i=0;
  print_d(1);
  while(1)
    {

      if(feof(infile)!=0)
        { break;};
      story[i]=malloc(sizeof(char [25]));
      fscanf(infile,"%s",story[i]);
      i++;

    }
  fclose(infile);
  fclose(listfile);
  i=0;

  print_d(2);
  while(1)
    {

      if(check(story[i])==1)
        { fprintf(outfile,"%s","censored");}
      else
        {
          fprintf(outfile,"%s",story[i]);
        };
    };
  print_d(3);
  fclose(outfile);
  i=0;
  while(list[i]!=NULL)
    { free(list[i]);};
  return 0;


}
#包括
#包括
#包括
字符*列表[20],*故事[100];
文件*列表文件;
文件*填充;
文件*输出文件;
整数检查(字符*字符串)
{
int i=0;
while(列表[i]!=NULL)
{
if(strcmp(string,list[i])==0{return 1;};
i++;
};
返回0;
};
无效打印d(int d){printf(“调试%d”,d);};
int main(int argc,字符**argv){
断言(argc==4);
printf(“hello\n”);
//以各自的模式分配文件指针
printf(“%s%s%s”,argv[1],argv[2],argv[3]);
listfile=fopen(argv[1],“r”);
打印(12);
infle=fopen(argv[2],“r”);
outfile=fopen(argv[3],“w”);
打印d(0);
int i=0;/*臭名昭著的“i”*/
而(1)
{
如果(feof(listfile)!=0)
{break;};
list[i]=malloc(sizeof(char[15]);
fscanf(列表文件“%s[^\n]”,列表[i]);
i++;
}
i=0;
打印d(1);
而(1)
{
如果(feof(infle)!=0)
{break;};
故事[i]=malloc(sizeof(char[25]);
fscanf(填充,“%s”,故事[i]);
i++;
}
fclose(infle);
fclose(列表文件);
i=0;
打印(2);
而(1)
{
如果(检查(故事[i])==1)
{fprintf(输出文件,“%s”,“已审查”);}
其他的
{
fprintf(输出文件,“%s”,故事[i]);
};
};
打印(3);
fclose(输出文件);
i=0;
while(列表[i]!=NULL)
{free(list[i]);};
返回0;
}
随后出现了以下问题

[1] 输出是一个hello,后跟一个seg故障

这就是事情变得有趣的地方

如果我修改

printf(“%s%s%s”,argv[1],argv[2],argv[3])

printf(“%s%s%s\n”,argv[1],argv[2],argv[3])

输出是一个“hello”,后跟三个文件名,然后是一个segfault

在用户danfuzz指出我应该将print_d debug改为print to stderr(我做到了)…调试打印现在可以正常工作了。所以我想一个更好的问题是,为什么会发生这种情况,以及防止这种情况发生的步骤


对于经验丰富的程序员来说,这似乎是一个微不足道的问题,但是请注意,早期版本(上面代码中的版本)在seg故障之前没有打印出任何消息,这导致我得出结论,在事件/文件打开的命令行部分发生了一些事情。

与其在论坛上猜测或询问,不如运行一个调试器。如果在linux上工作,gdb将直接带您找到分段错误的位置

假设您的应用程序名为“foo”:

当它崩溃时:

# bt

不要在论坛上猜测或询问,只需运行调试器即可。如果在linux上工作,gdb将直接带您找到分段错误的位置

假设您的应用程序名为“foo”:

当它崩溃时:

# bt
一些观察结果

您应该阅读关于
fflush(stdout)
,因为它将帮助您处理调试语句

void print_d(int d)
{
    printf(" debug %d ",d); fflush(stdout);
};
您分配给字符指针数组、
list[20]
story[100]
,但是您有循环(由臭名昭著的“i”索引),可以很容易地从列表或故事的末尾走出来

如果试图打开文件名为
argv[2]
argv[3]
的文件,一行为读,另一行为写,请将这些行更改为以下内容:

printf("%s %s %s ",argv[1],argv[2],argv[3]); fflush(stdout);

if( !(listfile=fopen(argv[1],"r")) )
{
    printf("cannot open %s\n",argv[1]); fflush(stdout);
    return(1);
}
print_d(1);
if( !(infile=fopen(argv[2],"r")) )
{
    printf("cannot open %s\n",argv[2]); fflush(stdout);
    return(2);
}
print_d(2);
if( !(outfh=fopen(argv[3],"w+")) ) //notice the "w+" to create missing file
{
    printf("cannot open %s\n",argv[3]); fflush(stdout);
    return(3);
}
print_d(3);
现在文件已正确打开,请将调试打印参数更改为递增的数字顺序,这样您就可以按顺序发现(;)循环工作的计数器

int check(char*string)
{
    int i;
    for(i=0; list[i]!=NULL; i++)
    {
        if(strcmp(string,list[i])==0){return 1;};
    };
    return 0;
};
更改循环以成功读取两个文件

for(i=0; i<20; ++i)
{
    if(feof(listfh)!=0) { break; };
    list[i]=malloc(sizeof(char [15]));
    fscanf(listfh,"%s[^\n]",list[i]);
}
fclose(listfh);
debug(4);
您还需要确保只释放分配的行

for(i=0; list[i] && list<20; i++)
{
    free(list[i]);
}
对于(i=0;list[i]&&list一些观察结果

您应该阅读关于
fflush(stdout)
,因为它将帮助您处理调试语句

void print_d(int d)
{
    printf(" debug %d ",d); fflush(stdout);
};
您分配给字符指针数组、
list[20]
story[100]
,但是您有循环(由臭名昭著的“i”索引),可以很容易地从列表或故事的末尾走出来

如果试图打开文件名为
argv[2]
argv[3]
的文件,一行为读,另一行为写,请将这些行更改为以下内容:

printf("%s %s %s ",argv[1],argv[2],argv[3]); fflush(stdout);

if( !(listfile=fopen(argv[1],"r")) )
{
    printf("cannot open %s\n",argv[1]); fflush(stdout);
    return(1);
}
print_d(1);
if( !(infile=fopen(argv[2],"r")) )
{
    printf("cannot open %s\n",argv[2]); fflush(stdout);
    return(2);
}
print_d(2);
if( !(outfh=fopen(argv[3],"w+")) ) //notice the "w+" to create missing file
{
    printf("cannot open %s\n",argv[3]); fflush(stdout);
    return(3);
}
print_d(3);
现在文件已正确打开,请将调试打印参数更改为递增的数字顺序,这样您就可以按顺序发现(;)
循环工作的计数器

int check(char*string)
{
    int i;
    for(i=0; list[i]!=NULL; i++)
    {
        if(strcmp(string,list[i])==0){return 1;};
    };
    return 0;
};
更改循环以成功读取两个文件

for(i=0; i<20; ++i)
{
    if(feof(listfh)!=0) { break; };
    list[i]=malloc(sizeof(char [15]));
    fscanf(listfh,"%s[^\n]",list[i]);
}
fclose(listfh);
debug(4);
您还需要确保只释放分配的行

for(i=0; list[i] && list<20; i++)
{
    free(list[i]);
}


for(i=0;list[i]&&list您应该始终检查fopen()的返回值是否为0。@CharlieBurns您认为在打开文件时可能发生了什么事情……这可能是第一次。但是可以。关于
if(strcmp(string,list[i])==0{return 1;};
,请删除最后一个
(不确定它会影响什么,只是一个混淆因素。@Ryker不好的做法?你可能想让
print\u d
print换行,也可能去stderr而不是stdout。似乎stdout的默认缓冲对你来说很混淆。你应该始终检查fopen()的返回值。)要查看是否为0。@CharlieBurns您认为在打开文件时可能发生了什么事情……这可能是第一次。但是可以。关于
if(strcmp(string,list[i])==0){return 1;};
,请删除最后一个
(不确定它会影响什么,只是一个混乱的因素。@Ryker坏习惯?你可能想让
print\u d
打印一个换行符,也可能去stderr而不是stdout。似乎stdout的默认缓冲让你很困惑。我对segfault以外的东西更感兴趣,gdb会给你更多。放一个断点,检查变量,找出你的问题。这比打印或猜测你的建议是正确的要容易得多,但是告诉我好先生,你的“评论”不应该在“评论”部分而不是在“回答”部分吗?也许你是对的。但是gdb是调试的正确答案。现在你的答案是transfo