微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 fputc() 附加到我的文件而不覆盖它?

如何解决为什么 fputc() 附加到我的文件而不覆盖它?

我正在编写一个 C 程序,它将某个文件中的所有大写字符更改为小写。问题是,在将所有字符(已处理)存储在一个字符串中并尝试打印该文件中的所有字符后,它们会被附加到该文件中,而不会被覆盖。我正在使用 "r+" 作为权限。

这是我的代码

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

#define MAX 1024

int main(int argc,char **argv)
{
    if (argc != 2) {
        printf("Invalid number of arguments.\n");
        exit(1);
    }

    FILE *f = fopen(argv[1],"r+");
    if (f == NULL)
    {
        printf("Could not open specified file.\n");
        exit(2);
    }

    char buf[MAX];
    int len = 0;
    
    while(!feof(f))
    {
        int c = fgetc(f);
        if (c >= 'A' && c <= 'Z')
            c = tolower(c);
        if (c != EOF) {
            buf[len] = c;
            len++;
        }
    }

    for (int i = 0; buf[i] != '\0'; i++)
        fputc(buf[i],f);

    fclose(f);

    return 0;
}

fputs(buf,f) 也有同样的问题。即使在附加后,所选文件的末尾也会出现一些“奇怪”的字符。

到底是什么问题?我该如何解决?谢谢你。将不胜感激。

解决方法

由于多种原因,您的程序有错误甚至未定义的行为:

  • while(!feof(f)) 不能可靠地检测到文件结尾,feof() 被设置之后f 读取失败的尝试失败。你应该写:

      while ((c = getc(f)) != EOF) {
          if (isupper(c))
              c = tolower(c);
          ...
    
  • 使用 if (c >= 'A' && c <= 'Z') 进行大写测试适用于 ASCII,但对于 EBCDIC 会失败。您可以改为使用 isupper(c) 或无条件使用 tolower(c)

  • 读取和写入同一个文件,使用 "r+" 打开读取和更新模式,需要调用 fseek()rewind() 以从读取更改为写入,反之亦然反之。

  • 您不检查 len 是否停留在 buf 的边界内,从而在尝试超出数组末尾写入足够长的输入时导致未定义的行为。

  • 您没有在 buf[len] 处设置空终止符,因此调用 fputs(buf,f) 具有未定义的行为,因为 buf 不是正确的 C 字符串。类似地,已发布代码中的循环在 buf[i] != '\0' 中进行迭代,这会导致未定义的行为,因为在从文件读取的数据的末尾尚未设置此空终止符。

这是修改后的版本:

#include <ctype.h>
#include <stdio.h>

int main(int argc,char *argv[]) {
    FILE *f;
    int c;

    if (argc != 2) {
        printf("Invalid number of arguments.\n");
        return 1;
    }

    if ((f = fopen(argv[1],"r+")) == NULL) {
        printf("Could not open file %s.\n",argv[1]);
        return 2;
    }

    while ((c = getc(f)) != EOF) {
        if (isupper(c) {
            fseek(f,-1L,SEEK_CUR);
            putc(tolower(c),f);
            fseek(f,0L,SEEK_CUR);
        }
    }
    fclose(f);
    return 0;
}

请注意,从文件中读取并写入不同的文件会更有效和可靠。您可以尝试这个简单的过滤器,并与上面的大文件代码进行比较:

#include <ctype.h>
#include <stdio.h>

int main() {
    int c;
    while ((c = getchar()) != EOF) {
        putchar(tolower(c));
    }
    return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。