尝试包含行和列的文件 I/O,定位文件时出现问题 *
Attempting File I/O with lines and columns, problems with positioning the FILE *
我正在尝试编写 2 个函数:
- 将 FILE* 移动到传递的索引
- 其他,将 FILE* 中的内容从 2 个索引复制到字符串。
出现了非常莫名其妙的错误,我已经修复好几个小时了,快崩溃了,请指出我的愚蠢。
观察到的行为:
chknbuff()
正在跳过最后一个字符,所以我录制了一些可以解决该问题的代码。
- 阅读超过第一行(例如 ln=2,col=x)会在其他文件中触发
chkncpy()
中的 EOF 错误。
- 抑制
chknmove()
的 EOF 警告给出 Segmentation Fault
s ,这意味着确实遇到了 EOF
。
代码:
#include <stdio.h>
/*-------Function-Definitions------------*/
int chknmove(FILE *tomove,long long line,long long col){
// moves FILE * to line & col passed
rewind(tomove); int chk,f; long long i,q; i=0; q=0; f=0;
if(line>=1 && col>=1){
while(i < line){
chk = fgetc(tomove);
if(chk == EOF){
printf("\n Invalid Index.\n");f=-1;break;
}
else if(chk == '\n'){
if(i == line - 1){
printf("\n Invalid Index.\n");f=-1;break;
}
i++; q = 0;
}
else if(i == line - 1 && q == col - 1){
break;
}
else
q++;
}
if(f==0)
fseek(tomove,-1,SEEK_CUR);
}
else{
printf("\n Invalid Index.\n");f=-1;
}
return f;
}
int chknbuff(FILE *source, char *dest, long long beginln, long long begincol, long long endln, long long endcol){
// copies file contents from beginning line&cols to end lines&cols to a string.
int z = chknmove(source,beginln,begincol);
if(z==0){
int chk; long long i,q,m; i=0; q=0; m=0; //endcol++;
if(endln>=1 && endcol>=1 && endln>=beginln){
while(i < endln){
chk = fgetc(source);
if(chk == EOF){
printf("\n Invalid Index1.\n");z=-1;break;
}
else if(chk == '\n'){
if(i == endln-1){
printf("\n Invalid Index2.\n");z=-1;break;
}
dest[m]=chk;m++; i++; q = 0;
}
else if(i == endln-1 && q == endcol-1 ){
break;
}
else{
dest[m]=chk;m++; q++;
}
}
if(z==0){
fseek(source,-1,SEEK_CUR);
chk = fgetc(source);
if(chk!=EOF)
dest[m]=chk; m++;
}
dest[m++]='[=11=]';
}
else{
printf("\n Invalid Index3.\n");z=-1;
}
}
return z;
}
/*---------------------------------------------*/
int main(){
FILE * write = fopen("xyz","w");
if(write == NULL)
perror("\n Error ");
else{
printf("\n Filename : "); char fpart[501]; scarf("%500[^\n]",fpart); FILE * part = fopen(fpart,"r");
if(part==NULL)
perror("\n Error ");
else{
long long beginln, begincol, endln, endcol; char sep1,sep2;
printf("\n Starting Index : "); scanf("%lld%c%lld",&beginln,&sep1,&begincol); eat();
printf("\n Terminating Index : "); scanf("%lld%c%lld",&endln,&sep2,&endcol); eat();
char buff[MAX_F_BUFF];int f = chknbuff(part,buff,beginln,begincol,endln,endcol);
if(f==0)
fputs(buff,write);
}
int d = fclose(write);
if(d==EOF)
perror("\n Failed ");
else
printf("\n Success.\n");
}
return 0;
}
如果需要任何额外的信息,请评论,我会尽力添加
在这个 self-answer 中,我 post 我的方法为我解决了这个问题。我在问题中的功能有点拙劣和混乱,这里不再是。
我已经从 dxiv's answer 那里借来解决了它,并且我自己干预了如何处理 '\n'
字符。它工作得很好 afaik.
希望对以后的其他人有所帮助。
我需要的功能:
int chknmove(FILE *tomove, long long line, long long col){
/* Moves FILE* to given ((line,col) -1 char) , such that next char read from FILE* will be @ (line,col)
Checks validity of index as it moves : if col not in line || EOF encountered, returns -1. */
rewind(tomove); // rewind file 'just in case'
int f = 0 ; // control variable which stores state (succeeded/failed) of chknmove()
if (line < 1 || col < 1)
{
f=-1;
printf("\n Illegal Index.\n");
// Follows 1-based line/col index : -ve values are illegal
return -1;
}
else {
long long i,q; i = q = 0; // i = lines encountered ; q = chars encountered in line i ; both are 0-based
while(i < line){
int chk = fgetc(tomove); //
if(chk == EOF){
printf("\nInvalid %s - beyond EOF.\n", (i == line -1 ) ? "Column" : "Line");
f = -1; break;
}
else if(chk == '\n'){
if(i==line-1 && q == col-1)
/* 1. This allows for user to directly point to the '\n' char , allowing him to append to line
2.(line/col - 1) : since i & q are 0-based */
break;
else{
if(i == line-1 ){
// except if target index was the '\n' , reading beyond newline @ target line is invalid, since '\n' terminates line
printf("\nInvalid column for line %lld.\n",line);
f=-1; break;
}
i++; q=0; // if not @ target line , reset and continue
}
}
else if(i == line-1 && q == col-1 ) // if dest index reached, break .
break;
else // if non-EOF , non-\n char encountered, increment q and continue.
q++;
}
if(f==0){
fseek(tomove,-1,SEEK_CUR); // So that the after returning/exiting chknmove() , the char read from FILE* is @ line,col
return 0;
}
else
return -1;
}
}
AND
int chknbuff(FILE* source, char *dest, long long beginln, long long begincol, long long endln, long long endcol) {
/* Copies everything from FILE *source to char *dest within begining index and terminating index , if they're valid
Returns -1 if they're invalid.*/
if (beginln < 1 || begincol < 1 || endln < beginln || endcol < ((endln == beginln) ? begincol : 1))
// -ve indexes and reading/writing backwards is illegal
return -1;
long long i, q; // i -> lines && q -> chars
int f=0; long long m = 0;
if(chknmove(source,beginln,begincol)==0){
// checked if begining index is valid and if so, moved to it.
i=beginln; q=begincol; // i & q have same base as line & col , so 1-based
while(1){
int ch = fgetc(source);
if(ch==EOF){
printf("\nInvalid Terminating Index.\n");
f=-1; break;
}
else if(ch=='\n'){
if(i==endln && q==endcol){
dest[m]=ch; m++;
break;
}
else{
if(i==endln){
printf("Invalid column for line %lld.\n",endln);
f=-1; break;
}
i++; q=1; // q set to 1 -> q is 1-based !
dest[m]=ch; m++;
}
}
else if(i==endln && q==endcol){
dest[m]=ch; m++; break;
}
else{
q++; dest[m]=ch; m++;
}
}
}
else
f=-1;
dest[m]='[=11=]'; // null terminate the buffer
if(f==0) return 0;
else return -1;
}
如有遗漏errors/details欢迎留言,我会尽快回复
以下是对我的评论“你可以用一个函数完成所有操作”的扩展,并通过一次文件传递完成。 range 中的字符用 putchar(chk);
打印,可以替换为 fputc(chk, write);
或 dest[count] = chk;
以保存到文件或字符串缓冲区。
#include <stdio.h>
#include <stdlib.h>
// return number of characters in 'copy' range between (beginline, begincol) and (endline, endcol)
// line/col are 1-based and the 'copy' range is inclusive of both begin/end positions
long long copy_range(FILE* fyl, long long beginln, long long begincol, long long endln, long long endcol) {
long long line, col, count; int chk;
if (beginln < 1 || begincol < 1 || endln < beginln || (endln == beginln && endcol < begincol))
return -1;
// assume current file position is at the beginning, maybe 'rewind' if that's not guaranteed
line = 1; col = 1; count = -1;
// read the file sequentially
// start saving characters once (beginline, begincol) is reached
// break out of the loop after (endline, endcol) is reached
do {
// attempt to read character at position (line, col)
chk = fgetc(fyl);
// attempt failed, return error
// check count to see whether it happened before or within the 'copy' range
// check line to see if the entire line is past EOF vs. just the target column
if (chk == EOF) {
printf("\nInvalid %s %s.\n",
(count < 0) ? "Beginning" : "Ending",
(line == beginln) ? "Column" : "Line");
break;
}
// found newline character
if (chk == '\n') {
// error if looking for (beginln, begincol) and newline found on beginln before begincol
// or if looking for (endln, endcol) and newline found on endln before endcol
if (line == ((count < 0) ? beginln : endln)) {
printf("\nInvalid %s Column.\n",
(count < 0) ? "Beginning" : "Ending");
break;
}
// comment the following if *not* preserving newlines in 'copy' range
if (count >= 0) {
putchar(chk); count++;
}
// update position and move on
line++; col = 1; continue;
}
if (line == beginln && col == begincol) {
// enter the 'copy' range, start counting
printf("--- begin ---\n"); count = 0;
}
if (count >= 0) {
// save character if within the 'copy' range
putchar(chk); count++;
}
if (line == endln && col == endcol) {
// leave the 'copy' range, return the count
// if saving to a string, add the nul-terminator here, but do not increment counter
printf("\n---- end ----\n"); break;
}
col++;
} while (line <= endln);
return count;
}
int main() {
char fpart[501];
printf("\nEnter Filename:\n");
if (scanf("%500[^\n]", fpart) != 1) return -1;;
FILE* part = fopen(fpart, "r");
if (part == NULL) return errno;
long long beginln, begincol, endln, endcol;
printf("\nEnter Starting Index:\n");
if (scanf("%lld %lld", &beginln, &begincol) != 2) return -2;;
printf("\nEnter Terminating Index:\n");
if (scanf("%lld %lld", &endln, &endcol) != 2) return -3;
return copy_range(part, beginln, begincol, endln, endcol) > 0;
}
[ EDIT ] 在评论之后,澄清意味着将换行符计算为前一行的最后一个位置,这是对上面的修改,它移动了 '\n'
在字符被处理后检查,并删除现在多余的换行符回显。
long long copy_range(FILE* fyl, long long beginln, long long begincol, long long endln, long long endcol) {
long long line, col, count; int chk;
if (beginln < 1 || begincol < 1 || endln < beginln || endcol < ((endln == beginln) ? begincol : 1))
return -1;
line = 1; col = 1; count = -1;
do {
chk = fgetc(fyl);
if (chk == EOF) {
printf("\nInvalid %s %s.\n",
(count < 0) ? "Beginning" : "Ending",
(line == beginln) ? "Column" : "Line");
break;
}
if (line == beginln && col == begincol) {
printf("--- begin ---\n"); count = 0;
}
if (count >= 0) {
putchar(chk); count++;
}
if (line == endln && col == endcol) {
printf("\n---- end ----\n"); break;
}
if (chk == '\n') {
if (line == ((count < 0) ? beginln : endln)) {
printf("\nInvalid %s Column.\n",
(count < 0) ? "Beginning" : "Ending");
break;
}
line++; col = 1;
}
else
col++;
} while (line <= endln);
return count;
}
我正在尝试编写 2 个函数:
- 将 FILE* 移动到传递的索引
- 其他,将 FILE* 中的内容从 2 个索引复制到字符串。
出现了非常莫名其妙的错误,我已经修复好几个小时了,快崩溃了,请指出我的愚蠢。
观察到的行为:
chknbuff()
正在跳过最后一个字符,所以我录制了一些可以解决该问题的代码。- 阅读超过第一行(例如 ln=2,col=x)会在其他文件中触发
chkncpy()
中的 EOF 错误。 - 抑制
chknmove()
的 EOF 警告给出Segmentation Fault
s ,这意味着确实遇到了EOF
。
代码:
#include <stdio.h>
/*-------Function-Definitions------------*/
int chknmove(FILE *tomove,long long line,long long col){
// moves FILE * to line & col passed
rewind(tomove); int chk,f; long long i,q; i=0; q=0; f=0;
if(line>=1 && col>=1){
while(i < line){
chk = fgetc(tomove);
if(chk == EOF){
printf("\n Invalid Index.\n");f=-1;break;
}
else if(chk == '\n'){
if(i == line - 1){
printf("\n Invalid Index.\n");f=-1;break;
}
i++; q = 0;
}
else if(i == line - 1 && q == col - 1){
break;
}
else
q++;
}
if(f==0)
fseek(tomove,-1,SEEK_CUR);
}
else{
printf("\n Invalid Index.\n");f=-1;
}
return f;
}
int chknbuff(FILE *source, char *dest, long long beginln, long long begincol, long long endln, long long endcol){
// copies file contents from beginning line&cols to end lines&cols to a string.
int z = chknmove(source,beginln,begincol);
if(z==0){
int chk; long long i,q,m; i=0; q=0; m=0; //endcol++;
if(endln>=1 && endcol>=1 && endln>=beginln){
while(i < endln){
chk = fgetc(source);
if(chk == EOF){
printf("\n Invalid Index1.\n");z=-1;break;
}
else if(chk == '\n'){
if(i == endln-1){
printf("\n Invalid Index2.\n");z=-1;break;
}
dest[m]=chk;m++; i++; q = 0;
}
else if(i == endln-1 && q == endcol-1 ){
break;
}
else{
dest[m]=chk;m++; q++;
}
}
if(z==0){
fseek(source,-1,SEEK_CUR);
chk = fgetc(source);
if(chk!=EOF)
dest[m]=chk; m++;
}
dest[m++]='[=11=]';
}
else{
printf("\n Invalid Index3.\n");z=-1;
}
}
return z;
}
/*---------------------------------------------*/
int main(){
FILE * write = fopen("xyz","w");
if(write == NULL)
perror("\n Error ");
else{
printf("\n Filename : "); char fpart[501]; scarf("%500[^\n]",fpart); FILE * part = fopen(fpart,"r");
if(part==NULL)
perror("\n Error ");
else{
long long beginln, begincol, endln, endcol; char sep1,sep2;
printf("\n Starting Index : "); scanf("%lld%c%lld",&beginln,&sep1,&begincol); eat();
printf("\n Terminating Index : "); scanf("%lld%c%lld",&endln,&sep2,&endcol); eat();
char buff[MAX_F_BUFF];int f = chknbuff(part,buff,beginln,begincol,endln,endcol);
if(f==0)
fputs(buff,write);
}
int d = fclose(write);
if(d==EOF)
perror("\n Failed ");
else
printf("\n Success.\n");
}
return 0;
}
如果需要任何额外的信息,请评论,我会尽力添加
在这个 self-answer 中,我 post 我的方法为我解决了这个问题。我在问题中的功能有点拙劣和混乱,这里不再是。
我已经从 dxiv's answer '\n'
字符。它工作得很好 afaik.
希望对以后的其他人有所帮助。
我需要的功能:
int chknmove(FILE *tomove, long long line, long long col){
/* Moves FILE* to given ((line,col) -1 char) , such that next char read from FILE* will be @ (line,col)
Checks validity of index as it moves : if col not in line || EOF encountered, returns -1. */
rewind(tomove); // rewind file 'just in case'
int f = 0 ; // control variable which stores state (succeeded/failed) of chknmove()
if (line < 1 || col < 1)
{
f=-1;
printf("\n Illegal Index.\n");
// Follows 1-based line/col index : -ve values are illegal
return -1;
}
else {
long long i,q; i = q = 0; // i = lines encountered ; q = chars encountered in line i ; both are 0-based
while(i < line){
int chk = fgetc(tomove); //
if(chk == EOF){
printf("\nInvalid %s - beyond EOF.\n", (i == line -1 ) ? "Column" : "Line");
f = -1; break;
}
else if(chk == '\n'){
if(i==line-1 && q == col-1)
/* 1. This allows for user to directly point to the '\n' char , allowing him to append to line
2.(line/col - 1) : since i & q are 0-based */
break;
else{
if(i == line-1 ){
// except if target index was the '\n' , reading beyond newline @ target line is invalid, since '\n' terminates line
printf("\nInvalid column for line %lld.\n",line);
f=-1; break;
}
i++; q=0; // if not @ target line , reset and continue
}
}
else if(i == line-1 && q == col-1 ) // if dest index reached, break .
break;
else // if non-EOF , non-\n char encountered, increment q and continue.
q++;
}
if(f==0){
fseek(tomove,-1,SEEK_CUR); // So that the after returning/exiting chknmove() , the char read from FILE* is @ line,col
return 0;
}
else
return -1;
}
}
AND
int chknbuff(FILE* source, char *dest, long long beginln, long long begincol, long long endln, long long endcol) {
/* Copies everything from FILE *source to char *dest within begining index and terminating index , if they're valid
Returns -1 if they're invalid.*/
if (beginln < 1 || begincol < 1 || endln < beginln || endcol < ((endln == beginln) ? begincol : 1))
// -ve indexes and reading/writing backwards is illegal
return -1;
long long i, q; // i -> lines && q -> chars
int f=0; long long m = 0;
if(chknmove(source,beginln,begincol)==0){
// checked if begining index is valid and if so, moved to it.
i=beginln; q=begincol; // i & q have same base as line & col , so 1-based
while(1){
int ch = fgetc(source);
if(ch==EOF){
printf("\nInvalid Terminating Index.\n");
f=-1; break;
}
else if(ch=='\n'){
if(i==endln && q==endcol){
dest[m]=ch; m++;
break;
}
else{
if(i==endln){
printf("Invalid column for line %lld.\n",endln);
f=-1; break;
}
i++; q=1; // q set to 1 -> q is 1-based !
dest[m]=ch; m++;
}
}
else if(i==endln && q==endcol){
dest[m]=ch; m++; break;
}
else{
q++; dest[m]=ch; m++;
}
}
}
else
f=-1;
dest[m]='[=11=]'; // null terminate the buffer
if(f==0) return 0;
else return -1;
}
如有遗漏errors/details欢迎留言,我会尽快回复
以下是对我的评论“你可以用一个函数完成所有操作”的扩展,并通过一次文件传递完成。 range 中的字符用 putchar(chk);
打印,可以替换为 fputc(chk, write);
或 dest[count] = chk;
以保存到文件或字符串缓冲区。
#include <stdio.h>
#include <stdlib.h>
// return number of characters in 'copy' range between (beginline, begincol) and (endline, endcol)
// line/col are 1-based and the 'copy' range is inclusive of both begin/end positions
long long copy_range(FILE* fyl, long long beginln, long long begincol, long long endln, long long endcol) {
long long line, col, count; int chk;
if (beginln < 1 || begincol < 1 || endln < beginln || (endln == beginln && endcol < begincol))
return -1;
// assume current file position is at the beginning, maybe 'rewind' if that's not guaranteed
line = 1; col = 1; count = -1;
// read the file sequentially
// start saving characters once (beginline, begincol) is reached
// break out of the loop after (endline, endcol) is reached
do {
// attempt to read character at position (line, col)
chk = fgetc(fyl);
// attempt failed, return error
// check count to see whether it happened before or within the 'copy' range
// check line to see if the entire line is past EOF vs. just the target column
if (chk == EOF) {
printf("\nInvalid %s %s.\n",
(count < 0) ? "Beginning" : "Ending",
(line == beginln) ? "Column" : "Line");
break;
}
// found newline character
if (chk == '\n') {
// error if looking for (beginln, begincol) and newline found on beginln before begincol
// or if looking for (endln, endcol) and newline found on endln before endcol
if (line == ((count < 0) ? beginln : endln)) {
printf("\nInvalid %s Column.\n",
(count < 0) ? "Beginning" : "Ending");
break;
}
// comment the following if *not* preserving newlines in 'copy' range
if (count >= 0) {
putchar(chk); count++;
}
// update position and move on
line++; col = 1; continue;
}
if (line == beginln && col == begincol) {
// enter the 'copy' range, start counting
printf("--- begin ---\n"); count = 0;
}
if (count >= 0) {
// save character if within the 'copy' range
putchar(chk); count++;
}
if (line == endln && col == endcol) {
// leave the 'copy' range, return the count
// if saving to a string, add the nul-terminator here, but do not increment counter
printf("\n---- end ----\n"); break;
}
col++;
} while (line <= endln);
return count;
}
int main() {
char fpart[501];
printf("\nEnter Filename:\n");
if (scanf("%500[^\n]", fpart) != 1) return -1;;
FILE* part = fopen(fpart, "r");
if (part == NULL) return errno;
long long beginln, begincol, endln, endcol;
printf("\nEnter Starting Index:\n");
if (scanf("%lld %lld", &beginln, &begincol) != 2) return -2;;
printf("\nEnter Terminating Index:\n");
if (scanf("%lld %lld", &endln, &endcol) != 2) return -3;
return copy_range(part, beginln, begincol, endln, endcol) > 0;
}
[ EDIT ] 在评论之后,澄清意味着将换行符计算为前一行的最后一个位置,这是对上面的修改,它移动了 '\n'
在字符被处理后检查,并删除现在多余的换行符回显。
long long copy_range(FILE* fyl, long long beginln, long long begincol, long long endln, long long endcol) {
long long line, col, count; int chk;
if (beginln < 1 || begincol < 1 || endln < beginln || endcol < ((endln == beginln) ? begincol : 1))
return -1;
line = 1; col = 1; count = -1;
do {
chk = fgetc(fyl);
if (chk == EOF) {
printf("\nInvalid %s %s.\n",
(count < 0) ? "Beginning" : "Ending",
(line == beginln) ? "Column" : "Line");
break;
}
if (line == beginln && col == begincol) {
printf("--- begin ---\n"); count = 0;
}
if (count >= 0) {
putchar(chk); count++;
}
if (line == endln && col == endcol) {
printf("\n---- end ----\n"); break;
}
if (chk == '\n') {
if (line == ((count < 0) ? beginln : endln)) {
printf("\nInvalid %s Column.\n",
(count < 0) ? "Beginning" : "Ending");
break;
}
line++; col = 1;
}
else
col++;
} while (line <= endln);
return count;
}