今天是第二篇筆記了,主要記錄一下比較有意思的知識點,做不到面面兼顧。
有錯誤 請指正 謝謝
1.引言:
任何計算機語言都有一組公共的語法特徵,不通語言的主要區別在於語法特徵的實現細節。
2.基本特徵:
一般泛指內置數據類型。大多數C++語言通過兩種方式擴充語言:1是自定義數據類型2是把常用的封裝成庫提供給使用者。
3.一句老話:
C++對象類型決定了其能進行的操作。一個表達式是否合合法取決於參與其中的數據類型。如C++之類的靜態類型語言會在編譯器進行類型檢測,諸如python之類的語言是在運行期進行檢查。關於編譯和運行時期的概念按照其字面意思進行理解,大致是正確的。
4.一個例子:
i=i+j;//這個語句的具體含義取決於i和j的數據類型。i可能是一個類的對象
//也可能只是常見的內置數據類型。
5. 基本內置類型:
分爲兩類,1是算術類型(arithmetic type),2是空類型(void type)
算術類型:字符類型,布爾型,整形,浮點型。
void 類型:不對應具體的值。常見的就是函數的返回值。
6.C++幾種字符類型:
拓展字符類型,基本字符類型。
7.字節:
計算機尋址的最小內存快。通常是8位一個字節。位:bit; 字節:byte。
8.存儲的基本單位:
字(word)一般由4個或者8個字節組成。有點類似吞吐量的意思。內存中每個自己與一個地址關聯起來。可以通過地址訪問相應的自己。爲了賦予地址明確的含義,必須知道存儲的內容的數據類型。數據類型決定了數據所佔用的字節數,以及如何解釋這些自己的內容。在深度探索C++對象模型也提到類似的問題。
9.重點關注C++類型的概念。
10.符號:
無符號和帶符號類型.
除去布爾型和拓展字符型,其他整形可以劃分爲有符號型和無符號型。
有符號可以表示0,正數,負數。無符號就只能表示正數,0.
11.在相應的類型前加上unsigned 或者signed 可以得到對應的符號類型。
12.其中字符型比較特殊:
分爲三種:char ,signed char, unsigned char ,但是對外表現只 有兩種有符號型和無符號型。也就是說char 和 signed char 是不一樣的,具體的行爲是由編譯器決定的。
13.無符號類型的所有比特位都用來存儲數值。有符號類型最高位是表示正負。
如:unsigned char 類型的表示範圍:理論上爲了對稱範圍是-127到127.實際現代計算機通常是-128到127.
14.類型轉換:
從一種類型轉換爲另一相關類型。主要是相關。
unsigned char c = -1; 因爲-1字面值默認是int 的,所以會進行轉換。這個地方涉及到二進制補碼的知識,也就是計算機如何存儲負數的。
最後輸出c的值是255。關於255是如何得來的,是-1轉換後的值除以表示的最大範圍所得到的餘數。
舉個例子:
上面提到:-1的默認類型是int型的。那麼-1在計算機中如何存儲呢?是這樣搞的。
首先:最高位是1表示負數。那麼-1表示成:1000 0001 ;然而工作並沒結束。
除去最高位之外,其餘進行求反,得到反碼。即:1111 1110 ;得到反碼。
最後一步:求補碼。對反碼+1;即可以得到: 1111 1111 ;
補碼對應的10進制數字是:255 .那麼255%256=255,故上面的c值是255.
如果轉換不了,或者超出範圍就會成爲未定義行爲或者截斷成爲異常值。
unsigned char c=256.//轉不了了。
不要混用帶符號和不帶符號的類型。以0開頭的數字是八進制,0x開頭表示16進制。
15.浮點型的默認字面值是double。
整形的字面值一般是最小容納類型(不包含short)也就是說int能容納下的數字,那麼編譯器就會默認你是int了。若int放不下,會自動上調到合適的類型。
16.字符和字符串字面值:
字符串字面值實際上是由字符字面值構成的數據。編譯器會在最後一位加一個空字符('\0') 標識結束。
所以字符串的實際長度比內容多1.
字符串字面值的書寫格式:特殊的一種,當兩個相鄰字符串之只有空格,縮進,換行符構成,那麼可以分開書寫。
<span style="font-size:18px;">如cout<<"This is a sample"</span>
<<" oh ! ";
兩類不可以直接使用的字符:1是不可打印字符,如退格,換行等。2是特殊含義的字符,比如反斜線,問號等。
那麼要使用此類字符要加上反斜線。比如常見的‘\n’表示換行。
上面這些可以稱爲轉義序列。
17.泛化轉義序列:
比如你可以這樣打印字母A: \x41;不建議使用。其次就是x表示16進制。
18.通過添加前綴後綴可以指定字面值類型。
如:double db1=2L;
還有許多前綴和後綴,不一一介紹。
19.內置類型採用列表初始化的時候,不能存在截斷的風險,否則會報錯。
20.聲明和定義的區別:
int i; //定義。
extern int i ;//聲明。
extren int i=0;//定義。
任何存在初始化行爲的聲明也是定義。
21.爲什麼支持分離式編譯,所以要嚴格區分定義和聲明,多次聲明沒問題,但只能一次定義。
22.複合類型的理解:
基於其他類型定義出來的類型。比如引用和指針。
23.常量表達式:
不會改變值,在編譯期就可以計算出結果。
24.constexpr:
聲明定義常量,並且只能用常量初始化。
constexpr int i=10;
一個陷進:
const int *p=nullptr;
constexpr int *p=nullptr;
這兩個一樣嘛?不同。第一個是指向常量的指針,第二個是指針常量。
類型別名:typedef 和 using 聲明別名。
如: using money=double ;
typedef double money;
兩者表達的意思一樣。
一個陷進:
typedef char *pstring;
const pstring p;
const char* p;
兩個等價嘛?不等價。所以不要簡單替換理解。第一個const修飾的是char*整體。也就是說p是指針常量。
第二個是指向常量的指針。
對於複雜聲明,建議從右向左讀。首先找變量名。區分變量名和標識符的關係。標識符包含變量名。
26.auto 和 decltype 類型說明符。
auto 可以用表達式的類型去初始化一個auto 類型。
如 int v1=2;
int v2=3;
auto x=v1+v2; //編譯器可以推斷出x的類型。這個地方有了初始化操作,不想初始化可以使用decltype.
decltypde(v1) x; //x的類型是int .這個地方並不需要吃初始化操作。
27.頭文件衛士:
ifndef xxx
#define xxx
#include<string>
class a{};
#ennif
防止多次包含。
28.習題解答:
2.1
<span style="font-size:24px;">區別:
1.int long ,long long ,short 的區別。
最主要的區別就是所佔的字節數是不同,也等價於容納數的範圍不同。long long 最大。
2.無符號類型和有符號類型的區別:
無符合的只能表示正數,有符號的可以表示全部。
3.float 和double 的區別:
精度不同,推薦使用double。
</span>
2.2<span style="font-size:24px;">利率選用 unsigned double ;本金選用 unsigned double; 付款也應該選用 unsigned double.</span>
2.3<span style="font-size:24px;">#include <iostream>
using namespace std;
int main(){
unsigned u = 10, u2 = 42;
cout << "u2 - u = "<<u2-u <<" type is "<<typeid(u2-u).name()<< endl; //32;
cout <<"u - u2 = "<<u-u2<<" type is " <<typeid(u-u2).name()<< endl; //4294967264
int i = 10, i2 = 42;
cout << "i2 - i = "<<i2-i<<" type is "<<typeid(i2-i).name() <<endl; //32;
cout <<"i - i2 = "<<i-i2<<" type is "<<typeid(i-i2).name()<< endl; //-32;
cout << "i - u = " << i - u <<" type is "<< typeid(i - u).name() <<endl; //0
cout <<"u - i = "<<u-i<< " type is "<<typeid(u-i).name()<<endl; //0
system("pause");
return 0;
}</span>
2.4
請看2.3
2.5
<span style="font-size:24px;">//(a) 'a ; L'a' ; "a" ;L"a" 從左到右類型依次是:char ,wchar_t ,常量字符串,寬字符常量字符串。
//(b) 10 ;10u ;10L ;10uL ;012; 0xC; 依次是 int,unsigned int ,long int ,unsigned long int ,8進制 int,16進制 int。
//(c) 3.14 ;3.14f ;3.14L 依次是 double ,float, double
//(d) 10 ;10u ;10. ;10e-2; int ,unsigned int ,double ,double ,
#include <iostream>
using namespace std;
int main(){
cout << typeid(10e-2).name() << endl;//驗證方法typeid().name() 函數。
system("pause");
return 0;
}</span>
2.6<span style="font-size:24px;">有區別:
第一組: int month=9,day=7; 9和7 都是10進制整數。
第二組: int month=09,day=07; 09是什麼鬼.不是八進制也不算十進制 07 是8進制整數。
</span>
2.7<span style="font-size:24px;">#include <iostream>
using namespace std;
int main(){
cout << "Who goes with F\145rgus?\012"; //145是三個八進制數字。\12換行、
cout << typeid("Who goes with F\145rgus?\012").name() << endl;
cout << 3.14e1L<<endl; // long double
cout << typeid(3.14e1L).name() << endl;
cout << 3.14f << endl;//float
cout << typeid(3.14f).name() << endl;
cout << 3.14L << endl;
cout << typeid(3.14L).name() << endl;
system("pause");
return 0;
}</span>
2.8<span style="font-size:24px;">#include <iostream>
using namespace std;
int main(){
cout << "\062\x4D\012";
cout << "\062\x9\x4D\012";
system("pause");
return 0;
}
//全部用ASCII碼錶示的。
</span>
2.9<span style="font-size:24px;">a. 錯誤:int input_value; cin>>input_value;
b. 錯誤:int i={3.13} 存在信息丟失風險。C++Primer 定義爲錯誤,vs2013可以通過
c. 錯誤:double salary=wage=99.99; wage 未定義。
d. 正確:int i=3.13; 會有截斷。
</span>
2.10<span style="font-size:24px;">global_str empty string;
global_int 0;
local_str 未初始化
local_int 未初始化</span>
2.11<span style="font-size:24px;">extern int ix=1024 /definition
int iy //definition
extern int iz //declaration</span>
2.12<span style="font-size:24px;">(a),(c),(d)
</span>
2.13<span style="font-size:24px;">j=100</span>
2.14<span style="font-size:24px;">不合法。i只存活於循環體內。循環體外無法打印i.</span>
2.15<span style="font-size:24px;">b,d 不合法。</span>
2.16<span style="font-size:24px;">不考慮截斷問題,全部可以通過編譯。vs2013+win 7
</span>
2.17<span style="font-size:24px;">output: 10 10 ,兩個10之間有一個空格</span>
2.18<span style="font-size:24px;">#include <iostream>
using namespace std;
int main(){
int v1=3,v2=4;
const int *p = &v1; //指向常量的指針
//*p = 3; 不合法
p = nullptr; //合法
int * const ptr = &v2;//常量指針
//ptr = nullptr; 不合法
*ptr = v1; //合法
system("pause");
return 0;
}</span>
2.19<span style="font-size:24px;">區別:1.無空引用,聲明即綁定,但可以有空指針。
2.指針是對象,佔據內存的行爲,引用是變量的別名。
</span>
2.20<span style="font-size:24px;">通過指針間接修改i的值,i的值爲以前值的平方積。</span>
2.21<span style="font-size:24px;">有。類型不一致。</span>
2.22<span style="font-size:24px;">1.p指針不爲空,則執行if裏面的語句。
2.*P的值不等於0,就執行if裏面的語句。</span>
2.23<span style="font-size:24px;">根據上下文觀察吧。或者輸出*p,看看是不是垃圾值。</span>
2.24<span style="font-size:24px;">因爲 p是 void* 型的。可以存儲任何變量的地址。
而lp 的類型是long int ,同i 的類型不一致。
理論上是可以接受的,但是實際情況定義爲錯誤比較好。</span>
2.25<span style="font-size:24px;">a)ip 是指針。i 是int ,r是i的引用
b)i 是int,ip是空指針
c)ip 是指針,ip2是int 。</span>
2.26<span style="font-size:24px;">a,d不合法。const 量必須初始化並且不能改變值。</span>
2.27<span style="font-size:24px;">b,d,e,g</span>
2.28
<span style="font-size:24px;">不合法的:a,b,d,e.不合法原因因爲常量只能初始化,不能賦值。</span>
2.29
<span style="font-size:24px;">合法:a,b,c</span>
2.30<span style="font-size:24px;">頂層const: v2, 靠右的是頂層const.
底層const: p2, 靠左的是底層const.
</span>
2.31
<span style="font-size:24px;">全部合法。賦值操作時,可以忽略const.但是涉及到const作爲左值時,也就是值將被修改,那麼要關注const.
</span>
2.32
<span style="font-size:24px;">不合法:修改方案:int null=0,*p=&null;</span>
2.33
<span style="font-size:24px;">42, 42 ,42 ,報錯,報錯,42.</span>
2.34
略
2.35
<span style="font-size:24px;">j : int; k:int;p:int const *; j2: int ; k2: int .
#include <iostream>
using namespace std;
int main(){
const int i = 42;
const auto j = i;
const auto &k = i;
auto *p = &i;
const auto j2 = i, &k2 = i;
cout << typeid(k2).name(); //用typdeid函數進行驗證。
system("pause");
return 0;
}
平臺不同,可能有差異。測試平臺:vs2013+win 7
</span>
2.36
<span style="font-size:24px;">a:int ; b: int ; c: int ; d: int ;
結果:a=4,b=4,c=4,d=4;
#include <iostream>
using namespace std;
int main(){
int a = 3, b = 4;
decltype(a) c = a;
decltype((b)) d = a;
++c;
++d;
cout << "a= " << a << endl;
cout << "b= " << b << endl;
cout << "c= " << c << endl;
cout << "d= " << d << endl;
cout << "d's type is :" << typeid(d).name();
system("pause");
return 0;
}
</span>
2.37
<span style="font-size:24px;">#include <iostream>
using namespace std;
int main(){
int a = 3, b = 4;
decltype(a) c = a;
decltype(a=b) d = a;
cout << "d's type is :" << typeid(d).name();
system("pause");
return 0;
}
//由於int& 類型屬於符合類型,而且類似int, 所以編譯器可能會d 劃爲 int 型。如果你的結果是int& ,不用奇怪。
</span>
2.38
<span style="font-size:24px;">區別:auto 類型推斷時肯定要初始化;而decltype 不需要,除非必要。
關於int& 和 int ,我的編譯器不區分,所以不做測試。</span>
2.39
<span style="font-size:24px;">#include <iostream>
using namespace std;
struct Foo{ }
int main(){
system("pause");
return 0;
}
// error C2628: “Foo”後面接“int”是非法的(是否忘記了“;”?)
//error C3874 : “main”的返回類型應爲“int”而非“Foo”
//error C2440 : “return” : 無法從“int”轉換爲“Foo”</span>
2.40
<span style="font-size:24px;">#include <iostream>
using namespace std;
#include <string>
struct Foo{
string bookNo;
unsigned int units_sold; //可能一開始寫的時候注意不到無符號數的使用。
double revenue;
};
int main(){
system("pause");
return 0;
}</span>
2.41
略
2.42
<span style="font-size:24px;">#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <iostream>
#include <string>
struct Sales_data{
std::string bookNo;
unsigned int units_sold;
double revenue;
};
#endif // !SALES_DATA_H
重點是學會使用header gurd !!!最好都要加上。不建議包含命名空間,詳情見下一節。
</span>
End
爲什麼寫的這麼零碎?因爲我寫的不好,因爲書本纔是王道。我只能寫一點不常見的東西,不然無異於抄書。習題解答僅供參考,其實不用關心答案正確與否,會了就會了,不會的自己應該很清楚。