Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么这个程序分配的内存比需要的多?_C_Malloc - Fatal编程技术网

C 为什么这个程序分配的内存比需要的多?

C 为什么这个程序分配的内存比需要的多?,c,malloc,C,Malloc,我正在用C编写一个程序,需要从stdin读取。我不想让它分配超出需要的内存,所以我以块的形式读取输入,malloc 下面是代码(allocd变量仅用于跟踪分配的内存量): 问题是,我的程序似乎分配的内存字节比文件中的字符多得多,如您所见: $ ./code <file.txt ALLOC'D: 1680 $。/code您正在为(尝试)读取的每一行分配新的内存块,而不管该行实际有多长。我认为,fgets是错误的工具,你想要的是: #包括 #包括 #包括 #定义尺寸20 int main(i

我正在用C编写一个程序,需要从stdin读取。我不想让它分配超出需要的内存,所以我以块的形式读取输入,
malloc

下面是代码(
allocd
变量仅用于跟踪分配的内存量):

问题是,我的程序似乎分配的内存字节比文件中的字符多得多,如您所见:

$ ./code <file.txt
ALLOC'D: 1680

$。/code您正在为(尝试)读取的每一行分配新的内存块,而不管该行实际有多长。我认为,
fgets
是错误的工具,你想要的是:

