在C中写入文件时出现逻辑错误

时间:2015-07-06 05:01:59

标签: c ansi

我有一个正在处理的项目,基本上它需要我从命令行读取切换并读取和写入一些输出到同一文件覆盖其以前的内容。如果未指定文件,则从stdin读取并写入stdout,这是一个对所有输出行进行编号的函数:

int main(int argc,char *argv[]) { 
     FILE *fp; 
     if((fp = fopen(argv[2]),"a+")) == 0) { 
            fp = stdin; /* if we cant read the file then it is read from stdin*/
     }
     if((strcmp("-e",argv[1])) == 0){
         if(fp == stdin) { 
              display_dollar(fp);  
         } 
     } 
    fclose(fp);
} 

这是我的display_dollar函数(实际打印到stdout或fp的函数)

void display_dollar(FILE *fp) { 
     char line[LINESIZE]; 
     char lines[LINESIZE];  
        while(fgets(line,LINESIZE,fp)) { 
            sscanf(line,"%s\n",lines);
            if(fp == stdin) { 
               printf("%s%c\n",lines,'$'); 
               lines[0] = '\0'; /* "clear" buffer */
            } else { 
               fprintf(fp,"%s%c\n",lines,'$'); 
               lines[0] = '\0'; /* "clear" buffer */
            } 
      }
}

这对于stdout非常有效,但是我无法将任何内容打印到fp指定的文件中,我不明白我做错了什么。谢谢!

有人建议我在比较fp时取出parantheses但是当我用

编译它时会收到编译器警告
gcc -ansi -W -Wall -pedantic 

警告如下:

assign2.c: In function ‘main’:
assign2.c:20:9: warning: assignment makes pointer from integer without a cast [enabled by default]
 if(fp = fopen(argv[argc - 1],"a+") == 0) {
     ^
 assign2.c:20:3: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
 if(fp = fopen(argv[argc - 1],"a+") == 0) {
 ^

3 个答案:

答案 0 :(得分:2)

原始代码

仔细看看这一行 - 它没有做你想做的事情:

if((fp = fopen(argv[2]),"a+") == 0) {
   ^          ^       ^     ^
   1          2       2     1

括号并未按您的意愿配对。您没有向fopen()传递足够的参数。并且您将"a+"0进行了比较。

你真的想要:

if ((fp = fopen(argv[2], "a+")) == 0) {

修订代码

在修订后的代码中,您似乎有:

if(fp = fopen(argv[argc - 1],"a+") == 0) {

这被解析为:

if (fp = (fopen(argv[argc - 1], "a+") == 0)) {

分配0或1的结果,将fopen()的返回值与0进行比较,而不是指针,因此抱怨assignment makes pointer from integer without a cast

关于suggest parentheses around assignment used as truth value的第二次警告表明了问题;赋值的结果用作条件,有时只是正确的(这是它不是的时间之一)。它通常出现在以下情境中:

if (i = j)

您可能打算:

if (i == j)

但是如果你真的想测试作业,那么你应该写:

if ((i = j) != 0)

或(消灭了这个想法 - 当人们这样做时我讨厌它!):

if ((i = j))

仍有问题......

  

但它仍然不会写入文件,

您在文件中只有一个读/写位置。您正在读取和写入同一文件fp。如果是stdin,您就会遇到一系列问题;如果它是一个普通的文本文件,你有另一套。

首先,在为更新而打开的文件上进行读取和写入(或写入和读取)之间,您必须主要执行定位操作 - fseek()rewind()。其次,因为您以附加模式打开文件,所有写入都发生在文件的末尾。这意味着当您在写入后尝试读取时,位置位于文件的末尾(即EOF)。

如果文件是标准输入,那通常是不可搜索的,这也有影响。标准输入(或者至少是Unix上的底层文件描述符0)通常是可写的,但这并不是你应该(ab)使用的东西。

  • 您需要输入文件和输出文件,或者需要正确搜索。

也许你想要"r+"而不是"a+"模式。

答案 1 :(得分:0)

好吧,长话短说我重写了代码以获得一个输入和输出文件,因为在不使用缓冲区的情况下覆盖当前文件会更复杂。

如果有任何问题或需要解释,请告诉我。

#include <stddef.h>
#include <stdio.h>
#include <string.h>

#define LINESIZE 1024

void display_dollar(FILE *, FILE *);

int main(int argc, char *argv[]) {
  FILE *infp = stdin;
  FILE *outfp = stdout;
  for (int i = 4; i < argc; ++i)
    fprintf(stderr, "Unknown argument: %s\n", argv[i]);
  if (argc >= 4 && (outfp = fopen(argv[3], "w")) == NULL)
    outfp = stdout;
  if (argc >= 3 && (infp = fopen(argv[2], "r")) == NULL)
    infp = stdin;
  if (argc >= 2 && strcmp("-e", argv[1]) == 0)
    display_dollar(infp, outfp);
  else
    fprintf(stderr, "Usage: %s -e [infile [outfile]]\n", argc ? argv[0] : "program");
  fclose(infp);
  fclose(outfp);
  return 0;
}

void remove_newlines(char *str) {
  for(long i = strlen(str)-1; i >= 0 && (str[i] == '\n' || str[i] == '\r'); --i)
    str[i] = '\0';
}

void display_dollar(FILE *infp, FILE *outfp) {
  char line[LINESIZE];
  while (fgets(line, LINESIZE, infp)) {
    remove_newlines(line);
    fprintf(outfp, "%s%c\n", line, '$');
  }
}

答案 2 :(得分:0)

此代码:

void display_dollar(FILE *fp) { 
     char line[LINESIZE]; 
     char lines[LINESIZE];  
        while(fgets(line,LINESIZE,fp)) { 
            sscanf(line,"%s\n",lines);
            if(fp == stdin) { 
               printf("%s%c\n",lines,'$'); 
               lines[0] = '\0'; /* "clear" buffer */
            } else { 
               fprintf(fp,"%s%c\n",lines,'$'); 
               lines[0] = '\0'; /* "clear" buffer */
            } 
      }
}

1) changes the number of characters in the next line, so the output file will be corrupted.
2) each read/write to the file moves the file-position-pointer.
   you could use ftell() to see this happening.
3) the code must not corrupt the file, so it will have to write a new file.
4) this has a logic error, the %s will stop when any white space is encountered.  
This includes newlines (of which there will (almost) always be one
or any tab or any space.
then appending a '$' will overlay something in the line.
therefore, the line to output will be corrupted.
the corruption could be a space or a NUL or a tab or a newline being overlayed

Suggestions:
1)  When outputting to a file, always create a new file
2)  always find the newline with strstr() (or similar), overlay the newline with "$\0",
    then strcat()  "\n\0"

这意味着修改display_dollar()声明以包含输入和输出文件指针