C 试图';插入';或';添加';变成一个文本文件-一个小问题

C 试图';插入';或';添加';变成一个文本文件-一个小问题,c,file,file-io,file-pointer,C,File,File Io,File Pointer,代码M.R.E已提供 症状“简单”: 在hello\nhello\nhelleof&插入'\'-ln=2&col=1(或者更确切地说是任何line>1&&col==1)时,程序奇怪地做得很好,但会吃掉'\n',导致第2行与第1行融合在一起,而不是你好\n\u你好\n你好 尝试在文件最后一行的a字符上插入“”@ln=3&col=5(或者更确切地说,在由EOF终止的行中的任何字符上插入“col>1)结果它跳过了行的最后一个实际字符:hello\nhello\nhellu EOF,而不是hello\n

代码M.R.E已提供

症状“简单”:

  • hello\nhello\nhelleof
    &插入'
    \
    '-
    ln=2
    &
    col=1
    (或者更确切地说是任何
    line>1&&col==1
    )时,程序奇怪地做得很好,但会吃掉
    '\n'
    ,导致第2行与第1行融合在一起,而不是
    你好\n\u你好\n你好
  • 尝试在文件最后一行的a字符上插入“
    ”@
    ln=3
    &
    col=5
    (或者更确切地说,在由EOF终止的行中的任何字符上插入“
    col>1
    )结果它跳过了行的最后一个实际字符:
    hello\nhello\nhellu EOF
    ,而不是
    hello\nhello\nhellu EOF
  • 尝试使用最后一行中的第一个字符(
    col==1
    ,在由EOF终止的行中)将导致抛出错误消息(
    \n无效索引。
  • 就我的直觉而言,我认为在处理行终止(
    '\n'
    EOF
    )&它是如何计算的,以及通常的循环计数器时有一个缺陷,但我不明白

    想法/算法:

    • 从用户获取源文件
    • 从用户处获取索引(行、列)
    • 从源文件复制到tmp文件,直到(用户索引-1列)
    • 现在,允许用户将字符串写入tmp文件的缓冲区
    • 一旦用户终止输入,从用户索引复制到tmp,直到
      EOF
    • 重命名/删除+将tmp重命名为用户的源文件名
    下面的代码完成了所有真正的对话:

    #包括
    #包括
    /*chknmove()、chkncpy()和/或main()中可能存在的错误区域;
    还提供了使用的所有其他功能*/
    长lncnt(文件*lcount){
    /*使用fgets()统计文件中的行数*/
    倒带(lcount);/*确保从开始计算行数*/
    长行=0;字符行[501];
    while((fgets(第501行,lcount))!=NULL){
    行++;
    }
    倒带(lcount);/*将fptr保留为@0,0,而不是EOF*/
    回流线;
    }
    int chknmove(文件*tomove,长行,长列){
    /*用于检查并将文件*移动到特定行/列的函数*/
    倒带(tomove);/*确保fptr位于文件的开头*/
    int f=0;/*将check变量设置为0表示成功*/
    
    如果(行您的代码太复杂:

    • 复制文件开头的不同情况应合并到单个函数调用中,该函数调用将数据复制到第
      上的列
      col
      处的字节(不包括该字节)

    • 然后从用户输入进行复制

    • 最后复制输入文件的其余部分

    • 代码假定行和列从
      1
      开始编号。这可能是显而易见的,但您应该指定这一点,因为这可能不是每个人都能看到的

    • 这种风格很难理解:你应该在二进制运算符周围使用水平空格,在关键字,
      之后和
      {
      之前。在一行上塞满多个语句也不是一个好主意

    以下是一个简化版本。通常,大多数代码都用于错误处理:

    #包括
    #包括
    void flush_行(FILE*fp){/*读取当前行的其余部分*/
    INTC;
    而((c=getc(fp))!='\n'&&c!=EOF)
    继续;
    }
    int copy_文件(文件*从,文件*到){
    INTC;
    而((c=getc(from))!=EOF){
    if(putc(c,to)=EOF)
    返回EOF;
    }
    返回0;
    }
    int copy_行(文件*from、int line1、int col1、文件*to){
    int c,line=1,col=1;
    对于(;;){
    如果(行>=line1 | |(行==line1&&col>=col1))
    打破
    如果((c=getc(from))==EOF)
    打破
    if(putc(c,to)=EOF)
    返回EOF;
    col++;
    如果(c=='\n'){
    line++;
    col=1;
    }
    }
    返回0;
    }
    int writer(文件*写入){
    [501];/*str中逐行存储输入的字符*/
    char*p;
    printf(“\n用\“/end/\”终止输入\n\n在下面键入:\n\n”);
    而(fgets(in、501、stdin)){
    如果((p=strstrstr(in,“/end/”)!=NULL){
    /*若行中有“/end/”,则在/end/之前的所有字符都将写入文件,并且输入循环中断*/
    int o=p-in;
    if(fprintf(写入,'%s',o,in)<0)
    返回EOF;
    打破
    }否则{
    /*将行写入文件*/
    如果(fputs(输入,写入)<0)
    返回EOF;
    }
    }
    返回0;
    }
    int main(){
    /*要在给定索引下添加/插入文件的main*/
    const char*temp_filename=“temp.Ctt”;
    char fadd[501];/*文件名str*/
    printf(“\n文件名:”);
    如果(scanf(“%500[^\n]”,fadd)!=1)
    返回1;
    冲洗管线(标准DIN);
    文件*add=fopen(fadd,“r”);
    if(add==NULL){
    perror(“\n无法打开输入文件”);
    返回1;
    }
    int行,col;
    /*阅读索引:基于1的行号和列号*/
    printf(“\n索引:”);
    如果(扫描频率(“%d%*c%d”、&行和列)!=2){
    fprintf(stderr,“无效输入”);
    返回1;
    }
    冲洗管线(标准DIN);
    文件*tmp=fopen(临时文件名,“w”);
    if(tmp==NULL){
    perror(“\n无法创建临时文件”);
    fclose(add);
    返回1;
    }
    if(复制_行(添加、行、列、tmp)){
    perror(“\n复制文件开头时出错”);
    fclose(add);
    fclose(tmp);
    删除(临时文件名);
    返回1;
    }
    if(编写器(tmp)){
    perror(“\n写入用户输入时出错”);
    fclose(add);
    fclose(tmp);
    删除(临时文件名);
    返回1;
    }
    if(复制_文件(添加,tmp)){
    perror(“\n复制剩余文件内容时出错”);