2015-12-13 203 views
-1

我是C文件管理新手。我的老师希望作为一项功课来创建一个从源文件复制到目标文件的功能。我创建了,但它始终给我带来错误:分段错误。我打开时出现分段错误

void source_to_destination(FILE *source , FILE *destination) 
{ 
    char name_source[10], name_destination[10],line[100]; 
    memset(line,0,sizeof(line)); 
    memset(name_source,0,sizeof(name_source)); 
    memset(name_destination,0,sizeof(name_destination)); 
    read_name_file(name_source); 
    read_name_file(name_destination); 

    source = fopen(name_source,"r"); 
    destination = fopen(name_destination,"w"); 

    while(fgets(line,sizeof(line),source) != NULL) 
    { 
     fputs(line,destination); 
    } 

} 
+2

** **务必检查能遇到一个错误函数的结果!解引用_null pointer_是未定义的行为。还要注意,你必须“成功”打开文件** iff **。 – Olaf

+0

我在main()中关闭了它们。我认为问题出现在'destination = fopen(name_destination,“w”);' –

+2

'source'和'destination'指针是你的函数的参数,但是你不使用通过这些参数传递的参数值。这不是天生的错误,但是这一点以及你不关闭文件的事实表明你认为调用者会以某种方式通过这些参数从函数接收流指针。它不会,如果调用者认为已经完成,那肯定会产生段错误。 –

回答

-1

以下代码

  1. 编译干净
  2. 执行愿望操作(复制文件)
  3. 执行适当的错误检查
  4. 从命令行 得到的文件名您将需要修改此以通过您现有的功能获取文件名
  5. 总是本身包括关闭打开的文件
  6. 后清理演示了如何通过FILE*变量--into--功能

    子函数原型,等等都需要进行修改 如果你想打开子功能 中的文件然后有main()关闭它们。

这里是执行所希望的操作

#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 


#define MAX_LINE_LENGTH (256) 

// prototypes 
void source_to_destination(FILE *source , FILE *destination); 


