1.malloc与free成对使用:malloc函数在内存空间申请空间,但不初始化,函数申明为void* malloc(size_t size) 一般需要强制类型转换。开辟的空间的首地址用指针变量存放,以便找到。空间的释放free(指针变量),释放空间后把空间里面的数据清空,但是指针变量里面还是存放的这块空间的首地址。后续若再次使用到该指针变量将会很危险,所以最好还是把该指针变量置空。
#include#include #include #include int main() { int* p=(int*)malloc(10*sizeof(int)); // 开辟不成功,打印不成功原因 if(p==NULL) { printf("%sn",strerror(errno)); } else { // 开辟成功,使用空间 int i=0; for(i=0;i<10;i++) { *(p+i)=i;//依次为该空间赋值。 } for(i=0;i<10;i++) { printf("%d",*(p+i)); } } free(p); p=NULL; return 0; }
(引自鹏哥c语言)
2.calloc函数:函数申明为void* calloc(size_t num,size_t size),也是向内存空间申请一个空间,但会初始化这个空间全部为0,函数参数与malloc有点不一样,如int* p=(int*)calloc(10,sizeof(int))。申请完后也需要释放空间。
#include#include #include #include int main() { int* p=(int*)calloc(10,sizeof(int)); if(p==NULL) { printf("%sn",strerror(errno)); } else { int i=0; for(i=0;i<10;i++) { printf("%d ",*(p+i)); } } free(p); p=NULL; }
3.realloc函数:调整动态开辟空间的大小,函数申明:void*realloc(void* memblock,size_t size)。
#include#include #include #include int main() { int* p=(int*)malloc(20); // 开辟不成功,打印不成功原因 if(p==NULL) { printf("%sn",strerror(errno)); } else { // 开辟成功,使用空间 int i=0; for(i=0;i<10;i++) { *(p+i)=i;//依次为该空间赋值。 } int* ptr=(int*)realloc(p,40); if(ptr!=NULL) { p=ptr; int j=0; for(j=0;j<10;j++) { *(p+j)=j; printf("%d ",*(p+j)); } } free(p); p=NULL; } }
4.动态内存分配常见错误:
1).对空指针进行解引用操作,本质在于未对动态函数开辟的结果进行成功与否的判断,万一没有开辟成功,动态函数就返回空指针,对空指针解引用为非法。
2).对动态开辟的内存的越界访问。
3).对非动态开辟的空间使用free释放空间。
4).使用free释放动态开辟的内存一部分。指向动态开辟的内存的指针变量在free空间之前,不能有任何改变值的操作,++pp++等,可以*(p+i)这种形式。
5).对同一块动态开辟的空间进行多次释放。
6).对动态开辟的空间忘记释放,导致内存泄漏。
5.几个经典的笔试题:
(一)
#include#include #include void GetMemory(char* p) { p=(char*)malloc(100); } void test(void) { char* str=NULL; GetMemory(str); strcpy(str,"hello world"); printf(str); return 0; } //test运行结果:程序崩溃。
问题分析:str里面是空指针,p里面倒是存放动态开辟空间的首地址,但是p出了GetMemory函数没有返回,所以被丢弃了,因此strcpy函数中str里面还是空指针,没有存放hello word的空间。程序在此就崩溃了。 另外会出现内存泄漏的问题,没有释放动态开辟的空间。
正确修改1(传值修改):
#include#include #include char* GetMemory(char* p) { p=(char*)malloc(100); return p; } void test(void) { char* str=NULL; str=GetMemory(str); strcpy(str,"hello world"); printf(str); free(str); str=NULL; return 0; }
正确修改2.(传址修改:传址能够通过形参函数内部可以直接操作函数外部的变量。):
#include#include #include void GetMemory(char** p) { *p=(char*)malloc(100); } void test(void) { char* str=NULL; GetMemory(&str); strcpy(str,"hello world"); printf(str); free(str); str=NULL; return 0; }
(二) 返回栈空间地址的问题
#include#include char *GetMemory(void) { char p[] = "hello world"; return p; } void Test(void) { char *str = NULL; str = GetMemory(); printf(str); } //随机值,非法访问内存。
错误解释:返回栈空间地址,局部数组空间已还给操作空间了。即使返回了数组空间地址,里面的数据已变成随机值。
正确修改:用static修饰延长数组的生理周期。
另外还需注意一个点,函数内部动态内存分配是在堆区开辟的,出了函数该空间不考虑丢失,但在栈区定义的变量空间会丢失。比如:
int* test()
{
int* ptr=(int*)malloc(40);
return ptr;
}
int main()
{
int* p=test();
return 0;
}
(三) 忘记释放空间,有内存泄漏之风险
#include#include void GetMemory(char **p, int num) { *p = (char *)malloc(num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); } //test运行结果是,hello
虽然能打印,但没有释放空间,有内存泄露之风险。
(四) 释放后的空间再次使用,非法访问
#include#include void Test(void) { char *str = (char *) malloc(100); strcpy(str, "hello"); free(str); if(str != NULL) { strcpy(str, "world"); printf(str); } } //test运行结果是 world
正确修改free(str)后面添加str=NULL。逻辑才对。
(引自鹏哥C语言)
内核空间是留给操作系统的。数据段又叫静态区。
6.柔性数组:C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。其中结构体中柔性数组是不占大小的。柔性数组大小的创建是通过malloc函数创建,并可以通过realloc函数来改变其大小。



