程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C/C++深度分析

C/C++深度分析

編輯:C++入門知識

C/C++深度分析


C語言數組

開發中數組是一種常見的數據結構,當然我們知道數組相當於一種容器,但是它不僅僅只能存數值和字符,同時它還可以存放函數的入口地址,以及結構體的數據。

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;

}

運行的結果為:

1.PNG

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved