C程序内存分配图
栈区:局部变量
堆区:动态分配的数据
静态存储区/全局区:全局变量,静态数据
代码区:代码,指令
内存分配说明
内存动态分配的相关函数
堆区:
#inlcude<stdlib.h>
Malloc(size);//分配长度为size个字节的连续空间
Calloc(n,size);//分配size个长度为n个字节的连续空间,总共有size*n个字节
Free§;//销毁指针p所指向的堆空间,其他函数和主函数不能再使用
Realloc(p,size);//重新分配指针p所指向的内存空间大小,指针所指向的地址不变,仅仅是空间扩大或缩小
Void*:
Void*:仅仅是一个纯地址,而不指向任何的对象:
Void* p;//无类型指针变量
如果是void类型,不能够用p来取得值(报错)
void*强制类型转换举例:
代码
#include<stdio.h>
//动态内存分配(堆区)--void*无类型指针int main()
{int a=102;int *pa=&a;//类型转换1char b='c';char *pb=&b;void *p;char *pc;char *pd;p=(void*)pb;//强制类型转换,char*pb-->void*,并把pb地址赋值给ppc=(char*)p;//强制类型转换,void*p-->char*pd=(char*)pa;//记住:没有*p,p只是一个地址,不指向任何对象printf("类型转换1:\n");printf("pb=%c address=%p self-address=%p\n",*pb,pb,&pb);printf("p:address=%p self-address=%p\n",p,&p);printf("pc=%c address=%p self-address=%p\n",*pc,pc,&pc);printf("pd=%c address=%p self-address=%p\n",*pd,pd,&pd);getchar();return 0;
}
说明:
在C99的编译器中,其他类型转void*类型,是自动类型转换:
int a=2;
void *p=&a;
低版本的则需要强制类型转换:
void *p=(void *)&a;
应用案例
代码
#include<stdio.h>
#include<stdlib.h>
//动态内存分配(堆区)--malloc()函数
//输出所有成绩中小于60的成绩
#define SIZE 5
void check(int *p,int len);//函数原型,函数声明
int *check1(int *p,int len);int main()
{int *p=(int*)malloc(5*sizeof(int));//开辟5*4大小的空间,相当于一个长度为8的数组int i=0;//*p=-842150451是一个垃圾值,堆区的第一个字节,4个字节才存储一个元素,因此不能使用*pprintf("address=%p self-address=%p\n",*p,p,&p);printf("输入每一个成绩:\n");while(i<5){//p+i=arr[0]+i的地址//通过数组的地址来为数组每一个元素赋值scanf("%d",p+i);i++;}printf("方式1:\n");//输出成绩1check(p,5);//输出成绩2int*k=check1(p,5);printf("\n方式2:\n");for(i=0;i<5;i++){if(*k!=0){printf("%d",*k);k++;}}getchar();//entergetchar();return 0;
}
void check(int *p,int len)
{int i;for(i=0;i<len;i++){if(p[i]<60){printf("%d ",p[i]);}}}int *check1(int *p,int len)
{static int i,j=0,arr[SIZE];//局部数据,使用静态staticfor(i=0;i<len;i++){if(p[i]<60){arr[j++]=p[i];}}return arr;
}
图示
练习–逆序输出字符串
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//动态内存分配(堆区)--函数练习
//malloc()分配内存空间
//realloc()重新分配内存空间
//free()释放内存空间char *reverse(char *s,int len);//函数声明
//逆序打印字符串
const int size=100;
int main()
{char *p=(char*)malloc(size*sizeof(char));//为p动态分配内存空间char s[size];gets(s);int len=strlen(s);char *p=(char*)realloc(p,len*sizeof(char));//重新为p分配更合适的内存空间//p=k[0]的地址(char*)p=reverse(s,len);int i;for(i=0;i<len;i++){printf("%c",*p+i);//或p++}free(p);//释放p所指向的内存空间getchar();//entergetchar();return 0;
}
//逆序字符串
char *reverse(char *s,int len)
{int i=len-1,j=0;static char k[size];while(i>=0){k[j++]=s[i];i--;}return k;
}
基本原则
1)每开辟一个内存就会占用系统开销,所以需要避免分配大量小内存块
2)内存泄漏:没有释放内存空间,这一个内存空间就会一直被占用
3)开辟了动态内存后一定要记得释放:谁分配,谁释放
指针使用一览
指针数组:
由n个指向整型元素的指针而组成,里面存放指针
Int *ptr[3];
数组指针:
指向一个有n个元素的数组的指针,里面存放的是整型变量(int类型长度为n的数组的首地址),存的是一个数组地址,而不是单个元素
int(*p)[n]
int (*p)(int ,int):指向函数的指针