開發中數組是一種常見的數據結構,當然我們知道數組相當於一種容器,但是它不僅僅只能存數值和字符,同時它還可以存放函數的入口地址,以及結構體的數據。
typedefstruct _value
{
int val_1;
int val_2;
}VALUE;
typedef struct _table
{
char index;
chardata[100];
int(*UniSetFunc)(VALUE*);
}TABLE;
int add(VALUE*val )
{
inttemp = 0;
temp = val->val_1 + val->val_2;
returntemp;
}
TABLE page[10]
{
{“ First section ”, “abcdefghijklmn”, add},
{“Second section”, “opqrstuvwxyz”, NULL}
};
intmain()
{
VALUEAddValue;
AddValue.val_1 = 2;
AddValue.val_2 = 4;
intresult = 0;
result= page[0]-> UniSetFunc(&AddValue);
printf(“The Result of add is %d\n”,result);
return 0;
}
此時數組就轉換為類似於Python語言中的字典的結構,便於後續的開發利用以及追加升級和維護。
代碼分析:首先我們知道函數的名字可以做為函數的入口地址(類似於數組的名代表數組的地址一樣),所以在TABLE結構體中我們定義了一個成員函數int(*UniSetFunc)(VALUE*); 此處UniSetFunc作為函數的入口參數,VALUE*代表函數的形參類型;TABLE類型的數組 page[10]即包含了結構體的數據以及函數的入口地址,可以通過調用page[0]-> UniSetFunc(&AddValue)來間接地調用add函數並實現AddValue中AddValue.val_1和AddValue.val_1兩個數求和的運算。
內存命中率問題:
為了可以提高代碼運行效率,要才充分的利用內存空間,應連續的訪問內存區域。
我們知道數組在內存中存放的位置是一整塊的區域,並且是連續存放的,對於定義的數組array[2][2]來說,假設array[0][0]的地址為0x04030,則array[0][1],array[1][0],array[1][1] 的地址分別為0x04031, 0x04032, 0x04033;提高內存命中率的即是應該盡可能的連續的訪問內存空間區域,而非跳躍式的訪問;接下來讓我們來看一個矩陣相乘的問題。
for(int i = 0; i < 2; ++i)
{
for(int j = 0; j < 2; ++j)
{
for(int k = 0; k < 3; ++k)
{
matrix[i][j]+= matrix1[i][k] * matrix2[k][j];
}
}
}
以上代碼是常用的將矩陣matrix1與matrix2相乘然後賦值給matrix的方法,即用matrix1矩陣得到行向量乘以矩陣matrix2的列向量,然後賦值給matrix,這樣由於矩陣在內存存儲的結構,我們可以清楚的知道訪問matrix2的時候並非采用連續的訪問方式,故內存的命中率較低。接下來我們看一種高內存命中率的方法。
for(int i = 0; i < 2; ++i)
{
for (int k = 0; k < 3;++k)
{
for (int j =0; j < 2; ++j)
{
matrix[i][j]+= matrix1[i][k] * matrix2[k][j];
}
}
}
可以看出代碼僅僅將第二個for循環與第三個for循環交換了位置,而其他的部分沒有任何變化,然而內存的命中率卻大大的提高了,我們采用將matrix1與matrix2矩陣內部各原素依次相乘然後再累加的方式,來進行矩陣相乘的目的,這樣在訪問matrix1與matrix2矩陣時沒有發生任何內存未命中的問題,從而提高了內存命中的概率。
volatile,const以及static之間的關系:
const關鍵字為常量關鍵字,它作用的量為常量,不允許程序去改變該常量的值,如constint value = 12;此常量value值不允許程序將其改變,在開發的過程const關鍵字會經常用到,為了防止程序意外的改變某一固定的常量,我們應及時的給其加上const關鍵字;另外const關鍵字作用於常量時必須直接給常量初始化,因為在整個程序運行大的過程中不允許對其改變,故必須立即初始化,例如:const intvalue = 12 是正確的,而constint value; value = 12;這樣的語法是錯誤的! 接下來我們來研究一個稍微難一點的問題,即常量指針與指針常量。先看一段代碼:
#defineSWITCH 1
intmain()
{
int val_1 = 5;
int val_2 = 10;
const int *p1 = &val_1;
int const *p2 = &val_1;
int *const p3 = &val_1;
#ifdefSWITCH // This is a switch
*p1 = 20;
*p2 = 21;
*p3 = 22;
#endif
#ifndefSWITCH
p1 = &val_2;
p2 = &val_2;
p3 = &val_2;
#endif
printf("%d\n", *p1);
printf("%d\n", *p2);
printf("%d\n", *p3);
return 0;
}
在cygwin編譯器下執行,我們可以看到這樣的錯誤:
從圖中我們可以清楚的看到,指針p1與p2僅能讀取val_1中的值為指針常量,即不能改變它所指的變量的內容,所以*p1 = 20; *p2 = 21;兩條命令是錯誤的!(#ifdef SWITCH … #endif 為條件編譯即為宏開關)。然後我們將#define SWITCH 1 語句給注釋掉,此時將運行第二塊代碼,得到結果如下:
從錯誤中可以看出p3為常量指針,它只能指向一個固定的地址,而不能改變它所指的方向,故p3= &val_2;的操作是錯誤的,因此正確的代碼如下:
int main()
{
intval_1 = 5;
intval_2 = 10;
constint *p1 = &val_1;
intconst *p2 = &val_1;
int*const p3 = &val_1;
printf("Frist\n");
printf("%d\n",*p1);
printf("%d\n",*p2);
printf("%d\n",*p3);
p1= &val_2;
p2= &val_2;
*p3= 22;
printf("Second\n");
printf("%d\n",*p1);
printf("%d\n",*p2);
printf("%d\n",*p3);
return0;
}
運行的結果為: