今天小編給大家?guī)韈語言學(xué)習(xí)之路--由淺入深(快速掌握c基礎(chǔ))。溫馨提示:亮點在最后嫌褪!
1.第一個C程序:HelloWorld.c
首先我這里是使用這個軟件編寫的:下載地址:文章末尾
安裝過程一直next就好了
安裝后在你的代碼目錄創(chuàng)建一個HelloWorld.c喉童,代碼目錄可以隨意,然后雙擊打開HelloWorld.c就可以默認進入我們下載的c開發(fā)軟件中,如圖:
其中圖中標(biāo)記為我們java中常用的編譯和運行
下面就可以開始我們c語言的第一個helloWorld,通常說從helloWorld開始可以快速成為大神:
#include // java import xxx.xx.pack 引用函數(shù)的聲明 #include
main() // 程序的入口函數(shù)
{
//代碼文件目錄是本級目錄則會執(zhí)行成功露戒,否則會找不到該類
printf("Hello world ! "); // 控制臺打印一個hello world
//如果不是本級目錄必須先指定目錄地址描验,才能執(zhí)行成功
system("java -classpath c:\ HelloWorld");
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
代碼中我們首先可以看到
1白嘁、 這個東西拿java來說就是我們通常的包名
2、main函數(shù)是主入口膘流,和java一樣
3絮缅、c語言中必須使用system("pause");使命令行暫停,方便觀察程序的執(zhí)行結(jié)果呼股,否則結(jié)果會在你眼中一閃而過
2.C語言的基本類型與JAVA基本類型對比:
上一節(jié)中我們開始我們的第一個helloWorld耕魄,下面我們講學(xué)習(xí)c中的數(shù)據(jù)類型:
// java數(shù)據(jù)類型 和長度int 4個字節(jié) double 8個字節(jié) float 4個字節(jié) long 8個字節(jié)
// short 2個字節(jié) boolean 1個字節(jié) char 2個字節(jié) byte 1個字節(jié)
// char, int, float, double, signed, unsigned, long, short and void
// c語言中 數(shù)據(jù)類型比java少一些 在c語言中沒有 boolean類型的數(shù)據(jù) int 1 代表真 0 代表假
// c 語言中沒有String類型的數(shù)據(jù) java中表示一個字符串 String , c語言中表示字符串 通過char類型的數(shù)組來表示字符串
// c 語言沒有byte類型 所有用char的類型表示byte類型
#include #include
// sizeof(); c語言的一個函數(shù) 可以把 某種數(shù)據(jù)類型的長度獲取出來 int
main()
{ // %d 類似sql語句的? 占位符
printf("char的長度為%d ", sizeof(char));//1
printf("int的長度為%d ", sizeof(int));//4
printf("float的長度為%d ", sizeof(float));//4
printf("double的長度為%d ", sizeof(double));//8
printf("long的長度為%d ", sizeof(long));//在不同的情況下可能會有不同的大小,但是long的長度一定比int大 4
printf("short的長度為%d ", sizeof(short));// 2
//signed, unsigned, 數(shù)據(jù)類型的修飾符
// signed int ; 代表的是有符號的int的數(shù)據(jù)
// unsigned int ; 無符號的int數(shù)據(jù)
printf("signed int的長度為%d ", sizeof( signed int));//4
printf("unsigned int的長度為%d ", sizeof( unsigned int));//4
// 符號的修飾符 只能修飾 整數(shù)類型的數(shù)據(jù) long int
// 不能修飾 浮點型的數(shù)據(jù) float double
// printf("signed float的長度為%d ", sizeof( signed float));
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
從上面我們可以知道彭谁,c語言有以下幾種數(shù)據(jù)類型:
char, int, float, double, long, short
使用char表示java的byte類型數(shù)據(jù)
使用char數(shù)據(jù)去表示java中String類型的數(shù)據(jù)
c的兩種修飾符 signed, unsigned,
3.C語言中的輸入輸出函數(shù):
上一節(jié)我們了解c語言的基本數(shù)據(jù)類型吸奴,下面我們看看c的輸入輸出函數(shù):
/*%d - int
%ld – long int
%c - char
%f - float
%lf – double
%x – 十六進制輸出 int 或者long int 或者short int
%o - 八進制輸出
%s – 字符串
Int len;
Scanf("%d",&len);*/#include // java import xxx.xx.pack 引用函數(shù)的聲明 #include
main() // 程序的入口函數(shù)
{ int i = 3;
float f = 3.1415;
double d = 6.2815;
char c = 'A'; //通過單引號定義字符
short s = 2;
//輸出的時候占位符和數(shù)據(jù)類型必須一一對應(yīng),否則得不到正確的結(jié)果
printf("int i=%d ",i);
printf("float f=%f ",f);
printf("char c=%c ",c);
printf("double d=%lf ",d);
printf("short s=%d ",s);
/*char arr[20] ; //定義一個長度為20的數(shù)組
//java中是System.in
scanf("%s",arr); // 從鍵盤接受一個字符串,放在c數(shù)組里面
//java中是System.out
printf("s =%s ",arr);
*/
int j ;
scanf("%d", &j);//&代表的是取地址
//從控制臺得到j(luò)地址所代表的址輸出
printf("j=%d ",j);
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
從代碼中我們知道c語言的 輸入:scanf();函數(shù) 根據(jù)地址去輸入&j 輸出:printf();函數(shù)
4.指針入門:
上一節(jié)我們學(xué)到了輸入輸出,下面我們將學(xué)習(xí)一個新名詞指針 首先java中是沒有指針這個名詞的奄抽,
指針是什么? 指針就是一個地址 地址代表的就是一塊內(nèi)存空間 指針變量是什么蔼两? 用來存放指針
從上面我們就可以知道java中的內(nèi)存控件就是c語言中的指針,下面我們看下代碼:
#include #include
main()
{
int i =5;// 定義一個int 類型的變量i 值 =5
//%#X表示16進制的地址占位符
printf("i的地址 %#X ",&i);
//獲取i的地址逞度,&i就是一個指針
// &i;
//定義一個指針變量额划,數(shù)據(jù)類型*
int* p ; // 指針變量 定義一個int* 類型的變量p
//其他兩種表示方式:int *p, int * p;
p = &i; // 就是把i的指針賦給指針變量p ,現(xiàn)在指針變量p里面存放的內(nèi)容(數(shù)據(jù)) 就是i的地址
printf("p里面的內(nèi)容為(i的地址) %#X ",p);
//*號 操作符
// *號的幾種含義
//1 . *號放在某種數(shù)據(jù)類型的后面,代表就是這種數(shù)據(jù)類型的指針 int* float*
//2 . *號 代表一個乘法符號 3*5 = 15;
//3 . *號放在一個指針變量的前面 -> 代表取這個指針變量所存放的地址里面對應(yīng)的數(shù)據(jù)
printf("i=%d ",i);
printf("*p的值%d ",*p);
// 改變p的值 會不會影響i的值?
//p = NULL;
// printf("i=%d ",i);//5
// 改變i的值 會不會影響p的值?
// i = 100;
// printf("p里面的內(nèi)容為(i的地址) %#X ",p);
// 通過上述實驗 p和 i 是兩個不同的變量 ,改變i的值 不會影響 p的值,同理,更改p的值 也不會影響i的值
// 更改*p的值 會不會影響i的值
// *p = 88;
// printf("i=%d ",i); //88
// 更改i的值 會不會影響 *p的值呢?
// i = 99;
// printf("*p的值%d ",*p); //99
//*p 和i 其實代表的是同一個變量,代表是同一塊內(nèi)存空間
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
從代碼中我們可以知道:
· 1.指針就是地址,而c語言中我們在變量前面加上&符號就可以到地址也就是指針如:int i=9;那么i的指針表示方式是&i
· 2.指針變量就是用來存放指針的一個變量档泽,如:數(shù)據(jù)類型* 變量名俊戳;如:int * p 這樣就是一個指針變量,將我們上面的&i=p這樣我們就將i的指針放在了指針變量p中
· 3.得到指針變量中的值使用符號*,例如我們將上面指針變量p的指針i的值取出來表示就是:*p
· 4.*p 和i 其實代表的是同一個變量,代表是同一塊內(nèi)存空間
·
5.指針介紹:
上一節(jié)我們已經(jīng)知道了指針和指針變量的用法,下面我們將通過一個小程序進一步說明指針
#include #include
main()
{
// 所有的變量都會分配一塊內(nèi)存空間
// 指針就是用來表示一塊內(nèi)存空間的地址的
// 地址可以用過 &這個符號獲取到某個變量的在內(nèi)存中的地址
// 這個地址如果想把他存放起來 就需要有一個變量 去存放這個地址
// 存放內(nèi)存地址的變量 就是指針變量
// 指針和指針變量
// 指針是用來表示一塊內(nèi)存地址的,
// 指針變量是用來存放一個內(nèi)存地址的 .
//
printf("ready go! 剩余時間60秒 ");
int time = 60;
printf("time變量對應(yīng)的內(nèi)存地址為%#X ", &time);
for(;time>0;time--){
printf("剩余時間%d ",time);
sleep(4000);
}
printf("游戲結(jié)束");
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
從代碼中我們編寫了一個for循環(huán)馆匿,打印time指針值抑胎,可以在命令行程序已經(jīng)在開始走了
從圖中可能大概你們可以看到我使用一個外掛軟件找到了time指針值,外掛地址
怎么使用外掛軟件:
1.首先點擊圖中的箭頭圖標(biāo)渐北,
2. 彈出Process List在里面找到我們的程序阿逃,然后點擊,
3.左邊Address欄就會出現(xiàn)我們程序中的time地址
從圖中我們居然看到我們的程序運行到22的時候怎么又從59開始了赃蛛,正常情況下我們是21啊恃锉,這是怎么回事呢??哈哈,這其實就是用到了我們上圖 中的外掛呕臂,首先我們使用外掛找到我們的time地址破托,然后將time 的值改為60之后就發(fā)現(xiàn)命令行又從60開始了。
通過這個外掛我們就更加深刻了解指針的作用歧蒋,下面我們將使用幾個案例去了解指針的一些細節(jié)
6.案例:使用指針交換兩個數(shù)據(jù):
#include
#include
// 問 java 中有值傳遞和引用傳遞 嗎? 他們的區(qū)別是什么?
// 其實在java中只有值傳遞 , 沒有引用傳遞
// Person p = new Person(); p里面存放的內(nèi)容 就是person對象的地址
void swap2(int* p , int* q){ // 傳遞的形參為 i 和j 變量的地址
// *p 代表 i *q 代表就是 j
int temp;
temp = *p;
*p = *q;
*q = temp;
}
void swap1(int i ,int j){ // 形參 i 和j 跟主函數(shù)里面的i和j是兩個不同的變量
printf("子函數(shù) i 地址%#X ",&i);
printf("子函數(shù) j 地址%#X ",&j);
int temp;
temp = i;
i = j;
j = temp;
}
main()
{
//利用指針 可以在子函數(shù)里面修改主函數(shù)里面的數(shù)據(jù)
int i = 3;
int j = 5;
printf("i=%d ",i);
printf("j=%d ",j);
printf("主函數(shù) i 地址%#X ",&i);
printf("主函數(shù) j 地址%#X ",&j);
/*/交換兩個數(shù)字
int temp;
temp = i;
i = j;
j = temp;
*/
//方法一中確實將i,j的值交換了土砂,但是當(dāng)函數(shù)一執(zhí)行完,函數(shù)被回收谜洽,i,j就被銷毀了萝映,交換失敗
// swap1(i,j);
//方法二接收的是i,j的地址,i褥琐,j在main函數(shù)里锌俱,所以數(shù)據(jù)交換成功
swap2(&i,&j);
printf("交換后 ");
printf("i=%d ",i);
printf("j=%d ",j);
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
7.案例:使用指針獲取子函數(shù)的數(shù)據(jù):
#include
#include
//int** q 表示里面存放的是一個int* q的指針
f(int** q){
int i = 3;
printf("子函數(shù) i的地址 %#X ",&i);
// *q 代表的就是p變量
*q = &i;
} /**
使用指針的時候 不可以訪問已經(jīng)被系統(tǒng)回收掉的數(shù)據(jù)
子函數(shù)執(zhí)行完畢后 子函數(shù)里面所有的局部變量都會別系統(tǒng)回收
*/
main()
{
// 希望在主函數(shù)里面去使用子函數(shù)里面的變量 i
// f();
// 希望在主函數(shù)里面得到子函數(shù) 里面int i變量的地址
int* p ; //存放子函數(shù)f中 int i的地址的一個變量
f(&p);
/**在6中我們已經(jīng)說過函數(shù)會被回收晤郑,
* 當(dāng)f()函數(shù)一執(zhí)行完敌呈,就會被回收,i就會被回收
* 但是回收是有一定的時間造寝,所以如果我們在正在回收還未回收完全時去取值磕洪,
* 會得到正確的值或者地址,但是如果我們比如下面我先打印地址值诫龙,在去打印*p
* 此時p是i的地址值析显,而*p就不是了,因為此時i被回收了,但是我們注釋輸入地址值
* 此時*p就會成功打印i的值
*/
// printf("主函數(shù) i的地址 %#X ",p);
// printf("i的值為 %d ",*p);
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
8.案例:使用指針返回一個以上的值
#include
#include
// public List getPersons() {};
// public byte[] getbytes(){};
/*
如果讓子函數(shù) 更改主函數(shù)里面的數(shù)據(jù)
如何讓子函數(shù) 返回一個以上的值
1.子函數(shù)的形參 為 主函數(shù)中要修改的變量的地址
2. 調(diào)用子函數(shù)的時候 把要修改的變量的地址 傳遞給子函數(shù)
3. 在子函數(shù)里面 修改這個地址里面存放的變量的內(nèi)容
4. 主函數(shù)使用這個變量的時候 里面的值就發(fā)生了變化
*/
int f(int* p, int* q){
*p = 33;
*q = 55;
}
main()
{
int i = 3;
int j = 5;
f(&i,&j);
printf("i=%d ",i);//33
printf("j=%d ",j);//55
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
6.7.8案例總結(jié):
1.子函數(shù)在main函數(shù)中調(diào)用結(jié)束后會被銷毀签赃,隨之傳入的形參也會被銷毀
2.main函數(shù)里的數(shù)據(jù)要想通過子函數(shù)進行交互谷异,子函數(shù)的傳入的參數(shù)必定是指針變量
3.方法中的返回值不能像java中一樣返回集合之類的數(shù)據(jù)分尸,通過指針去返回多個數(shù)據(jù)。
9.指針的常見錯誤:
通過6歹嘹、7箩绍、8節(jié)我們細致的了解了指針,下面我們將講解指針的一些錯誤:
#include #include
main()
{
/* int* p; //定義一個指針變量 垃圾值 -> 野指針
//printf("*p=%d ",*p);
*p = 1231;
// 立刻藍屏
//
指針變量如果沒有賦值就不能使用
*/
/* int d = 324233;
char* c; ; // 編譯錯誤 不符合的指針類型
c = &d;
printf("*p = %c ",*c);
類型不相同的指針不可以互相轉(zhuǎn)換
*/
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
錯誤總結(jié):
1.指針變量中必須得有指針尺上,否則在取指針變量中的指針的值的時候會異常
2.不能給沒有定義指針的指針變量的指針的值賦值
3.指針變量和指針的數(shù)據(jù)類型必須一一對應(yīng)
10材蛛、指針占多少個字節(jié):
之前第二2節(jié)中我們知道了c的基本數(shù)據(jù)類型的字節(jié)數(shù),那么指針占多少個字節(jié)呢怎抛? 看代碼:
#include #include
main()
{
int i =3;
double d = 3.141692;
float f = 3.1423;
char c ='B';
int* ip = &i;
double* dp = &d;
float* fp = &f;
char* cp = &c;
//電腦不同輸入的值可能是4可能是8
printf("int 類型指針變量的長度為 %d ",sizeof(ip)); //8
printf("double 類型指針變量的長度為 %d ",sizeof(dp)); //8
printf("float 類型指針變量的長度為 %d ",sizeof(fp)); //8
printf("char 類型指針變量的長度為 %d ",sizeof(cp)); //8
// 在32位的操作系統(tǒng)上 因為程序 最大能使用的內(nèi)存空間的地址 就是2的32次方
// 指針只需要4位 就可以表示出來所有的內(nèi)存空間
// 64 并且編譯支持64位 8位
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
首先我們定義了不同的幾個變量卑吭,然后將他們的地址放入指針變量中,最后輸出马绝,我們居然發(fā)現(xiàn)輸出結(jié)果都一樣豆赏。
總結(jié):
1..指針變量的內(nèi)存大小是固定的,與數(shù)據(jù)類型沒有關(guān)系
2.指針變量的內(nèi)存大小最終取決于我們的電腦
11富稻、使用char* 指針表示字符串
在第二節(jié)中我們知道河绽,c語言中是使用char數(shù)組去表示一個java中的String字符串, 在我們學(xué)習(xí)指針之后我們將看看怎么用指針更加簡單的表示一個字符串:
#include #include
main()
{
char arr[20] ={'h','e','l','l','o',''};
// 利用char類型指針 方便的表示一個字符串
char* arr1= "hello world";
printf("%s",arr1);
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
從代碼中我們可以看到使用char數(shù)組的方式是比較復(fù)雜的唉窃,然后我們使用指針的方式:char* arr1="",這樣就可以簡單的直接表示一個字符串
注意:在java中我們定義數(shù)組可以int arr[]; int [] arr;但是在c語言中[]只能卸載變量名后面耙饰,如:int arr[]
12、指針與數(shù)組
指針進階:
#include
#include
// 數(shù)組是一塊連續(xù)的內(nèi)存空間 數(shù)組名 就是內(nèi)存空間的首地址
// 數(shù)組名[i] == *(數(shù)組名+i);
main()
{
/* char[] arr = new char[20];
char arr[] ;
*/
// 創(chuàng)建一個長度為5的int類型的數(shù)組
int arr[5] ={1,2,3,4,5};
printf("a[0]=%d ",arr[0]);
printf("a[4]=%d ",arr[4]);
// 邏輯上是錯誤的代碼 數(shù)組下標(biāo)越界
// printf("a[5]=%d ",arr[5]);
// windows xp 緩沖區(qū)越界補丁
// arr是一個什么東西呢?
printf("arr = %#X ",arr);
// 打印 數(shù)組的第一個元素的地址
printf("arr[0]地址 = %#X ",&arr[0]);
// 打印數(shù)組中的第二個元素
printf("arr[1]=%d ",arr[1]);
printf("arr[1]=%d ", *(arr+1));
//問題: arr[i] *(arr+i) 代表的是同一個變量么?
// 代表的是同一塊內(nèi)存空間 指向的是同一個變量
//通過實驗 : 數(shù)組名表示的 就是這個數(shù)組第一個元素 的首地址
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
· 語言語法上沒有數(shù)組越界纹份,在邏輯上存在數(shù)組越界苟跪,
· arr是一個指針,arr的指針就是&arr[0]的指針蔓涧,也就是說數(shù)組的指針就是數(shù)組第一個元素的指針
· 數(shù)組中的數(shù)據(jù)的指針是一塊連續(xù)的內(nèi)存空間
· arr[i]等同于*(arr+i)
13件已、指針的計算
通過上一節(jié)我們大概知道了指針與數(shù)組的關(guān)系,下面我們通過一個案例去鞏固一下:
#include #include
main()
{
int i =3; //天津的某個路上 蓋了一個房子 3
int j =5; // 北京的某個路上 蓋了一個房子 5
int* p = &i; // p 天津的門牌號
int* q = &j; // q 北京的門牌號
// 指針的運算和數(shù)組都是緊密關(guān)聯(lián)的
char arr[5]={'a','b','c','d','e'}; //一塊連續(xù)的內(nèi)存空間
char* p1 = &arr[2];
printf("char = %c ", *(p1-1));
// char 內(nèi)存中占用 1個字節(jié)
// int 內(nèi)存 中占用 4個字節(jié)
int intarr[5]={1,2,3,4,5}; //一塊連續(xù)的內(nèi)存空間
int* q1 = &intarr[2];
printf("char = %d ", *(q1-1));
// 指針的運算 按照 約定好的數(shù)據(jù)類型 偏移相對應(yīng)的內(nèi)存空間的大小
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
總結(jié):
1. 數(shù)組中的數(shù)據(jù)的指針是一塊連續(xù)的內(nèi)存空間
2. 指針的運算按照約定好的數(shù)據(jù)類型偏移相對應(yīng)的內(nèi)存空間的大小
14.案例:通過子函數(shù)打印數(shù)組
#include
#include #define pi 3.1415
// 寫一個子函數(shù) 打印數(shù)組里面的每一個元素
void printArr(int* arr, int len){ // arr是數(shù)組的首地址 len數(shù)組的長度
int i=0;
for(;i
// printf("arr[%d]=%d ",i,arr[i]); // arr[i] 和 *(arr+i) 代表的含義相同
printf("arr[%d]=%d ",i, *(arr+i));
}
}
main()
{
// int arr[10]={1,2,3,4,5};
printArr(&arr[0],10);
//1 .定義一個數(shù)組 缺陷 數(shù)組的長度 必須事先申請好
//2. 循環(huán)賦值
//3. 打印數(shù)組里面的內(nèi)容
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
總結(jié):
1.int arr[5]; 這一句代碼一旦執(zhí)行 ,就立刻會在內(nèi)存里面申請 5個內(nèi)存空間 每個內(nèi)存空間的大小可以存放一個int類型的數(shù)據(jù)
2.留下疑問:沒有辦法動態(tài)的增加這一塊空間的大小, 也沒辦法減小這一塊內(nèi)存空間元暴,只能提前寫死篷扩,例如我們代碼中arr[10],直接就將我們的arr數(shù)組大小寫死了
15茉盏、realloc()方法介紹
在上一節(jié)中我們留下的疑問是不能更改數(shù)組的內(nèi)存控件鉴未,而realloc()方法則完美解決了這個問題,具體使用方式:
int arr[10];
arr = realloc(arr,sizeof(int)*12); //空間的長度為12了
首先我們可以看到realloc接收兩個參數(shù):
1.第一個參數(shù)表示你需要更改大小的變量
2.第二個表示更改之后的長度
我們了解了realloc()方法是可以更改變量內(nèi)存大小的鸠姨,那么就會存在這樣一個問題铜秆,改變之后的內(nèi)存會不會覆蓋之前的數(shù)據(jù)呢?
1.對于增加內(nèi)存:realloc是直接在原有的基礎(chǔ)上添加內(nèi)存空間讶迁,所以還是會保持原有的數(shù)據(jù)再進行添加
2.對于減少內(nèi)存:realloc是會將排列在最后的內(nèi)存空間值給回收掉的连茧, 比如原始數(shù)據(jù)int arr[4]={1,2,3啸驯,4}客扎;減少2個內(nèi)存的話,就是int arr[8]={1,2}
·
16罚斗、動態(tài)分配內(nèi)存
前面我們看到我們定義的那些函數(shù)變量等虐唠,都是由系統(tǒng)給我們自動分配內(nèi)存,我們是不用去理會系統(tǒng)到底什么時候去給我們分配惰聂,什么時候去回收疆偿,
而接下我們要學(xué)習(xí)的是自己去管理內(nèi)存即動態(tài)分配內(nèi)存,看代碼:
#include
#include
#include
// malloc memory allocate 內(nèi)存申請
main()
{
// 接受一個參數(shù) 申請多大(byte)的內(nèi)存空間
int* p = (int*)malloc(sizeof(int)); // 在堆內(nèi)存里面申請一塊可以存放一個int類型數(shù)據(jù)的內(nèi)存空間
*p = 4; // 就是往 p 里面存放的地址 表示的那塊內(nèi)存空間里面存放一個int類型的數(shù)據(jù) 4
printf("*p=%d ",*p);
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
代碼中我們首先如java導(dǎo)入類的方式搓幌,在代碼上面添加了一行: 這個就是動態(tài)內(nèi)存所要用到的方法了杆故,接下來我們在main函數(shù)中 int* p = (int*)malloc(sizeof(int)); 這樣我們即給指針變量p分配了int字節(jié)大小的內(nèi)存空間,完成了一個動態(tài)分配內(nèi)存的操作
這樣我們就可以使用如上方式去解決上一節(jié)中的疑問了
學(xué)到的知識點:
· malloc(byte length)方法用于動態(tài)申請內(nèi)存溉愁。
· 動態(tài)申請內(nèi)存其實就是在申請指針
疑問:
· 我們之前看到的处铛,函數(shù)使用完成后是會被回收掉的,難道我們動態(tài)申請內(nèi)存怎么被回收呢拐揭?不然是會浪費內(nèi)存空間的
17撤蟆、動態(tài)分配內(nèi)存2
在上節(jié)中我們已經(jīng)知道了malloc(byte length)方法是用來動態(tài)分配內(nèi)存的, 下面我們將通過一個小案例來進一步講解動態(tài)分配內(nèi)存堂污,并且解決上一節(jié)中的疑問
#include
#include
#include
f(int** address){ //address 存放的是q的地址
// 動態(tài)的在堆內(nèi)存里面申請一塊空間
int* p ;
p = (int*)malloc(sizeof(int)*3);
*p = 3;
*(p+1) = 4;
*(p+2) = 5 ;
printf("子函數(shù)里面 地址%#X ",p);
*address = p;
// 在子函數(shù)里面把p釋放掉了
//free(p);
}
main()
{
int* q ;
f(&q);
printf("主函數(shù)里面 地址%#X ",q);
printf("*q = %d ",*(q+0));
printf("*q = %d ",*(q+1)); // 殘留的內(nèi)存映像
printf("*q = %d ",*(q+2));
//動態(tài)內(nèi)存分配 程序員可以自己手工的決定一個變量的生命周期
//手工的釋放調(diào)用內(nèi)存空間
//不要使用已經(jīng)回收掉的內(nèi)存空間里面的數(shù)據(jù)
system("pause"); // 調(diào)用windows下系統(tǒng)的命令 讓程序暫停執(zhí)行 方便觀察程序的執(zhí)行結(jié)果
}
首先我們看到是f(int** address) 其中int **表示的是多級指針家肯,下面我們會詳細介紹,在這里只要知道他是一個存放指針變量的指針變量就行了盟猖, 然后定義一個指針變量p并動態(tài)分配內(nèi)存和賦值讨衣, 最后將p傳遞給f(int** address)的形參
接著我們看到main函數(shù)中我們使用了f()函數(shù)并得到了f()函數(shù)中的值
細心的同學(xué)可能可以看到我們在f()方法中可以看到我們注釋的一個函數(shù):free(p)
free(p):將動態(tài)釋放的內(nèi)存給回收,使用free(p)函數(shù)即可解決我們在上一節(jié)留下的疑問,其中p是我們需要釋放內(nèi)存的指針變量
接著我將free(p)打開式镐,按理說p分配的動態(tài)內(nèi)存空間的數(shù)據(jù)是會被free(p)執(zhí)行后給回收的反镇,最后居然發(fā)現(xiàn)在main函數(shù)打印(q+0)為0,(q+1)為4娘汞,(q+2)為5歹茶, 結(jié)果可想而知free(p)難道只將第一個數(shù)據(jù)給回收了?其實在執(zhí)行free(p)之后確實將p給回收了你弦,(q+1)為4惊豺,(q+2)為5,只是殘留的映像鳖目,在回收過程中只是將p的內(nèi)存空間標(biāo)記為可以再次寫入扮叨,其實真正并沒有徹底回收,所以會出現(xiàn)這種情況
寫在最后
關(guān)于怎么快速學(xué)C/C++,可以加下小編的C/C++學(xué)習(xí)群:领迈,814+974+917,邀請碼:云志,不管你是小白還是大牛狸捅,小編我都歡迎衷蜓,不定期分享干貨,歡迎初學(xué)和進階中的小伙伴尘喝。