C读取并替换char

时间:2013-04-27 16:37:07

标签: c

我正在尝试读取一个文件并用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 个答案:

答案 0 :(得分:3)

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

  

C11(n1570),§7.21.5.3fopen函数

     

以更新模式打开文件时('+'作为第二个或第三个字符)    在上面的模式参数值列表中,输入和输出都可以在上面执行   相关流。

     

但是,如果没有输入,输出不应直接输入   干预调用fflush函数或文件定位函数(fseek,    fsetposrewind),输入不得直接跟随没有输出的输出   干预调用文件定位函数,除非输入操作遇到文件结尾。

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

int c;

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

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

答案 1 :(得分: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(),它可以让你四处走动。请记住在"rb+"之后打开flush()fputc()的文件。

如果您已经解决了这个基本问题,您会注意到您的方法存在另一个问题:处理换行符!您最有可能限制应用“增量”的字符范围,并规定a跟在z之后A跟在Z之后。

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

答案 2 :(得分:2)

<强> 7.21.9.1p2

  

fgetpos函数存储解析状态的当前值(如果   任何)和流指向的流的文件位置指示符   在pos指向的对象中。存储的值包含未指定的值   fsetpos函数可用于重新定位的信息   在调用fgetpos时流到它的位置   功能

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

fgetc会返回int,因此它可以表示与负unsigned char值不同的每个EOF值。

假设您的char默认为无符号类型。 (ch = fgetc(input))将(可能为负数,对应错误)返回值直接转换为无符号char类型。 (unsigned char) EOF可以比较EOF吗?你的循环何时结束?

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

这两个问题的答案都表明您错误地处理了fgetc的返回值。 将其存储在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);
}

确保检查返回值...

答案 3 :(得分:2)

执行随机访问的程序

  1. 定位记录
  2. 阅读记录
  3. 定位记录
  4. 更新(写)记录
  5. 执行刷新(以完成更新)
  6. 以下代码是考虑它的重写。

    #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;
    }
    

答案 4 :(得分:1)

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