首页 文章

C读取并替换char

提问于
浏览
2

我正在尝试读取一个文件并用ASCII表中相应的char up替换每个char . 它会正确打开文件,但继续阅读第一个字符 .

int main(int argc, char * argv[])
{
    FILE *input;
    input = fopen(argv[2], "r+");
    if (!input)
    {
        fprintf(stderr, "Unable to open file %s", argv[2]);
        return -1;
    }

    char ch;
    fpos_t * pos;
    while( (ch = fgetc(input)) != EOF)
    {
            printf("%c\n",ch);
            fgetpos (input, pos);
            fsetpos(input, pos-1);
            fputc(ch+1, input);
    }
    fclose(input);
    return 1;
}

文本文件是

abc
def
ghi

我很确定这是由于fgetpos和fsetpos,但是如果我将其删除,那么它将在文件的末尾添加字符,下一个fgetc将返回EOF并退出 .

5 回答

  • 2

    procedure for performing random access such

    • 定位了记录

    • 读取记录

    • 定位了记录

    • 更新(写)记录

    • 执行刷新(以完成更新)

    以下代码是考虑它的重写 .

    #include <stdio.h>
    #include <ctype.h>
    
    int main(int argc, char * argv[]){
        FILE *input;
        input = fopen(argv[1], "rb+");
        if (!input){
            fprintf(stderr, "Unable to open file %s", argv[1]);
            return -1;
        }
    
        int ch;
        fpos_t pos, pos_end;
        fgetpos(input, &pos);
        fseek(input, 0L, SEEK_END);
        fgetpos(input, &pos_end);
        rewind(input);
        while(pos != pos_end){
            ch=fgetc(input);
            if(EOF==ch)break;
            printf("%c",ch);
            if(!iscntrl(ch) && !iscntrl(ch+1)){
                fsetpos(input, &pos);
                fputc(ch+1, input);
                fflush(input);
            }
            pos += 1;
            fsetpos(input, &pos);
        }
        fclose(input);
        return 1;
    }
    
  • 2

    处理在更新模式下打开的文件时必须小心 .

    C11(n1570),§7.21.5.3fopen函数当使用更新模式打开文件时(''作为上述模式参数值列表中的第二个或第三个字符),可以对相关联的输入和输出执行流 . 但是,如果没有对fflush功能或文件定位功能(fseek,fsetpos或倒带)的干预调用,输出不应直接输入,并且输入不应直接跟随输出而不干预文件定位函数,除非输入操作遇到文件结尾 .

    所以你的阅读可能看起来像:

    int c;
    
    while ((c = getc(input)) != EOF)
    {
        fsetpos(/* ... */);
        putc(c + 1, input);
        fflush(input);
    }
    

    顺便说一句,你会遇到 'z' 字符的问题 .

  • 2

    我真的怀疑问题在这里:

    fpos_t * pos;
    

    你正在声明一个指向 fpos_t 的指针,这很好,但是当你检索pos时,存储的信息在哪里?

    它应该是:

    fpos_t pos; // No pointer
      ...
         fgetpos (input, &pos);
         fsetpos(input, &pos);  // You can only come back where you were!
    

    阅读(草案)标准, fpos_t 的唯一要求是能够代表 FILE 的位置和状态,似乎没有办法移动位置 .

    注意表达式 pos+1 移动指针,不影响它指向的值!

    你可能想要的是旧的,亲爱的 ftell()fseek() ,它可以让你四处走动 . 只需记住在 fputc() 之后用 "rb+"flush() 打开文件 .

    如果您已经解决了这个基本问题,您会注意到您的方法存在另一个问题:处理换行符!你很可能应该限制你将应用"increment"的字符范围,并规定 a 跟随 zA 跟随 Z .

    那就是说,是否需要就地进行?

  • 1

    7.21.9.1p2

    fgetpos函数存储解析状态的当前值(如果有)和由pos指向的对象中的流指向的流的文件位置指示符 . 存储的值包含fsetpos函数可用的未指定信息,用于在调用fgetpos函数时将流重新定位到其位置 .

    未明确的信息似乎并没有激发对减法的信心 . 您是否考虑在阅读角色之前调用 fgetpos ,这样您就不必进行非便携式减法?此外,您对 fgetpos 的调用可能应该传递指向现有 fpos_t 的指针(例如,使用 &address-of 运算符) . 您的代码当前传递指向乱码的指针 .

    fgetc 返回 int ,以便它可以表示与负 EOF 值不同的每个可能的 unsigned char 值 .

    假设您的 char 默认为无符号类型 . (ch = fgetc(input)) 将(可能为负,对应于错误)返回值直接转换为无符号 char 类型 . (unsigned char) EOF 能否等于 EOF ?你的循环什么时候结束?

    假设您的 char 默认为 signed type . (c = fgetc(input)) 可能会将任何返回的 unsigned char 值的较高范围转换为负数(但从技术上讲,此语句会调用未定义的行为) . 在某些情况下,你的循环不会过早结束(例如在EOF之前)吗?

    这两个问题的答案都表明您正在错误地处理 fgetc 的返回值 . Store it in an int!

    也许您的循环应该类似于:

    for (;;) {
        fpos_t p;
    
        /* TODO: Handle fgetpos failure */
        assert(fgetpos(input, &p) == 0);
    
        int c = fgetc(input);
    
        /* TODO: Handle fgetc failure */
        assert(c >= 0);
    
        /* TODO: Handle fsetpos failure */
        assert(fsetpos(input, &p) == 0);
    
        /* TODO: Handle fputc failure */
        assert(fputc(c + 1, input) != EOF);
    
        /* TODO: Handle fflush failure (Thank Kirilenko for this one) */
        assert(fflush(input) == 0);
    }
    

    确保检查返回值...

  • 2

    更新模式('')处理起来有点棘手 . 也许你可以改变方法并将整个文件加载到char数组中,迭代它然后最终将整个文件写入清空的输入文件中?没有流问题 .

相关问题