表達式求值的過程中,往往會伴隨著數據類型的自動轉換,而數據類型的轉換的一般情況如下所示,從低到高。
long double
double
float
unsigned long int
long int
unsigned int
int
有幾點需要注意:
1. 這里沒有出現char,short,enum,因為它們會被自動轉換為int或是unsigned int類型
2. 當unsigned int 和 int 出現在同一個式子中時,需要注意,如:5u – 10,結果是大于0的,不是-5,而是4294967291
3. 另外對于32位機,由于long int的表現形式與int相同,unsigned int的表現形式與unsigned long int相同,因此long int的數值范圍無法包含unsigned int,因此在32位機進行處理時,它們間的類型的自動轉換可以理解為4位的有符號自動轉為4位的無符號,然后再向上轉為float型等;如 unsigned int a = 45; long int b = 2147483643; a + b中可以理解為都轉換成了unsigned long類型
摘要:就windows下傻瓜式安裝codelite時出現的一些問題進行了闡述,并提供了一定的解決方案,希望對于遇到相同情況的讀者有所幫助。
在這里不說為什么選擇codelite這么個IDE,其實這樣的爭執在幾分鐘后往往會偏離正題,思緒被情緒控制,各執己見,何謂?
什么是傻瓜式安裝呢,就是在windows下,利用release的安裝版本,這里下的是包含wxWidget,MinGW的安裝版本,然后根據它的指示一直下一步下一步進行就行了。如果你的機子最初是干干凈凈的,最后安裝的程序會是成功的。但是這基本上是不可能的,而我呢,恰好由于事先在機子上裝了些東西,就使得安裝完成后并不能像codelite官網中quick start所說的那樣進行操作。
想原因可能如下:
*. 原來安裝過code::block,將code::block自帶的mingw32-make.exe所在的目錄加在了環境變量中,并且原來安裝過庫wxWidget的低版本,由于選擇了codelite,于是將wxWidget原來的版本和code::block都刪除了。并在環境變量中也將值刪除了。
然后卸載掉codelite進行重裝,不過依然不能運行wxWidget框架程序。build時出現需要將“WXWIN = C:\wxWidget”的提示,查看了一下setting:tags setting : ctags : include files內包含的竟然是perl中的mingw,額裝的東西太多了,于是將perl相關的環境變量也刪除了。
繼續重裝,結果發現依然沒有任何改變,悲劇,到底是怎么回事呢,細想來,原來C盤的Application Data中有codelite的配置文件,由于卸載的過程中并沒有將這些配置文件刪除,重裝后依然使用的是這些配置文件,才導致了問題的出現,于是將Application Data下的codelite文件夾刪除,再進行重裝,終于是成功了。
傻瓜式安裝,只是設想到了理想的情況下如何進行處理,沒有料想到會出現想我這樣的情況,所以安裝結束后相關配置文件中的數據的設定出現了錯誤,導致無法正常build。
至此,安裝結束了,學習才剛剛開始。
也許你會說,為什么不從codelite軟件中對配置數據進行設定呢,其實進行了嘗試,正確的設定了ctags : include files的位置,但是結果依然無法build,出現類似“WXWIN = C:\wxWidget”的提示,于是將其設置到環境變量中也沒有得到相應的解決,所以茫然之下才出此下策,一切從頭開始。
相信隨著深入的學習,對于它的處理方式,配置文件的設定等,都會慢慢了解的,一鳴驚人的背后蘊含著多少的厚積呢,急不來的。
補充一下:
環境變量的設置不是設置計算機的環境變量,而是設置codelite下setting下的環境變量,額,因為慣性思維沒有考慮到這點,悲劇哦。
VIM的學習不是一天兩天的事情,先用著IDE吧,并逐步學習VIM的使用。
最近由于工作的需要,要用到界面的開發,選什么庫呢,MFC,Qt or wxWidget。對微軟的東西有種莫名的反感,也許那么多年了不得不用它的產品,特別是操作系統,有時特別是在安裝程序的時候,點著是否接受協議,不接受自然是無法安裝了,都習慣性點擊同意了,會剎那的感覺自己是不是被當作了一個“低能兒”的,也許是這么一種心理的作怪,總是在矛盾中用著微軟的產品,想跳出使用linux,但是學習上,別人都是用office進行操作,導師對于工作的檢查也都用MS office,換用linux的話會使工作進度,交流等產生一定的障礙吧。很多東西就仿佛和它綁在了一起。慢慢來,一步一步將它對自己的影響逐漸降低吧,又從開源的角度考慮,選擇了wxWidget于是又選擇了codelite作為學習該庫的IDE了。自然VIM依然在不斷的進行中。
相信微軟是無法束縛我的思維的。成為工具的主人。
總結:
隨著對VIM的慢慢接觸,逐漸發現了它作為編輯器的強大,相信自己會持之以恒的。
習慣有時能夠在解決問題上節省很多的時間,但會使得一個人的敏感性降低,沒有什么東西是一塵不變的,正因為人們都在重復著一種類似的生活方式,上班,工作,回家,睡覺,繼而上班,這樣不斷的往復著,或是學習上課等,也是以一種類似的方式往復著,這樣便更加容易陷入到習慣的河流中,慢慢迷失了原有的激情,原有的對于事、對于人的敏感性。在這里并不是想要一味著貶低習慣,只是想喚醒人們心中那種不知道出現了多久的迷茫,喚醒覆滅已久的熱情,讓他們能夠在生活的腳步中,保持一顆清醒的頭腦,成為習慣的主人,而不是成為習慣的奴隸,并謹記流動著的才是真理,死寂不變的是一灘死水,今天的清澈,并不能改變未來的骯臟與渾濁。
寫給自己,也寫給大眾。
摘要:簡要比較了直接、指針、引用三中函數參數傳遞方式,并對其優缺點進行了大致的說明
1. 眾所周知,函數參數的直接傳遞就是實現一個拷貝值,這個拷貝值的變化,并不會改變原值的變化,因為兩個被來就是不同的個體,就好比兩個克隆的個體,雖然兩者之間有很多相同的地方,但是它們的思維是獨立的。
2. 通過指針的方式給函數參數傳值呢,從根本上來講,它仍然是直接傳值,但是這個拷貝的值比較特殊,是一個地址罷了,如:
1: void fun(int *pnValue)
2: {
3: ...;
4: }
5: int main()
6: {
7: int nValue = 6;
8: fun(&nValue);
9: }
它其實是將nValue的地址拷貝給了pnValue,如果在fun函數中,一開始就將pnValue的值給改變,如pnValue=&nValue2,那么pnValue指向的內容的改變,將不會影響到nValue。
同時有一點需要注意的是,空指針對象是沒有意義的,會引起程序的奔潰,因此在開始因該進行檢測,if(!pnValue) return;
通過指針傳參數的優點:
1) 允許你改變傳遞的參數的值
2) 由于它拷貝的僅僅是一個字節大小的地址,因此傳遞的過程是快速的,特別對于較大的結構或是類
3) 我們通過這種傳參方式,獲取從函數中返回的多個量
缺點:
1) 傳遞的只能是普通的變量,不能是字面常量或表達式
2) 所有的傳遞值都得檢查是不是空指針
3. 通過引用的方式傳遞參數
雖然在底層的操作中,通過引用也是通過“指針的方式”進行實現的http://blog.csdn.net/wanwenweifly4/article/details/6739687),但是從語言上考慮,引用是對象的別名,也是一個對象,并不是指針,因為它的概念是在語言上定義的,而不是底層的實現方式,換一種思維,拋開所有的比匯編語言高級的語言,回到匯編語言建立初期,單單從匯編語言上考慮,那時有沒有指針的概念呢?因此應該理性的對待引用在C++語言中的概念,也應該冷靜的認識它在底層中的實現方式,區分的對待,其實也不用爭執于這個問題,認清了,會用了,就成了。(這些僅個人見解,批判的看待吧)。
它在傳參中的優點:
1) 允許你改變傳遞的參數的值
2) 傳遞的過程是快速的,特別對于較大的結構或是類
3) 可以通過添加一個const,避免不經意的改變
4) 我們通過這種傳參方式,獲取從函數中返回的多個量
缺點:
1) 非const類型的參數,傳遞的只能是普通的變量,不能是字面常量或表達式
2) 不容易區分哪些變量是input,需要output,或都是
3) 通過函數的調用,很難看出那個參數是將被改變的,因為它和直接傳值的方式相同,只能通過函數原型進行辨認,當程序員不小心忽視的時候,可能會導致錯誤的發生
ps:
1: #include <iostream>
2:
3: int nFive = 5;
4: int nSix = 6;
8: void SetToSix(int *pTempPtr);
9:
10: int main()
11: {
12: using namespace std;
13:
16: int *pPtr = &nFive;
19: cout << *pPtr;
20:
23: SetToSix(pPtr);
27: cout << *pPtr;
28:
29: return 0;
30: }
31:
33: void SetToSix(int *pTempPtr)
34: {
35: using namespace std;
36:
38: pTempPtr = &nSix;
41: cout << *pTempPtr;
42: }
上面這個程序中輸出的結果是 565
如果想使得輸出的結果為566呢,有一個方法可以實現,就是采用指針的引用,如下:
1: // pTempPtr is now a reference to a pointer to pPtr!
2: // This means if we change pTempPtr, we change pPtr!
3: void SetToSix(int *&pTempPtr)
4: {
5: using namespace std;
6:
7: pTempPtr = &nSix;
8:
9: // This will print 6
10: cout << *pTempPtr;
11: }
1. const指針總是指向相同的地址,該地址是不能被改變的.
1: int nValue = 5;
2: int *const pnPtr = &nValue;
*pnPtr = 6; 這樣的操作是可行的;而 int nValue2 = 2; pnPtr = &nValue2;這樣的操作是不可行的。
int *const pnPtr 可以這么理解,pnPtr當作地址,該指針有const地址,并且指向一個整型變量。
2. 指向const變量(雖然這個變量本身可以不是const的)的指針
1: int nValue = 5;
2: const int *pnPtr = &nValue;
const int *pnPtr可以這么理解,一個可以改變地址的指針指向的是一個不能改變大小的變量。
也就是說,*pnPtr = 6;這樣是不行的;int nValue2 = 6; pnPtr = &nValue2;這樣是可行的
3. 當然,還有一種就是兩者都不能改變了。
int nValue = 2;
const int *const pnPtr = &nValue;
不過此時可以通過nValue=6;來改變*pnPtr的值。把int nValue = 2;改成 const int nValue = 2;那么就什么都不能變咯。
摘要:舉了幾個動態內存分配過程中,發生內存泄漏的例子
1. 分配了內存,卻沒有及時刪除,導致泄漏
1: void doSomething()
2: {
3: int *pnValue = new int;
4: }
2. 為指針變量分配了一個內存,然后又讓指針變量指向其他的值,導致泄漏
1: int nValue = 5;
2: int *pnValue = new int;
3: pnValue = &nValue; // old address lost, memory leak results
3. 連續分配了兩次內存,第一次分配的內存由于沒有delete,導致泄漏
1: int *pnValue = new int;
2: pnValue = new int; // old address lost, memory leak results
先來看一下一段代碼:
1: char szString[255];
2: cin >> szString;
3: cout << “You entered: ”<< szString << endl;
這段代碼在c++程序中是很常見的,但仔細想一下如果你輸入的字符串長度大于255,就會出現溢出的現象,也許這個問題通常會被人忽略。
其實我們可以選擇一個更好的實現方法,如下
1: char szString[255];
2: cin.getline(szString, 255);
3: cout << "Your entered: " << szString << endl;
通過這樣的方式,像第一個例子中可能出現的內存溢出的現象就可以避免了。
from http://www.learncpp.com/cpp-tutorial/59-random-number-generation/
通常在游戲,統計模型程序和科學模擬中會用到隨機事件。
而由于計算機的本質結構決定計算機只能生成偽隨機數據。
偽隨機生成器,設定一個初始值(seed),對它進行操作形成不同的數值,讓它看上去與初始值沒有聯系。如果算法足夠復雜,將同樣的算法用到最后生成的數字,這樣就能夠產生一些列看上去隨機的數值。
下面是一個產生100個偽隨機數的程序:
1.
1: #include <stdafx.h>
2: #include <iostream>
3: using namespace std;
4:
5: unsigned int PRNG()
6: {
7: // our initial starting seed is 5323
8: static unsigned int nSeed = 5323;
9:
10: // Take the current seed and generate a new value from it
11: // Due to our use of large constants and overflow, it would be
12: // very hard for someone to predict what the next number is
13: // going to be from the previous one.
14: nSeed = (8253729 * nSeed + 2396403);
15:
16: // Take the seed and return a value between 0 and 32767
17: return nSeed % 32767;
18: }
19:
20: int main()
21: {
22: // Print 100 random numbers
23: for (int nCount=0; nCount < 100; ++nCount)
24: {
25: cout << PRNG() << "\t";
26:
27: // If we've printed 5 numbers, start a new column
28: if ((nCount+1) % 5 == 0)
29: cout << endl;
30: }
31: }
事實上我們這個例子并不是很好,但是它足夠用來說明偽隨機數是如何產生的。
C++產生偽隨機數
語言中有內置的隨機數生成器,它需要兩個獨立的函數組合使用。
srand() 用來設置初始seed。srand()通常只調用一次。
rand()生成序列中的下一個隨機值。
2.
1: #include <iostream>
2: #include <cstdlib> // for rand() and srand()
3: using namespace std;
4:
5: int main()
6: {
7: srand(5323); // set initial seed value to 5323
8:
9: // Print 100 random numbers
10: for (int nCount=0; nCount < 100; ++nCount)
11: {
12: cout << rand() <<“\t”;
13:
14: // If we've printed 5 numbers, start a new column
15: if ((nCount+1) % 5 == 0)
16: cout << endl;
17: }
18: }
rand()產生的偽隨機數的范圍在0到RAND_MAX之間,通常它的值在cstdlib中為32767.
通常我們并不想要這個范圍內的隨機值。我們想要兩個nLow和nHigh范圍內。如1-6.
3.
1: // Generate a random number between nLow and nHigh (inclusive)
2: unsigned int GetRandomNumber(int nLow, int nHigh)
3: {
4: return (rand() % (nHigh - nLow + 1)) + nLow;
5: }
當我們反復運行第2個程序的時候,發現每次的結果都是相同的。由于我們每次設置的seed都是相同的。因此我們使用了time()函數來產生seed。
1: #include <stdafx.h>
2: #include <iostream>
3: #include <cstdlib> // for rand() and srand()
4: #include <ctime> // for time()
5: using namespace std;
6:
7: int main()
8: {
9:
10: srand(time(0)); // set initial seed value to system clock
11: for (int nCount=0; nCount < 100; ++nCount)
12: {
13: cout << rand() << "\t";
14:
15: if ((nCount+1) % 5 == 0)
16: cout << endl;
17: }
18: }
怎樣的偽隨機生成器算是好的呢?
1)生成器會以相同的概率產生每一個數值。
2)隨機序列的下一個數字不能明顯、容易被預測
3)隨機數生成器產生的數值有一個好的分布,忽而小,忽而大,讓人感覺是隨機的。
4)所有的偽隨機生成器都是周期性的
rand()函數只是一個普通的偽隨機生成器
大多數rand()都是使用Linear Congruential Generator方法實現的。
由于RAND_MAX通常是32767,意味著如果我們想要更大的范圍就會不適合了。同時,rand()也不適合產生浮點型隨機值如0.0-1.0. 同時rand()相對于其他算法擁有一個短的周期。
可以使用Mersenne Twister,它具有更好的結果,同時使用相對簡單。
from http://www.learncpp.com/cpp-tutorial/44-type-conversion-and-casting/
類型隱式轉換
類型隱式轉換的步驟如下所示:
Long double (highest)
Double
Float
Unsigned long int
Long int
Unsigned int
Int (lowest)
最底層是int而不是short或是char,是因為char和short在求值時會被擴展為int。
隱式轉換會出現一些有趣的問題,如5u - 10。也許你會認為結果是-5.但是10為int型,發生隱式轉換成unsigned int型,因此最后結果為unsigned int型,2^32 - 5。又如float fValue = 10/4;
from http://www.learncpp.com/cpp-tutorial/38-bitwise-operators/
前面的文章在 http://www.cnblogs.com/grass-and-moon/
位操作符的由來主要是為了更充分的利用內存,如果使用bool型變量,它是一個字節大小,其中一個字節的內存中只有一個位被利用,其余的位都被浪費了。但是現在內存是充裕的,程序員發現往往將代碼表達的更加讓人理解,更加容易維護是一種更好的選擇。
因此,位操作符的使用不再像最初那么平常了,除了一些特殊的環境中,如需要巨型數據處理的科學計算,或需要超速執行的游戲中,仍然會被使用。不管怎么樣,對它有個充分的認識和理解還是必須的。
Operator | Symbol | Form | Operation |
left shift | << | x << y | all bits in x shifted left y bits |
right shift | >> | x >> y | all bits in x shifted right y bits |
bitwise NOT | ~ | ~x | all bits in x flipped |
bitwise AND | & | x & y | each bit in x AND each bit in y |
bitwise OR | | | x | y | each bit in x OR each bit in y |
bitwise XOR | ^ | x ^ y | each bit in x XOR each bit in y |
注意 當我們使用位操作符時,使用的變量類型通常是無符號整型。
為操作符的原理通常很簡單,但是要將它用活,通常是有一定難度的。