【问题标题】:Concatenating the contents of multiple files passed from command line连接从命令行传递的多个文件的内容
【发布时间】:2021-05-15 18:05:09
【问题描述】:

我正在尝试连接在执行代码时传递的所有argv[] 参数的内容。这里的计数与argc 相同。 **文件包含argv

char *merge_everything(int count, char **files) {
        size_t size = 0;
        char *buf = NULL;
        buf = malloc((size + 1) * sizeof(*buf)); /* size + 1 byte for the \0 */
        if (buf == NULL) {
            printf("MALLOC ERROR\n");
            exit(1);
        }
        char *temp = buf;
    
        for (int i = 0; i < count - 1; i++) {
            FILE *f = fopen(files[i], "rb");
    
            fseek(f, 0, SEEK_END);
            long bytes = ftell(f);
            fseek(f, 0, SEEK_SET);
    
            fread(temp, (size_t) bytes, 1, f);
            temp += bytes;
            fclose(f);
        }
        *temp = 0;
        free(buf); //If I don't free buf here then memory leak? If I do temp has null?
        return temp; //temp has all the concatenated stuff
    }

我处于两难境地,最后释放bufreturn 语句之前。 请帮我纠正方法。 我热衷于使用缓冲区(通过malloc)而不是将其写入新文件。因此,这种方法。

【问题讨论】:

  • 如果我不在这里释放 buf 则内存泄漏。首先,您应该返回buf 而不是temp,因为前者是字符串的开头,而后者位于字符串的中间。其次,如果这样做了,那么它就不是内存泄漏,因为调用者负责释放。
  • 您是否意识到您分配的内存量与任何一个文件的大小都没有关系,更不用说所有文件了?
  • size_t size = 0; malloc((size + 1) * sizeof(*buf)); 你认为分配了多少内存?
  • 没有分配任何内容。我意识到了这一点,而不是给它一个像 512 之类的硬编码宏。我希望它适应文件 1 的大小,然后适应文件 2 的大小等等。
  • 很公平。但这不会神奇地发生。执行此操作的代码在哪里?一旦分配完成,它就不会自动改变大小。

标签: arrays c malloc concatenation file-handling


【解决方案1】:

您需要随时增加缓冲区。例如:

/* Read all named files into a buffer. */                                          
                                                                                   
#include <stdio.h>                                                                 
#include <stddef.h>                                                                
#include <ctype.h>                                                                 
#include <stdlib.h>                                                                
                                                                                   
struct buffer {                                                                    
        char *start;                                                               
        char *end;                                                                 
        size_t cap;                                                                
};                                                                                 
                                                                                   
void push(int c, struct buffer *);                                                 
int pop(struct buffer *a);                                                         
void * xrealloc(void *buf, size_t num, size_t siz, void *endvp);                   
FILE * xfopen(const char *path, const char *mode);                                 
                                                                                   
int                                                                                
main(int argc, char **argv)                                                        
{                                                                                  
        struct buffer a = {0};                                                     
        int c;                                                                     
        for( int i = 1; i < argc; i++ ){                                           
                FILE *ifp = xfopen(argv[i], "r");                                  
                while( (c = fgetc(ifp)) != EOF ) {                                 
                        push(c, &a);                                               
                }                                                                  
        }                                                                          
        while( (c = pop(&a)) != EOF ) {                                            
                putchar(c);                                                        
        }                                                                          
        return 0;                                                                  
} 

                                                                                   
int                                                                                
pop(struct buffer *a)                                                              
{                                                                                  
        return (a->start < a->end) ? *a->start++ : EOF;                            
}                                                                                  
                                                                                   
void                                                                               
push(int c, struct buffer *b)                                                      
{                                                                                  
        if( b->start == NULL || b->end >= b->start + b->cap ) {                    
                b->start = xrealloc(b->start, b->cap += BUFSIZ, 1, &b->end);       
        }                                                                          
        *b->end++ = c;                                                             
}                                                                                  
                                                                                   
void *                                                                             
xrealloc(void *buf, size_t num, size_t siz, void *endvp)                           
{                                                                                  
        char **endp = endvp;                                                       
        char *b = buf;                                                             
        ptrdiff_t offset = b && endp && *endp ? *endp - b : 0;                     
        b = realloc(b, num * siz);                                                 
        if( b == NULL ){                                                           
                perror("realloc");                                                 
                exit(EXIT_FAILURE);                                                
        }                                                                          
        if( endp != NULL ){                                                        
                *endp = b + offset;                                                
        }                                                                          
        return b;                                                                  
}                                                                                  
                                                                                   
FILE *                                                                             
xfopen(const char *path, const char *mode)                                         
{                                                                                  
        FILE *fp = fopen(path, mode);                                              
        if( fp == NULL ){                                                          
                perror(path);                                                      
                exit(EXIT_FAILURE);                                                
        }                                                                          
        return fp;                                                                 
}  

【讨论】:

    【解决方案2】:
    1. 您分配了 1 个字节并进行了大量读取。这是未定义的行为。
    2. 您需要为每个文件增加分配的内存大小。
    3. 您应该检查文件 I/O 错误。
    4. 我不知道为什么count-1,但也许你有你的理由。
    char *merge_everything(int count, char **files) {
            size_t size = 0;
            long bytes;
            char *buf = NULL, *temp;
    
            for (int i = 0; i < count - 1; i++) {
                FILE *f = fopen(files[i], "rb");
        
                fseek(f, 0, SEEK_END);
                bytes = ftell(f);
                fseek(f, 0, SEEK_SET);
    
                
                temp = realloc(buf, size + bytes);
                if(!temp)
                {
                    free(buf);
                    break;
                }
                buf = temp;
        
                fread(buf + size, (size_t) bytes, 1, f);
                size += bytes;
                fclose(f);
            }
            return buf; //temp has all the concatenated stuff
        }
    

    【讨论】:

    • 这有帮助!关于你的声明“调用者应该释放内存”,我猜这可以通过释放收集 buf 的 char * 来完成,对吧?
    • 另外,在你的 fread() 中,我怎样才能摆脱 \n 字符?这很棘手,因为我们正在跟踪读取的字节数。
    猜你喜欢
    • 1970-01-01
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    相关资源
    最近更新 更多