數組的定義
首先定義一個變量,來存儲一個人的年齡,例如:
#include<stdio.h> //頭文件
void main() //程序入口
{
int age = 20; //定義變量age並儲存值爲18
return; //程序結束
}
這沒什麼困難,但要是現在要求我們儲存20個人呢?如果一個一個去定義,那豈不是很浪費時間,這個時候,我們就可以使用數組了。
數組其實就是把一堆數據定義到一塊了,然後起一個名字,定義一個數據類型。
數組的格式:
數據類型 變量名[常量]={x,y,z};
例如:
#include<stdio.h> //頭文件
void main() //程序入口
{
int age [20]={1,2,3,4,5,6,7,8,9,10}; //定義數組
return; //程序結束
}
這裏需要說一下,爲什麼定義數組要用常量而不是變量,下面的這個例子不可以碼?
#include<stdio.h> //頭文件
void shuzu(int x) //定義函數
{
int age[x]; //定義變量age
return; //函數結束
}
void main() //程序入口
{
shuzu(20); //調用函數並傳值
return; //程序結束
}
上面這塊代碼,從邏輯上看起來好像沒什麼毛病,但是這麼寫是不行的,我們反彙編一下正常的程序就明白了:
這裏可以看到,我們要求age可以存20個數,所以堆棧提升了90,但是如果我們用變量的話,程序就不知道我們要存多少個數,堆棧就無法提升,反彙編生成不了,自然就會報錯了。
那麼如果我們傳值會堆棧怎麼樣呢:
#include<stdio.h> //頭文件
void main() //程序入口
{
int age [20]={1,2,3,4,5,6,7,8,9,10}; //定義數組並傳值
return; //程序結束
}
看一下反彙編:
可以看到,最先存進去的參數,地址編號最少。
數組的內存分配
如果我們把程序的函數據結構定義成char,看一下堆棧中會有什麼變化:
#include<stdio.h> //頭文件
void main() //程序入口
{
char age [20]; //定義數組
return; //程序結束
}
看一下反彙編:
90-54=36 = 54
這裏相對於之前的90減少54,也就是說,同樣的程序,不同類型,它少分配了36,這裏用的是char,但是爲啥要少分配36呢,這是因爲每臺電腦的本機寬度不同,我這裏是32位操作系統,處理4字節的程序比處理2字節的程序要方便,所以它4個字節的減少。
數組的讀寫
假如我們要往定義的數組裏存值,我們可以這樣寫:
#include <stdio.h> //頭文件
void main() //程序入口
{
int age[5]; //定義數組age,可以存儲5個數
age[0] = 1; //往數組的第一位存一個1
age[1] = 2; //往數組的第二位存一個2
age[2] = 3; //往數組的第三位存一個3
return; //程序結束
}
看一下堆棧:
跟之前統一傳值是一樣的。
數據存進去了我們也要讀,那麼怎麼讀數據呢,例如:
#include <stdio.h> //頭文件
void main() //程序入口
{
int age[5]; //定義數組age,可以存儲5個數
int r;
age[0] = 1; //往數組的第一位存一個1
age[1] = 2; //往數組的第二位存一個2
age[2] = 3; //往數組的第三位存一個3
r = age[1]; //讀取age數組裏的第二個數
printf("%d \n",r); //把讀出來的數輸出到控制檯
return; //程序結束
}
運行結果:
當然,我們還可以這麼取值:
#include <stdio.h> //頭文件
void main() //程序入口
{
int age[5] = {1,2,3,4,5}; //定義數組age,可以存儲5個數
int r; //定義變量
int x;
x = 0 //變量賦值
r = age[x]; //讀取age數組裏的第x個數
printf("%d \n",r); //把讀出來的數輸出到控制檯
return; //程序結束
}
這裏可以用x,就可以用x+y,x+1等等,只要你能返回一個結果,這個結果不超出數組的長度,那麼值就可以取出來,這裏就不一一舉例了,原理是相通的,運行結果:
注:定義數組的時候,必須是常量,而使用數組的時候,可以是變量。
讀取越界
什麼叫越界呢,就是你讀取的數超過了你定義數組的長度,例如:
#include <stdio.h> //頭文件
void main() //程序入口
{
int age[5] = {1,2,3,4,5}; //定義數組age,可以存儲5個數
int r;
int x;
x = 15; //讀第16個數,這裏就越界了
r = age[x]; //讀取age數組裏的第x個數
printf("%d \n",r); //把讀出來的數輸出到控制檯
return; //程序結束
}
這樣寫是不可以的,越界後的值是不可控的,在編寫程序的時候,一定要避免越界!看一下程序的運行結果:
一個緩衝區溢出的程序
通過這個程序,可以瞭解一下所謂的緩衝區溢出,挺有意思的:
#include <stdio.h> //頭文件
#include <windows.h>
void Fun() //定義函數
{
while(1) //無限循環
{
printf("1匹黑馬,專注於滲透測試與二進制安全!\n"); //輸出內容
}
}
int check() //定義函數
{
int arr[9]; //定義數組,可以存儲9個數
arr[10] = (int)&Fun; //把Fun()函數的起始地址轉爲int類型存到數組的第11位中
return 0;
}
void main() //程序入口
{
check(); //調用函數
getchar();
return; //getchar
}
運行結果:
從堆棧圖中就可以理解這是怎麼回事: