2015-05-10 58 views
0
#include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 

    int main() 

    { 

     char file_name[100]; 
     char insert[100]; 

     printf("Enter the file name:"); 
     scanf("%s", file_name); 
     FILE *f = fopen((strcat(file_name, ".txt")), "a"); 
     printf("Insert:"); 
     scanf ("%[^\n]%*s", insert); 
     fprintf(f, "%s", insert); 

    } 

上述代码应该写入/插入数据到文件,但是,程序在打印'Insert:'后立即终止。我似乎无法在这里找到问题。无法找到我的'写入文件'程序中的错误

+1

为什么提示输入文件名?你能想象如果'grep'这样工作吗?使用命令行参数:它极大地简化了你的程序! –

+0

您还错过了最后一个fclose()。这可能是好的,因为它可能在程序终止时自动关闭,但在正常使用中,您可能会写入少量的输出,直到您刷新或关闭,因为它将被缓冲。 – Rup

+1

编译所有警告和调试信息(例如'gcc -Wall -Wextra -g')。学习如何**使用调试器**('gdb')。阅读您正在使用的每个功能的文档,例如[scanf的](http://en.cppreference.com/w/c/io/fscanf)。总是使用'scanf'的返回项目数并检查失败('scanf','fopen',...) –

回答

3

scanf

scanf("%s", file_name); 

不会消耗你按输入文件名之后的换行符。它保持在标准输入流中(stdin)。该scanf

scanf ("%[^\n]%*s", insert); 

扫描的一切,直到一个换行符,然后扫描并丢弃的字符串。 %[^\n]将失败,如果下一个字符是\n。所以,scanf,在你的情况下失败并返回下一个字符是\ninsert保持未初始化并包含垃圾。

fprintf(f, "%s", insert); 

将垃圾写入f


如何解决问题?两种方法固定问题:

  1. 使用getchar();刚过第一scanf摆脱第一scanf遗留下来的换行符。
  2. 使用

    scanf (" %[^\n]%*s", insert); 
    

    ,而不是

    scanf ("%[^\n]%*s", insert); 
    

    之前%[^\n]扫描的空间,并丢弃所有whitespace characters(如\n,空间等),如果有的话,直到第一个非空白字符所看到在下面的C11标准的报价中:

    7.21.6.2 fscanf函数

    [...]

  3. 的空白字符(一个或多个)构成的指令是通过读取输入到第一执行非空白字符(保持未读),或直到不能再读取字符。该指令永远不会失败

我倾向于第二种方案,因为它需要的照顾任何的空白字符数。


这两种解决方案都能正常工作,但是您还有其他问题。在您提供第二个 scanf的数据后,您的程序不会停止扫描!解决这个问题很简单。请从第二个 scanf中删除 %*s

想知道为什么?引述C11标准,

7.21.6.2 fscanf函数

[...]

  • 转换标识符和它们的含义如下:
    [...]
    s匹配一系列非空白字符。
    [...]
  • 所以,%s将跳过前导空白字符和停止扫描,当它遇到一个空白字符或,如果长度字段存在,直到指定的长度或,直到出现空格字符,以先发生者为准。粗体部分解释它。


    为了提高安全性,请限制 scanfinsertfile_name读取的字符数,以便您可以避开 buffer overflows。另外,请检查 scanffopen的返回值,看看它们是否成功。在您的情况下, scanf都会在成功时返回1。如果不是1,则发生错误。 fopen,失败时返回 NULL。如果不是 NULL,则 fopen成功。


    最终方案:

    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    
    int main()   
    {   
        char file_name[100]; 
        char insert[100]; 
    
        printf("Enter the file name:"); 
        if(scanf("%94s", file_name) != 1) //Scans a maximum of 94 chars,+1 for \0 at the end,+4 for ".txt" 
        { 
         printf("scanf failed\n"); 
         exit(-1); //Exit the program with a negative return value 
        } 
    
        strcat(file_name, ".txt"); //Improves readability,do one thing in one line 
        FILE *f = fopen(filename, "a"); 
    
        if(f == NULL) //if fopen failed to open the filename, 
        { 
         printf("fopen failed\n"); 
         exit(-1); 
        } 
    
        printf("Insert:"); 
        if(scanf (" %99[^\n]", insert) != 1) // Note the space before %[^\n],99 scans a maximum of 99 chars,+1 for the \0 at the end 
        { 
         printf("scanf failed\n"); 
         fclose(f); //Free resources before exiting 
         exit(-1); 
        } 
        fprintf(f, "%s", insert); 
        fclose(f); //Close the file after use 
    } 
    


    如果你要放弃第二 scanf遗留的换行符,使用

    scanf (" %99[^\n]%*c", insert) 
    

    ,而不是

    scanf (" %99[^\n]", insert) 
    

    虽然这个程序并没有什么不同。


    如果你想知道为什么我从陈述章引号“ 7.21.6.2 fscanf函数”那是因为, fscanf是完全一样 scanf时,它的第一个参数是 stdin。从C11标准再次引用,

    7.21.6.4的scanf函数

    [...]

  • scanf功能相当于fscanf与参数之前插入到scanf参数stdin
  • +0

    downvote背后的原因是什么? – jimo

    +0

    不是我的失望。不知道为什么你被低估了。 PS:我已经达到了我的每日投票限额 –

    +1

    @diplodocus,好像比分现在已经平衡了! :)(2 upvotes,2 downvotes) –

    0

    问题出在您的第一个scanf。回车没有被处理,这意味着下一个scanf在被调用后立即处理它,因为它仍然在缓冲区中。

    也许尝试,scanf("%s\n", filename);

    +0

    我这样做了,但现在它给了我一个新行来输入输入(可以说我输入' x'),在移动到下一行时,它会打印'insert:'并再次请求输入(可以说我输入'y'),最后文件用'x'编辑? – jimo

    相关问题