#包括
#包括
#包括
#定义尺寸20
int main(int argc,char*argv[])
{
char*str=malloc(1);
*str='\0';
焦比[SIZ];
int allocd=0;
INTP;
//注意:fread()返回读取记录的大小和数量,而不是字符*
而((p=fread(buf,1,sizeof(buf,stdin)))
{
str=realloc(str,allocd+p+1);
//连接缓冲区
memcpy(str+allocd,buf,p);
allocd+=p;
}
str[allocd+1]=0;
printf(“分配:%i”,分配);
自由基(str);
}

您正在为(尝试)读取的每一行分配一个新的内存块,而不管该行实际有多长。我认为,
fgets
是错误的工具,你想要的是:

#包括
#包括
#包括
#定义尺寸20
int main(int argc,char*argv[])
{
char*str=malloc(1);
*str='\0';
焦比[SIZ];
int allocd=0;
INTP;
//注意:fread()返回读取记录的大小和数量,而不是字符*
而((p=fread(buf,1,sizeof(buf,stdin)))
{
str=realloc(str,allocd+p+1);
//连接缓冲区
memcpy(str+allocd,buf,p);
allocd+=p;
}
str[allocd+1]=0;
printf(“分配:%i”,分配);
自由基(str);
}
我正在用C编写一个程序,需要从stdin读取。我不希望它分配的内存超过所需,所以我以块的形式读取输入,每次读取一个新的块时都会占用更多的内存

好吧,对于程序员来说,您的节约意图是个好主意,但您的节约是错误的,因为您没有考虑到许多隐藏的东西,而是支持有效实现
malloc
所必需的

  • 首先,malloc需要将额外的内存与您请求的块相关联,以便维护堆,并且不会被分配任务搞得一团糟。这意味着,假设它与您请求的每一组内存关联的结构是一个常量,假设它是8字节大,
    malloc(1)
    将需要使用
    8bytes+1
    (这是您请求的最后一个)来管理您的任务。这意味着,如果您进行了一百万次这样的分配,您将在您的责任中分配一百万字节,但您将在
    malloc
    开销中浪费800万字节。具有活动计数的malloc数
  • 第二个问题是,当您使用malloc时,您正在将用于记住malloc给您的位置的指针的大小添加到总开销中。这在最后一个地方没有考虑,因为您只能使用一个alloc来存储一个数组,在该数组中存储一百万个相邻的结构,并且只使用一个指针引用它们。但是这通常是没有用的,如果您是那些在对象之间进行引用的指针,那么您将需要在记帐中包含所有这些指针。如果我们将此开销添加到上面分配的100万字节中,您将额外增加400-800万字节的开销。这意味着您已经分配了一百万字节,但是为了维护这些字节,您需要额外的800万字节开销,并且在malloc中隐藏了800万字节的开销
  • 可以避免代码中的初始
    malloc(1)
    。如果您阅读,您将看到
    realloc
    不需要非空指针来操作,如果您将
    null
    指针传递给它,它的行为将类似于初始的
    malloc()
    调用,但需要的实际存储量是多少
代码中的方法是正确的,您一直在使用单个活动malloc,您已经决定按照
SIZ
(一个大的
SIZ
有助于将
malloc
调用的开销降至最低,但平均而言,您将导致未使用内存的开销---分配的内存,但没有填充字符,大约是
SIZ
值的一半,可能更多)由于行长应遵循毒药分布,因此
SIZ
的最佳值应为平均行长(如果使用该平均值的两倍,则更好,以获得更好的性能)

一旦更正,您的代码将是:

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

#define SIZ 60 /* assumed an average line length of 30 chars */

int main(int argc, char *argv[])
{
    char *str = NULL; /* <<< use null, don't allocate something you don't need */
    char buf[SIZ];
    /* you don't need to know how many times you repeated the loop */
    int allocd = 0; /* allocated capacity */
    int strsz = 0;  /* filled size */

    while (fgets(buf, sizeof(buf), stdin)) /* the p pointer is not necessary */
    {
        /* grow str */
        int read_chars = strlen(buf);           /* (1 & 2) see below */
        printf("read: [%s]\n", buf);
        int pos_to_cp  = strsz;                 /* (3) we need this at the end
*/
        strsz         += read_chars;
        if (strsz >= allocd) {                  /* need to grow */
            printf("growing from %d to %d\n", allocd, allocd + (int)sizeof buf);
            allocd    += sizeof buf;            /* new size */
            str        = realloc(str, allocd);  /* reallocate to allocd */
        }
        strcpy(str + pos_to_cp, buf);           /* (3) see below */
                                                /* (4) see below */
    }

    printf("ALLOC'D: %i\n", allocd);
    printf("string: %s\n", str);

    free(str);
}
#包括
#包括
#包括
#定义SIZ 60/*假定平均线长度为30个字符*/
int main(int argc,char*argv[])
{
char*str=NULL;/*
我正在用C编写一个程序,需要从stdin中读取数据。我不希望它分配的内存超过需要的数量,所以我正在分块读取输入,每次读取一个新的块时都会占用更多的内存

好吧,对于程序员来说,您的节约意图是个好主意,但您的节约是错误的,因为您没有考虑到许多隐藏的东西,而是支持有效实现
malloc
所必需的

  • 首先,malloc需要将额外的内存与您请求的块相关联,以维护堆并且不会被分配任务搞砸。这意味着,假设它与您请求的每一组内存相关联的结构是一个常量,假设它是8字节大,
    malloc
    
    $ ./code <file.txt
    ALLOC'D: 1680
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define SIZ 60 /* assumed an average line length of 30 chars */
    
    int main(int argc, char *argv[])
    {
        char *str = NULL; /* <<< use null, don't allocate something you don't need */
        char buf[SIZ];
        /* you don't need to know how many times you repeated the loop */
        int allocd = 0; /* allocated capacity */
        int strsz = 0;  /* filled size */
    
        while (fgets(buf, sizeof(buf), stdin)) /* the p pointer is not necessary */
        {
            /* grow str */
            int read_chars = strlen(buf);           /* (1 & 2) see below */
            printf("read: [%s]\n", buf);
            int pos_to_cp  = strsz;                 /* (3) we need this at the end
    */
            strsz         += read_chars;
            if (strsz >= allocd) {                  /* need to grow */
                printf("growing from %d to %d\n", allocd, allocd + (int)sizeof buf);
                allocd    += sizeof buf;            /* new size */
                str        = realloc(str, allocd);  /* reallocate to allocd */
            }
            strcpy(str + pos_to_cp, buf);           /* (3) see below */
                                                    /* (4) see below */
        }
    
        printf("ALLOC'D: %i\n", allocd);
        printf("string: %s\n", str);
    
        free(str);
    }