精华内容
下载资源
问答
  • 内存分配方式三种:  1、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。  2、在栈上创建。在执行函数时,函数内局部变量的存储单元都...

    内存分配方式有三种:
      1、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
      2、在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
      3、从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。

    常见的错误      

    关于内存的一些知识已在内存分配中提及,现记录与分享常见的内存错误与对策。
    类型 1:内存未分配成功,却使用了它。
    方   法:在使用之前检查指针是否为NULL。
                 1)当指针p是函数的参数时,在函数入口处用语句assert(p!=NULL)进行断言检查。
                 2)当使用malloc或new来申请内存时,应该用if(p != NULL)进行防错检查。
    类型 2:引用了尚未初始化的指针
    原   因:内存的缺省初始值究竟是什么并没有统一的标准,在使用之前都进行初始化。
                  1)没有初始化的观念。
                  2)内存的缺省值是未定义,即垃圾值。
    类型 3:越界操作内存
    原   因:内存分配成功且初始了,但越界操作是不允许的。
    类型 4:忘记释放内存,造成内存泄漏。
    原   因:含有这种类型错误的函数,每被调用一次,就丢失一块内存。当内存充足时看不到这种错误带来的影响,当内存耗尽时系统提示:“内存耗尽”。因此,动态内存的申请与释放必须配对,程序中malloc与free的使用次数要相同。
    类型 5:释放了内存却继续使用它
    原   因:对应的情况有2种
                  1)返回了“栈内存的指针或引用”,因为堆栈中的变量在函数结束后自动销毁。
                  2)某块内存被free后,没有将指向该内存的指针设置为NULL,导致产生“野指针”。

    展开全文
  • C编译的程序对语法检查并不象其它高级语言那么严格,这就给编程人员留下“灵活的余地”,但还是由于这个灵活给程序的调试带来了许多不便,尤其对初学C语言的人来说,经常会出一些连自己都不知道错在哪里的错误。...
  • 内存分配方式三种: 1、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如全局变量,static变量。 2、在栈上创建。在执行函数时,函数内局部变量的存储单元都...

    一、内存分配方式

    内存分配方式有三种:

    1、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如全局变量,static变量。

    2、在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放,栈内存分配运算内置于处理器的指令集中,效率很高,凡是分配的内存容量有限。

    3、从堆上分配。也称动态内存分配。程序在运行的时候用malloc或者new申请任意多少的内存,程序员自己负责在何时用free或者delete释放内存。动态内存的生存期有程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收他。否则运行的程序会出现内存泄漏,频繁的分配和释放不同大小的堆空间将会产生堆内碎块。

    二、程序的内存空间

    一个由C/C++编译的程序占用的内存分为以下几个部分:

    1、栈区(stack)-- 由编译器自动分配释放,存放为运行函数而分配的局部变量,函数参数,返回数据,返回地址等。

    2、堆区(heap)-- 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。分配方式类似于链表。

    3、全局区(静态区)(static)-- 存放全局变量、静态数据、常量。程序结束后由系统释放。

    4、文字常量区--常量字符串就是放在这里的。程序结束后由系统释放。

    5、程序代码区 -- 存放函数体(类成员函数和全局函数)的二进制代码。

    三、常见的C语言内存错误及对策

    1、指针没有指向一块合法的内存

    定义了指针变量,但是没有为指针分配内存,即指针没有指向一块合法的内存,常见以下几种情况

    (1)结构体成员指针未初始化

    (2)没有为结构体指针分配足够的内存

    (3)函数的入口校验

    2、为地址分配的内存太小

    为指针分配了内存,但是内存大小不够,导致出现越界错误

    3、内存分配成功,但并未初始化

    定义一个变量时,第一件事就是初始化,在定义变量和数组时也可以初始化

    4、内存越界

    内存分配成功,且已经初始化,但是操作越过了内存的边界。这种错误经常是与由于操作数组或指针时出现“多1”或“少1”的情况

    5、内存泄漏

    (1)使用malloc函数,如:char *p = (char *)malloc(sizeof(指向的数据类型)*100);

    (2)使用malloc函数要检查内存是否申请成功,if(NULL != p)语句来验证;

    (3)用malloc函数申请0字节指针时 if(NULL != p)语句校验将不起作用

    (4)内存释放;使用malloc函数需要用free函数释放该内存块的首地址、使用malloc函数和free函数要对影响等否则发生段错误!

    (5)内存释放之后:使用函数free之后指针变量本身保存的地址并没有改变,需要从新把p的值变为NULL;

      p = NULL;

     如果没有将指针置为NULL,这个指针就变为“野指针”。所以,free之后,一定要给指针置为NULL

    6、内存已经释放,但是继续通过指针来使用

    这里一般由三种情况:

    (1)就是之前所说的,free(p)之后,继续通过p指针来访问内存,解决的办法就是给p置为NULL

    (2)函数返回栈内存。比如在函数内部定义一个数组,却用return 语句返回质量该数组的指针。解决的办法就是弄明白栈上变量的生命周期。

    (3)内存使用他太复杂,弄不清楚到底那块内存被释放,那块没有释放。解决的办法就是重新设计程序,改善对象之间的调用关系。

    最后,希望大家尽量使自己对每种错误发生及预防的手段烂熟于心,多练,多调试代码,多总结经验。


    展开全文
  • C编译的程序对语法检查并不象其它高级语言那么严格,这就给编程人员留下“灵活的余地”,但还是由于这个灵活给程序的调试带来了许多不便,尤其对初学C语言的人来说,经常会出一些连自己都不知道错在哪里的错误。...

    C编译的程序对语法检查并不象其它高级语言那么严格,这就给编程人员留下“灵活的余地”,但还是由于这个灵活给程序的调试带来了许多不便,尤其对初学C语言的人来说,经常会出一些连自己都不知道错在哪里的错误。看着有错的程序,不知该如何改起,通过对C的学习,积累了一些C编程时常犯的错误,以供参考。

    1、书写标识符时,忽略了大小写字母的区别。
    main()
    {
      int a=5;
      printf(“%d”,A);
    }
    编译程序把a和A认为是两个不同的变量名,而显示出错信息。C认为大写字母和小写字母是两个不同的字符。习惯上,符号常量名用大写,变量名用小写表示,以增加可读性。

    2、忽略了变量的类型,进行了不合法的运算。
    main()
    {
      float a,b;
      printf(“%d”,a%b);
    }
    %是求余运算,得到a/b的整余数。整型变量a和b可以进行求余运算,而实型变量则不允许进行“求余”运算。

    如果你想学习C/C++可以来这个群,首先是三三零,中间是八五九,最后是七六六,里面有大量的学习资料可以下载。

    3、将字符常量与字符串常量混淆。
    char c;
    c=”a”;
    在这里就混淆了字符常量与字符串常量,字符常量是由一对单引号括起来的单个字符,字符串常量是一对双引号括起来的字符序列。C规定以“\”作字符串结束标志,它是由系统自动加上的,所以字符串“a”实际上包含两个字符:‘a’和‘\0’,而把它赋给一个字符变量是不行的。

    4、忽略了“=”与“==”的区别。
    在许多高级语言中,用“=”符号作为关系运算符“等于”。如在BASIC程序中可以写
    if (a=3) then …
    但C语言中,“=”是赋值运算符,“==”是关系运算符。如:
    if (a==3) a=b;
    前者是进行比较,a是否和3相等,后者表示如果a和3相等,把b值赋给a。由于习惯问题,初学者往往会犯这样的错误。

    5、忘记加分号。
    分号是C语句中不可缺少的一部分,语句末尾必须有分号。
    a=1
    b=2
    编译时,编译程序在“a=1”后面没发现分号,就把下一行“b=2”也作为上一行语句的一部分,这就会出现语法错误。改错时,有时在被指出有错的一行中未发现错误,就需要看一下上一行是否漏掉了分号。
    {
      z=x+y;
      t=z/100;
      printf(“%f”,t);
    }
      对于复合语句来说,最后一个语句中最后的分号不能忽略不写(这是和PASCAL不同的)。

    6、多加分号。
      对于一个复合语句,如:
    {
      z=x+y;
      t=z/100;
      printf(“%f”,t);
    };
    复合语句的花括号后不应再加分号,否则将会画蛇添足。又如:
    if (a%3==0);
    I++;
    本是如果3整除a,则I加1。但由于if (a%3==0)后多加了分号,则if语句到此结束,程序将执行I++语句,不论3是否整除a,I都将自动加1。再如:
    for (I=0;I<5;I++);
    {
           scanf(“%d”,&x);
           printf(“%d”,x);
    }
    本意是先后输入5个数,每输入一个数后再将它输出。由于for()后多加了一个分号,使循环体变为空语句,此时只能输入一个数并输出它。

    7、输入变量时忘记加地址运算符“&”。
    int a,b;
    scanf(“%d%d”,a,b);
    这是不合法的。Scanf函数的作用是:按照a、b在内存的地址将a、b的值存进去。“&a”指a在内存中的地址。

    8、输入数据的方式与要求不符。
    ①scanf(“%d%d”,&a,&b);
    输入时,不能用逗号作两个数据间的分隔符,如下面输入不合法:
        3,4
    输入数据时,在两个数据之间以一个或多个空格间隔,也可用回车键,跳格键tab。
    ②scanf(“%d,%d”,&a,&b);
    C规定:如果在“格式控制”字符串中除了格式说明以外还有其它字符,则在输入数据时应输入与这些字符相同的字符。下面输入是合法的:
        3,4
    此时不用逗号而用空格或其它字符是不对的。
        3 4 3:4
    又如:
        scanf(“a=%d,b=%d”,&a,&b);
    输入应如以下形式:
        a=3,b=4

    9、输入字符的格式与要求不一致。
    在用“%c”格式输入字符时,“空格字符”和“转义字符”都作为有效字符输入。
        scanf(“%c%c%c”,&c1,&c2,&c3);
    如输入a b c

    字符“a”送给c1,字符“ ”送给c2,字符“b”送给c3,因为%c只要求读入一个字符,后面不需要用空格作为两个字符的间隔。

    10、输入输出的数据类型与所用格式说明符不一致。
    例如,a已定义为整型,b定义为实型
        a=3;b=4.5;
        printf(“%f%d\n”,a,b);
    编译时不给出出错信息,但运行结果将与原意不符。这种错误尤其需要注意。

    11、输入数据时,企图规定精度。
        scanf(“%7.2f”,&a);
    这样做是不合法的,输入数据时不能规定精度。
      
    12.switch语句中漏写break语句。
    例如:根据考试成绩的等级打印出百分制数段。
    switch(grade)
    {
      case ‘A’:printf(“85~100\n”);
      case ‘B’:printf(“70~84\n”);
      case ‘C’:printf(“60~69\n”);
      case ‘D’:printf(“<60\n”);
      default:printf(“error\n”);

    由于漏写了break语句,case只起标号的作用,而不起判断作用。因此,当grade值为A时,printf函数在执行完第一个语句后接着执行第二、三、四、五个printf函数语句。正确写法应在每个分支后再加上“break;”。例如
    case ‘A’:printf(“85~100\n”);break;

    13、忽视了while和do-while语句在细节上的区别。
    (1)main()
    {
    int a=0,I;
    scanf(“%d”,&I);
    while(I<=10)
    {a=a+I;
    I++;
    }
    printf(“%d”,a);
    }
    (2)
    main()
    {
    int a=0,I;
    scanf(“%d”,&I);
    do
    {a=a+I;
    I++;
    }while(I<=10);
    printf(“%d”,a);
    }
    可以看到,当输入I的值小于或等于10时,二者得到的结果相同。而当I>10时,二者结果就不同了。因为while循环是先判断后执行,而do- while循环是先执行后判断。对于大于10的数while循环一次也不执行循环体,而do-while语句则要执行一次循环体。

    14、定义数组时误用变量。
    int n;
    scanf(“%d”,&n);
    int a[n];
    数组名后用方括号括起来的是常量表达式,可以包括常量和符号常量。即C不允许对数组的大小作动态定义。

    15、在定义数组时,将定义的“元素个数”误认为是可使的最大下标值。
    main()
    {
        static int a[10]={1,2,3,4,5,6,7,8,9,10};
        printf(“%d”,a[10]);
    }
    C语言规定:定义时用a[10],表示a数组有10个元素。其下标值由0开始,所以数组元素a[10]是不存在的。
     
    16、在不应加地址运算符&的位置加了地址运算符。
        scanf(“%s”,&str);
    C语言编译系统对数组名的处理是:数组名代表该数组的起始地址,且scanf函数中的输入项是字符数组名,不必要再加地址符&。应改为:
        scanf(“%s”,str);

    17、同时定义了形参和函数中的局部变量。
    int max(x,y)
    int x,y,z;
    {
      z=x>y?x:y;
      return(z);
    }
      形参应该在函数体外定义,而局部变量应该在函数体内定义。应改为:
    int max(x,y)
    int x,y;
    {
      int z;
      z=x>y?x:y;
      return(z);
    }

    展开全文
  • 分配方式三种:  1、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。  2、在栈上创建。在执行函数时,函数内局部变量的存储单元都...

    分配方式有三种:

      1、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

      2、在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

      3、从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。

     

    常见的错误  :  

    关于内存的一些知识已在内存分配中提及,现记录与分享常见的内存错误与对策。

    类型 1:内存未分配成功,却使用了它。

    方   法:在使用之前检查指针是否为NULL。

                1)当指针p是函数的参数时,在函数入口处用语句assert(p!=NULL)进行断言检查。

                2)当使用malloc或new来申请内存时,应该用if(p != NULL)进行防错检查。

    类型 2:引用了尚未初始化的指针

    原   因:内存的缺省初始值究竟是什么并没有统一的标准,在使用之前都进行初始化。

                 1)没有初始化的观念。

                 2)内存的缺省值是未定义,即垃圾值。

    类型 3:越界操作内存

    原   因:内存分配成功且初始了,但越界操作是不允许的。

    类型 4:忘记释放内存,造成内存泄漏。

    原   因:含有这种类型错误的函数,每被调用一次,就丢失一块内存。当内存充足时看不到这种错误带来的影响,当内存耗尽时系统提示:“内存耗尽”。因此,动态内存的申请与释放必须配对,程序中malloc与free的使用次数要相同。

    类型 5:释放了内存却继续使用它

    原   因:对应的情况有2种

                 1)返回了“栈内存的指针或引用”,因为堆栈中的变量在函数结束后自动销毁。

                 2)某块内存被free后,没有将指向该内存的指针设置为NULL,导致产生“野指针”。

    内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

    内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

    memory leak会最终会导致out of memory

    内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。 

       
    内存泄漏是指你向系统申请分配内存进行使用(new)
    ,可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出!比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出. 

       以发生的方式来分类,内存泄漏可以分为4类: 

    1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。 
    2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。 
    3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。 
    4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。 

    从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到 

    内存泄漏

    堆内存释放,是从堆顶开始。那么如果堆中间的一块区域,大部分内存都释放了,堆顶还有一些会怎么样呢?

    我们来看个例子:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    int main()
    {
    char *p[11];
    int i;
    for(i=0;i<10;i++)
    {
    p[i]=(char *)malloc(1024*2);
    strcpy(p[i],"123");
    }
    p[10]=(char *)malloc(1024*2);
    strcpy(p[10],"123");
    for(i=0;i<10;i++)
    {
    free(p[i]);
    }
    pid_t pid=getpid();
    printf("pid:%d\n",pid);
    pause();
    return 0;
    }
    这里我申请了 11 个2k 的内存,然后将前10 个2k 内存释放掉,只剩下堆顶一个2k。

    按我们正常的逻辑,进程应该只是占用了一个物理页面,可实际上呢?
    我们查看 memmap 的结果,可以看到
    1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

    这个例子是,堆顶指针没变,堆顶下面的内存被释放了。

    让我们来想想 libc 会怎么办?
    第一个想法,也是最合理的方法,堆顶下面哪个页面空闲了,就将那个物理页面释放掉,返还给系统。
    Linux 内核只能通过缩小线性内存区的方式来释放物理内存。
    方法一,通过使用系统调用 brk,来改变堆顶地址释放内存。
    优点:
    算法简单,系统调用少,效率高。
    缺点:
    堆顶下方的物理页面即使空闲也无法及时释放。
    方法二:,通过将对应堆的线性区拆分,将中间的物理页面释放掉。
    优点:
    堆顶下方的内存能够得到即使的释放。
    缺点:
    算法复杂,涉及到线性区的拆分与合并,有可能会导致进程堆段形成多个不连续的小块内存空间,对进程的性能影响较大。
    综合以上因素,Linux 内核选则了通过调整堆顶来扩展和释放内存空间。
    它也决定了,只要堆顶部还有内存在使用,堆顶下方不管释放了多少内存都不会被释放,这也就是我们经常所说的内存空洞。
    除了通过 brk(功 能: 改变数据段空间分配)扩展堆顶地址外,我们还提到了另外一种内存分配方式mmap。当libc 在处理大块内存分配时,其会调用mmap 来分配一块地址空间;当释放时,直接调用unmmap 释放掉该段内存空间,因此对于这种大块内存分配的申请和释放,就不会存在内存空洞的问题。
    你可以通过使用mmap 分配内存的阀值,来减少内存空洞的概率。代价是,可能会使用更多的系统调用,降低进程的性能。
    要想消除内存空洞的影响,就要求我们在申请和释放内存时,要严格依照就近原则,最先释放堆顶地址的内存。可控制内存的申请和释放的顺序难度十分的大;另外由于内存碎片的影响,每次申请得到的内存地址都带有一定的随机性,后面申请的内存,并不一定就意味着在堆顶;这简直是Mission impossible。
    做为一个程序员,我很受挫折,我无能为力,我调用 free 都释放内存,可它并不一定会返还到系统中,我无法完全控制我程序的行为,谁又能保证堆顶没有那么一块正在使用的内存呢?

    这也给很多程序员以藉口,在测试中我们程序内存使用量增长,要求他们去检查时,他们往往会说,“内存我都释放了,这是内存空洞造成的,我也无能为力。”。老板也无话可说,内存空洞简直成了我们的噩梦。
    内存空洞和内存泄漏造成的内存增长是有区别的:
    内存泄漏是申请了的内存没有释放,如果你在做多次同样的操作,进程所使用的内存应该保持同样的一个速度进行增长。
    内存空洞是申请并释放了的内存由于不处于堆顶无法返还给系统,但是这些内存还是能留给进程自身使用,所以如果你做多次同样的操作,进程所使用的内存应该停留在一个水平线上,不怎么增长,或者增长不多。
    程序员可以根据这个现象来判断,你的进程中存在的是内存泄漏还是内存空洞。
    在实际情况中,内存空洞的现象并很多,通过我的观察在堆中,更多的是内存的碎片而不是内存空洞。因此程序员对于内存空洞只要了解这个概念,在申请分配内存时,本着就近原则就可以了,需要的时候才分配内存,不需要了立刻释放。不必去严格的追求申请和释放的顺序,也做不到。
    后面我将会介绍一种方法,通过它你可以观察当前进程的内存分布情况,你可以清楚的知道进程内存碎片和内存空洞的情况。
    虽然我给大家吃了很多宽心丸,但很多人还是不放心,担心他自己成为内存空洞的受害者。
    难道我们对于内存空洞真的是无能为力吗?
    实际上堆的内存管理机制有很多种,你也可以按照自己的要求来自己编写内存管理机制。前
    面我们介绍的是libc 中自带的内存管理机制Doug LeaMalloc。
    Doug Lea Malloc:Doug Lea Malloc 实际上是完整的一组分配程序,其中包括 Doug Lea 的原始分配程序,GNU libc 分配程序和 ptmalloc。 Doug Lea 的分配程序加入了索引,这使得搜索速度更快,并且可以将多个没有被使用的块组合为一个大的块。它还支持缓存,以便更快地再次使用最近释放的内存。
    这里我简单介绍另外一种内存管理机制 BSD Malloc。
    BSD Malloc:BSD Malloc 是随 4.2BSD 发行的实现,包含在 FreeBSD 之中,这个分配程序可以从预先确定大小的对象构成的池中分配对象。它有一些用于对象大小的 size 类,这些对象的大小为 2 的若干次幂减去某一常数。所以,如果您请求给定大小的一个对象,它就简单地分配一个与之匹配的 size 类。这样就提供了一个快速的实现,但是可能会浪费内存。
    据说这种算法可以消除内存空洞,因为它把原来的一个内存段,编程了多个内存段,从而减小了内存空洞的影响,而性能下降不多。
    有人尝试着将其移植到嵌入式 Linux 设备上,据说每个进程的内存的堆可以减少1/3,但是否有负作用不清楚,有待检验。

     


    展开全文
  • 编译和执行结果错误 <code class="language-bash">gcc -g -c demo.c demo.c:13:19: warning: incompatible integer to pointer conversion initializing 'byte *' (aka 'unsigned char *') with ...
  • 首先看一下内存分配方式有哪些,一般来说有以下三种:  (1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量等等。  (2)在栈上创建。...
  • Linux C语言学习笔记

    2020-12-18 11:02:11
    一、C语言的优点有哪些? 简单、快速、高性能、兼容性好、功能强大、易于学习 二、C语言最适合做什么? 三、Linux环境下学习C语言 1.开发环境准备 step1:安装Linux虚拟机 step2:安装文本编辑器 2.编写C语言 step1:...
  • C语言编程要点

    2017-09-18 00:10:37
    12.13. 适用于整数和浮点数的数学函数分别有哪些? 184 12.14. 什么是多字节字符(multibyte characters)? 185 12.15. 怎样操作由多字节字符组成的字符串? 186 第13章 时间和日期 186 13.1. 怎样把日期存储到单个数字...
  • 文章目录前言一、C语言的优点有哪些?简单、快速、高性能、兼容性好、功能强大、易于学习二、C语言最适合做什么?三、Linux环境下学习C语言1.开发环境准备step1:安装Linux虚拟机step2:安装文本编辑器2.编写C语言...
  • 2:写过C语言代码的都知道,如果程序中有错误,编译器会报错,那么错误主要有哪些?又是怎么被计算机发现的? 3:C语言的预处理操作都有哪些?宏定义和函数的主要区别在哪? 1、我们写的.c程序如何变为可执行程序...
  • C语言一些简单的简答

    2018-01-25 16:32:51
    首先看一下内存分配方式有哪些,一般来说有以下三种: (1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量等等。 (2)在栈上创建。...
  • 如果文章错别字,或者内容有错误,或其他的建议和意见,请您联系我们指正,非常感谢!!! 我只是用来方便学习 && 复习!!! 我只是一个学习者, 内功有限, 大家看到谨慎参考!!! C语言make和makefile文件 ...
  • c语言编写单片机技巧

    2009-04-19 12:15:17
    虽然C语言是最普遍的一种高级语言,但不同的MCU厂家其C语言编译系统是有所差别的,特别是在一些特殊功能模块的操作上。如果对这些特性不了解,那调试起来就的烦了,到头来可能还不如用汇编来的快。 5. 在教学中...
  • 你必须知道的495个C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    *2.5 在C语言中是否模拟继承等面向对象程序设计特性的好方法? 2.6 为什么声明externf(structx*p);给我报了一个晦涩难懂的警告信息? 2.7 我遇到这样声明结构的代码:structname{intnamelen;charnamestr[1];}...
  • 难道在C语言中一个结构不能包含指向自己的指针吗? o 2.7 怎样建立和理解非常复杂的声明?例如定义一个包含 N 个指向返回指向字符的指针的函数的指针的数组? o 2.8 函数只定义了一次, 调用了一次, 但编译器提示...
  • 对于非计算机专业而言,程序设计的学习助于理解计算机的能力所在,理解哪些是计算机擅长解决的问题,怎样的方式方法是计算机擅长的手段,从而能更好地利用计算机来解决本专业领域内的问题。 C语言是古老而长青的...
  • 2.5 在C语言中是否模拟继承等面向对象程序设计特性的好方法? 2.6 为什么声明extern f(struct x *p); 给我报了一个晦涩难懂的警告信息? 2.7 我遇到这样声明结构的代码:struct name {int namelen; char namestr[1...
  • 在添加Option Explicit语句后,VB将自动检查程序中是否未定义的变量,发现后将显示错误信息。  如果要自动插入Option Explicit语句,用户只要在“工具”菜单中选取“选项”命令,然后单击“选项”对话框中的...
  • 《你必须知道的495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    *2.5 在C语言中是否模拟继承等面向对象程序设计特性的好方法? 22 2.6 为什么声明extern f(struct x *p); 给我报了一个晦涩难懂的警告信息? 23 2.7 我遇到这样声明结构的代码:struct name {int namelen; ...
  • *2.5 在C语言中是否模拟继承等面向对象程序设计特性的好方法? 22 2.6 为什么声明extern f(struct x *p); 给我报了一个晦涩难懂的警告信息? 23 2.7 我遇到这样声明结构的代码:struct name {int namelen; ...
  • IvorHorton还著关于C、C++和Java的多部入门级好书,如《C语言入门经典(第4版)》和《C++入门经典(第3版)》。 译者  杨浩,知名译者,大学讲师,从事机械和计算机方面的教学和研究多年,发表论文数篇,参编和翻译的...
  • *2.5 在C语言中是否模拟继承等面向对象程序设计特性的好方法? 2.6 为什么声明externf(structx*p);给我报了一个晦涩难懂的警告信息?  2.7 我遇到这样声明结构的代码:structname{intnamelen;charnamestr[1];}...
  •  *2.5 在C语言中是否模拟继承等面向对象程序设计特性的好方法? 2.6 为什么声明externf(structx*p);给我报了一个晦涩难懂的警告信息? 2.7 我遇到这样声明结构的代码:structname{intnamelen;charnamestr[1];...

空空如也

空空如也

1 2 3 4
收藏数 80
精华内容 32
关键字:

c语言编译错误有哪些

c语言 订阅