一:程序存储区划分
1、栈区:(最低地址内存空间)一般的基本数据类型,包括数组类型、结构体类型、int\short\char····等类型,甚至是const int a=6,也是栈区的,并不是常量,也说明了const的标志并不是常量的定义,只是变量a不可以被更改的意思。
特点:可读可写,并且是先进后出,后进先出,由系统分配和回收(使用权)
如:const int a=10;//验证栈区的地址空间,对比以下,。
printf("%p\n",&a);
输出的地址是:OX7fff5fbff7dc
2、堆区:一般的动态内存分配,手动申请分配,手动释放,堆区的空间是占得最多的。
如:
char *p=malloc(10);
printf("%p\n",p);
输出的地址是:OX100206850
3、静态区:有static修饰的,并且是只能初始化一次,只有在程序退出才释放内存
如:int function(){
int a=0;
a++;
}
这个函数调用两次,结果a=1,但如果是static int a=0;则调用两次后a=2,因为只有在第一次调用时,a初始化为0,下一次调用时就不再初始化了。
如:
static int b;
printf("%p\n",b);
输出结果:OX100001028
4、常量区:常量不可以改变的,是可读,不能修改,如字符串数组:
str[]="iphone",printf("%p",str),和char *p="iphone",printf("%p",p);这两个地址是不一样的,上面打印的是字符数组型的栈区,而后面指针指向的则是常量区的地址
char *q="lanou";
printf("%p\n",q);
输出结果:ox100000f94
5、代码区:如 void function(){``````}
(低地址内存空间)代码区:函数的语句,所有的语句编译后会生成CPU指令存储在代码区
printf("%p\n",main);//直接打印一个函数名的地址
输出结果为:ox100000e40
二:动态申请内存(实际上在堆区执行的)
1、malloc()格式:void*malloc(unsigned int size);//void*,则返回的可以是任何类型的指针,因为是void万能指针类型,返回分配完的内存的首地址,里面的size是需要分配的字节数,可以是表达式
如:char*str=malloc(8);//申请8个字节的内存
strcpy(str,"iphone");//使用刚申请的内存空间
printf("%s\n",str);
int *arr=malloc(4);//这里可以存放一个整型的数据
short *sarr=malloc(4);//这里可以存放两个短整型的数据
Student *p=malloc(sizeof(student));//申请一个存放结构体的空间
Student*p=malloc(sizeof(Student)*5);//申请5个存放结构体的内存空间
栈内存空间的释放:(回收使用权,内存的东西并没有删除)
格式:void free(void *p)//这个就是为了避免多个指针指向同一个地址,造成冲突,因此申请了一个内存空间,必须要释放。
如:
char *p=malloc(8)//申请
free(p);//释放
p=NULL;//必须要置空,不然会变成乱指放的指针
课上练习:输出一个字符串的数字(也就是数字重新生成一个字符串)
char str[]="jsdh232kjjl324";
int number=sizeof(str);//计算数组的个数,但这个不是最好的,因为这是计算str的长度,不是数字的长度,以下才对
int count=0;
for (int i=0; i<number; i++) {//注意:(容易写错)
if(str[i]>='0'&&str[i]<='9') {
count++;
}
}
printf("%d\n",count);
char *q=malloc(count+1);//count +1是为了存储结束符号‘\0’
int j=0;
for (int i=0; i<number; i++) {
if(str[i]>='0'&&str[i]<='9') {
*(q+j)=str[i];//注意:(容易写错)把满足条件的数组赋给申请了存放数字的空间的指针
j++;//注意:(容易写错成q++)不是指针自增一,会导致指向其他空间
}
}
*(q+j)='\0';//注意:(容易落写)必须要加上这个结束符号
printf("%d\n",j);//打印存放数字的指针所存放的数字个数
printf("%s\n",q);//打印已经提取的数字所组成的字符串
free(q);//注意:(容易落写)释放内存空间
q=NULL;//注意:(容易落写)用完把指针放空,防止p还会指向于原来那块内存地址,如果其他在使用,则会出错!
//练习2(重点理解)
//输⼊入3个学员的姓名,动态分配内存保存学员姓名,并在最后输出
char *stu[3]={0};
char temp[255]={0};//定义一个用来暂时存放姓名字符串的数组
for(inti0;i<3;i++)
{
printf("please input 第%d个 words\n",i+1);
scanf("%s",temp);
unsigned long length=strlen(temp);
stu[i]=malloc(length+1);//加1是为了要存放结束符号‘\0’
strcpy(stu[i],temp);//字符串赋值只能用strcpy
//释放内存以及输出过程
for (int i=0; i<3; i++) {
printf("strs[%d]=%s\n",i,strs[i]);
free(strs[i]);
strs[i]=NULL;
}
}
//其他内存分配函数
//1\calloc:
// void *calloc(unsigned n,unsigned size);//可以申请n个size大小的空间,并且可以自动把该内存空间上的所有字节清零,但不会自动释放内存,还是需要free()来释放内存。
// //2、realloc
// void *realloc(void *p,unsigned newSize);//按给定的地址和大小来重新分配,也就是使用指针p重新指向重新分配的地址
三:内存操作函数
//1、初始化内存memset(),相当于malloc()+memset()=calloc()
char *p=malloc(10);
p=memset(p, 0, 10);//意思是:返回
//
//2、内存拷贝
void *memcpy(void *dest,const void*source,size_t n);
//如:
void *q;
const void *k;
void *p=memcpy(q,k,10);
// //3、比较内存mencmp(),返回值是int型,比出来时内存上内容的差值
课上练习3:定义两个整型指针,分别⽤用malloc、calloc对其分配空间保存3个元素,malloc分配的空间⽤用memset清零,随机对数组进⾏行赋值随机范围1-3,赋值后⽤用memcmp⽐比较两个数组。如果相同打印Good!否则打印Failed...
int *p=malloc(sizeof(int)*3);//定义整型指针p并且申请空间sizeof(int)这个类型的,三个则乘上3,实际上可以理解是要申请12个字节,因为3个int的元素
int *q=calloc(3,sizeof(int));//跟上面一样,只是把个数和每个的字节大小分开写
p=memset(p,0,12);
for(int a=0;i<3;i++){
*(p+i)=arc4random()%(3-1+1)+1;
*(q+i)=arc4random()%(3-1+1)+1;
printf("p[%d]=%d\n",i,*(p+i));
printf("q[%d]=%d\n",i,*(q+i));
}
int result=memcmp(p,q,12);//比较大小,如果相等,则result=0,返回值是0是,返回“Good"
// q=memcpy(q, p, 12);//赋值函数
int a=0;
// 错误做法:a=memcmp(p,q,3);
a=memcmp(p,q,12);//比较两个指针数组的大小,没大没小就是相等即为0时,表示相等,比较两块内存上内容上的差值
printf("%d\n",a);
if (a==0) {//如果相同(比较结果为0)打印Good!否则打印Failed...
printf("Good!\n");
}else{
printf("Failed!\n");
}
free(p);
p=NULL;
free(q);
q=NULL;