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):指向函數的指針