int main(int argc, char * argv[]) 
{ 
    if(3 != argc) 
    { // not correct number of command line parameters 
     fprintf(stderr, "USAGE: %s <sourceFili> <destinationFile>\n", argv[0]); 
     exit(EXIT_FAILURE); 
    } 

    // implied else, correct number of arguments 

    FILE *fp_in = NULL; 
    if(NULL == (fp_in = fopen(argv[1], "r"))) 
    { // then fopen failed 
     fprintf(stderr, "fopen for input file: %s failed due to %s\n", argv[1], strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 

    // implied else, fopen input file successful 

    FILE *fp_out = NULL; 
    if(NULL == (fp_out = fopen(argv[2], "w"))) 
    { // then fopen failed 
     fprintf(stderr, "fopen for output file: %s failed due to %s\n", argv[2], strerror(errno)); 
     fclose(fp_in); // cleanup 
     exit(EXIT_FAILURE); 
    } 

    // implied else, fopen output file successful 

    source_to_destination(fp_in, fp_out); 
    fclose(fp_in); 
    fclose(fp_out); 
    return 0; 
} // end function: main 


void source_to_destination(FILE *source , FILE *destination) 
{ 
    char line[ MAX_LINE_LENGTH ]; 

    while(fgets(line,sizeof(line),source)) 
    { 
     if(EOF == fputs(line,destination)) 
     { // then fputs failed 
      fprintf(stderr, "fputs to output file failed due to %s\n", strerror(errno)); 
      fclose(source); 
      fclose(destination); 
      exit(EXIT_FAILURE); 
     } 
    } 
} // end function: source_to_destination 
+0

非常感谢! –

+0

无法在错误消息中包含文件名是一个相当严重的遗漏。只要做'perror(argv [1])'和'perror(argv [2])''。此外,将所有错误打印到标准错误,包括报告错误用法的消息。 –

+0

谢谢@WilliamPursell,我会相应地修改我的答案 – user3629249

1

当从一个文件复制到另一个数据,读,写二进制优选的建议的方法。使用面向行的输入函数(如fgetsgetline)进行读取将无法正确读取文件中的所有字符的原因很多。文本输出函数遭受类似的缺点(例如,试图写入具有备用的含义ASCII可打印范围之外的字符或字符)使用fread

阅读与从二进制模式文件中写入和fwrite并不比使用fgets更难和fputs。但是,使用freadfwrite可以避免在文本模式下尝试一般文件复制时固有的缺陷,从而保证数据的正确和准确的副本。

如果您知道只有源文件中包含文本,则在文本模式下进行复制没有任何问题。这意味着你将不得不编写另一个函数来处理非文本文件。 (并且通常您不会看到基于文件内容的不同复制例程)。用二进制读取和写入消除了所有这些考虑因素。

以下是一个filecopy函数的简短示例,它将文件中的所有字节读入缓冲区,然后将缓冲区的内容写入目标文件。 (缓冲读/写通常效率更高,您可以通过调整MAXS轻松调整缓冲区大小)。该函数返回成功复制的字节数,否则返回-1。看一下它,并让我知道如果您有任何疑问:

#include <stdio.h> 
#include <stdlib.h> 

#define MAXS 256 

int filecopy (char *source, char *dest); 

int main (int argc, char **argv) { 

    if (argc < 3) { /* validate 2 arguments given */ 
     fprintf (stderr, "usage: %s file1 file2\n", argv[0]); 
     return 1; 
    } 

    int filesize = 0; 

    if ((filesize = filecopy (argv[1], argv[2])) == -1) { 
     fprintf (stderr, "error: filecopy failed.\n"); 
     return 1; 
    } 

    printf ("\n copied '%s' -> '%s' ('%d' bytes)\n\n", 
      argv[1], argv[2], filesize); 

    return 0; 
} 

int filecopy (char *source, char *dest) 
{ 
    char *buf = NULL; /* buffer used to read MAXS bytes from file */ 
    size_t nbytes = 0; /* number of bytes read from file */ 
    size_t idx = 0;  /* file index (length)   */ 
    FILE *fp = fopen (source, "r"); /* stream pointer  */ 

    if (!fp) { /* open source for reading */ 
     fprintf (stderr, "error: file open failed '%s'.\n", source); 
     return -1; 
    } 

    /* allocate MAXS size read buf initially */ 
    if (!(buf = calloc (MAXS, sizeof *buf))) { 
     fprintf (stderr, "error: virtual memory exhausted.\n"); 
     return -1; 
    } 

    /* while data read MAXS *buf from file - realloc for next read */ 
    while ((nbytes = fread (buf+idx, sizeof *buf, MAXS, fp))) 
    { 
     idx += nbytes;    /* update total bytes read */ 
     if (nbytes < MAXS) break; /* end-of-file reached */ 

     /* full read - realloc for next */ 
     void *tmp; 
     if (!(tmp = realloc (buf, (idx + nbytes) * sizeof *buf))) { 
      fprintf (stderr, "error: virtual memory exhausted.\n"); 
      exit (EXIT_FAILURE); 
     } 
     buf = tmp; 
    } 
    fclose (fp); /* close input stream */ 

    if (!(fp = fopen (dest, "w+b"))) { /* open output stream */ 
     fprintf (stderr, "error: file open failed '%s'.\n", dest); 
     exit (EXIT_FAILURE); 
    } 
    fwrite (buf, sizeof *buf, idx, fp); 
    fclose (fp); /* close output stream */ 

    free (buf); 
    return (int)idx; 
} 

编译

gcc -Wall -Wextra -O3 -o bin/filecopy_simple filecopy_simple.c 

输入文件(二进制)

-rw-r--r-- 1 david david 66672 Nov 19 13:17 acarsout2.bin 

使用/输出

$ ./bin/filecopy_simple dat/acarsout2.bin dat/acarsout3.bin 

copied 'dat/acarsout2.bin' -> 'dat/acarsout3.bin' ('66672' bytes) 

验证

$ ls -al acarsout[23]* 
-rw-r--r-- 1 david david 66672 Nov 19 13:17 acarsout2.bin 
-rw-r--r-- 1 david david 66672 Dec 13 14:51 acarsout3.bin 

$ diff dat/acarsout2.bin dat/acarsout3.bin 
$ 
+0

很好,但对于只懂文本脚本的许多'程序员'来说本质上是无用的功能:)他们无法应付任何事情但是文本行;他们的大脑爆炸了。没有工作的答案被接受,而不是:( –

+0

我同意。问题不是哪个答案被接受,重要的一点是提供提醒,并非所有的文件都是文本,并提供了一个合理的例子来说明如何以一般方式处理文件复制。当你思考这个问题时,教育只不过是缓慢揭示事实 - 我们所能做的就是帮助把封面进一步拉回来:“) –