我正在尝试读取一个文件并用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并退出。
答案 0 :(得分:3)
处理在更新模式下打开的文件时必须小心。
C11(n1570),§7.21.5.3
fopen
函数以更新模式打开文件时(
'+'
作为第二个或第三个字符) 在上面的模式参数值列表中,输入和输出都可以在上面执行 相关流。但是,如果没有输入,输出不应直接输入 干预调用
fflush
函数或文件定位函数(fseek
,fsetpos
或rewind
),输入不得直接跟随没有输出的输出 干预调用文件定位函数,除非输入操作遇到文件结尾。
所以你的阅读可能看起来像:
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)
执行随机访问的程序
以下代码是考虑它的重写。
#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数组中,迭代它然后最终将整个文件写入清空的输入文件中?没有流问题。