有关C的学习笔记以及内存管理

来源:互联网 发布:管家公进销存软件 编辑:程序博客网 时间:2024/05/18 19:44
1,条件编译;
调试版和发布版
系统宏:_func_(调用的函数)_FILE_(调用的文件名),_LINE_(在几行被调用)
头文件里放:宏定义,函数的声明,类型的定义(typedef,struct)
动态分配内存和释放内存:malloc和free
int *p=NULL;
p=(int *)malloc(100*sizeof(int));
.....
free(p);
p=NULL;
4 内存使用规则 
       发生内存错误是件非常麻烦的事情。编译器不能自动发现这些错误,通常是在程序运行时才能捕捉到。而这些错误大多没有明显的症状,时隐时现,增加了改错的难度。有时用户怒气冲冲地把你找来,程序却没有发生任何问题,你一走,错误又发作了。 
常见的内存错误及其对策如下: 
u       内存分配未成功,却使用了它。 
编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。常用解决办法是,在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行检查。如果是用malloc或new来申请内存,应该用if(p==NULL) 或if(p!=NULL)进行防错处理。 


u       内存分配虽然成功,但是尚未初始化就引用它。 
犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。 
内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。 


u       内功存分配成并且已经初始化,但操作越过了内存的边界。 
例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组操作越界。 


u       忘记了释放内存,造成内存泄露。 
含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。 
动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误(new/delete同理)。 
u       释放了内存却继续使用它。 
有三种情况: 
(1)程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。 
(2)函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。 
(3)使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。 


l         【规则7-2-1】用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。 
l         【规则7-2-2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。 
l         【规则7-2-3】避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。 
l         【规则7-2-4】动态内存的申请与释放必须配对,防止内存泄漏。 
l         【规则7-2-5】用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。 


const 常变量  为只读
1,常变量必须初始化 如:const int p=10;
2,const int *p=&a或者int const *p=&a;形式不能通过*p来改变其内存中的值,但是可通过其他指向该内存地址中的值,同时也可改变p的值(即p所指向的存储空间)
例1:int a=10;
    int *k=&a;
   const int *p=&a;
       a=11;right
       *p=11;error
       *k=11;right
例2:int a=10,b=13;
const int *p=&a;
const int *p=&b;//right
3,int * const p;形式其实质为p(地址)是不可改变的,但是其所指向的内存时刻改变的,无论通过什么形式改变其所指向的空间的值
例1:int a=10,b=12;
     int * const p=&a;
     *p=b; right
     p=b; error    
3, const int a=10;此形式定义只读的变量a,用法同上1,不能通过a本身改变其值,只能通过其他方式改变其值;
例:const int a=10;
    a=12;error
    
    int *p=&a;
     *p=13;right  此时a的值变为13






作为函数参数的数组名:在传递时,对于大量数据(数组,结构体)尽量用数组名或指针传递,即传首地址,在传参数时,对于一个并不打算修改其值时,用const修饰(见参识意,避免错误的操作改变原有的值)
例:void strcpy(char *buffer, char const * string)


静态的局部变量和静态的全局变量
 一·静态的局部变量
静态的局部变量只有在编译时可以赋初值,以后每次调用时不再分配内存单元和初始化,只是保留上一次函数调用结束时的值,并且只适用于它所定义的函数或复合语句,生存期:整个程序
二·静态的全局变量
        静态的全局变量在整个程序运行期间都存在;但它与外部变量(即全局变量)不同,静态全局变量只能在所定义的文件中使用,具有局部可见性(注意它与静态局部变量的“局部可见”是不一样的),而外部变量可在其他文件中使用。




指针与数组
     指针与数组并不相等,数组的属性和指针大相径庭。当我们申明一个数组时,它同时也分配了一些内存空间,用于容纳数组
元素。但是,申明一个指针,它只分配了用于容纳指针本身的空间。
     系统为指针分配的存储空间,在申明时就一定固定了为4个字节,于它指向的类型无关。无论指向哪里只与他本身的访问方式有关,而与所指向的类型的访问方式无关。若两种访问方式不同,系统可能会报错至少会发出警告。
int *p;
int a[][10];
p=a;error(p的访问方式是:int 型,a 的访问方式是:指向一个含有10个整型元素的数组,a的值为“包含10个整型元素的第一个子元素”);


strncpy : char *strncpy(char *dst,char const *src, size_t len);
当strlen(src)>=len时,只会将src的部分数据拷贝到dst中,并且只是覆盖dst中len个长度的字符,其它不变
      * strlen:计算字符串的长度包含‘\0’,即NUL字符串结束标志
0 0
原创粉丝点击