Course Overview
數組下標越界訪存
#include <stdio.h>
typedef struct {
int a[2];
double d;
} struct_t;
double fun(int i) {
volatile struct_t s;
s.d = 3.14;
s.a[i] = 1073741824;
return s.d;
}
int main() {
for (int i = 0; i < 100; ++i)
{
printf("fun(%d) = %.8lf\n", i, fun(i));
}
return 0;
}
fun(0) = 3.14000000
fun(1) = 3.14000000
fun(2) = 3.13999987
fun(3) = 2.00000061
fun(4) = 3.14000000
fun(5) = 3.14000000
zsh: segmentation fault
由於數組下標索引越界不檢查,當i >= 2時會修改a數組內存後的區域。當修改a[2],a[3]的時候會影響到結構體雙精度浮點數d的內存空間,從而影響fun函數的返回值。當i>=4時會繼續修改後面的內存,當i爲6時觸發了段錯誤導致程序崩潰,該內存最有可能是記錄已經分配的內存無法修改。
訪問內存方式與性能的關係
#include <stdio.h>
#include <time.h>
int a[2048][2048], b[2048][2048];
void copyij(int src[2048][2048], int dst[2048][2048])
{
int i, j;
for (i = 0; i < 2048; ++i)
{
for (j = 0; j < 2048; ++j)
{
dst[i][j] = src[i][j];
}
}
}
void copyji(int src[2048][2048], int dst[2048][2048])
{
int i, j;
for (j = 0; j < 2048; ++j)
{
for (i = 0; i < 2048; ++i)
{
dst[i][j] = src[i][j];
}
}
}
int main()
{
clock_t start_time, end_time;
double duration;
start_time = clock();
copyij(a, b);
end_time = clock();
duration = double(end_time - start_time) / CLOCKS_PER_SEC;
printf("copyij的運行時間: %lf\n", duration);
start_time = clock();
copyji(a, b);
end_time = clock();
duration = double(end_time - start_time) / CLOCKS_PER_SEC;
printf("copyji的運行時間: %lf", duration);
return 0;
}
copyij的運行時間: 0.024819
copyji的運行時間: 0.112909
CLOCKS_PER_SEC是標準c的time.h頭函數中宏定義的一個常數,表示一秒鐘內CPU運行的時鐘週期數,用於將clock()函數的結果轉化爲以秒爲單位的量,但是這個量的具體值是與操作系統相關的。
在一臺普通個人臺式機上粗略計算可以看到copyij與copyji性能上的差距,特定的機器上,我們運行它的性能會有更大的差距。不同的訪存方式會有不同的性能體驗,很明顯得得出結論先行再列的訪問方式由於先列後行的方式。我的猜想是:dst[i][j]
實質是指針訪問*((dst + i * 2048) + j)
頻繁地移動回溯指針性能消耗大。