基本知識
程序 = 算法 + 數據結構,算法是對操作的描述,數據結構是對數據的描述。
僞代碼:pseudo code
程序一般包括:
(1)預處理命令:#include等
(2)全局聲明部分
(3)函數:函數首部(聲明)、函數體(局部聲明+執行部分)
程序執行過程
源程序-->編譯成目標程序obj-->連接目標程序成可執行文件
類:數據成員+成員函數
命名空間
實際上就是一個由程序設計者命名的內存區域。程序員可以根據需要指定一些有名字的空間域,把一些全局實體分別放在各個命名空間中,從而與其它全局實體分隔開,解決名字衝突,防止全局命名空間污染。
C++庫的所有標識符(標準頭文件中函數、類、對象、類模版)都是在std命名空間定義的
A 的ASCII碼值65 a 的97
1.數據類型
- 基本類型:整型、浮點型、字符型、布爾型
- 構造類型:枚舉、數組、結構體類型(struct)、公用體(union)、類類型
- 指針類型
- 引用類型
- 空類型:null
int 4 unsigned int 4 short int 2 unsigned short int 2 long int 4 unsigned long int 4
char 1 uchar 1
float 4 double 8 long double 8
無符號:不用保存符號位,故比有符號多了一位
有符號:數值用補碼存放(無論正負),最高位爲符號位
VC中,long double與double字節數相同,故long double是無用的
GCC中,long double則有12個字節
無負值的量可以定義爲unsigned int,如年齡、學號等,以增大存儲範圍。
short int,long int,unsigned int這些類型後面的int可以省略
整型表示:
十進制,後面加L 或 l
八進制,前面加0
十六進制,前面加0x
浮點數表示:
默認爲雙精度型double
後面加 f 或 F 則爲單精度float
後面加 l 或 L 則爲長精度型long double
指數形式
數符 數字部分 指數部分
a = 3.14e2 a=0.314e4 a=31.4e1 a=3140e-1
浮點數,不管是用小數形式還是指數形式表示,在內存中都是以指數形式表示的,且數字部分必須小於1
如3.14159 在內存中表示爲 + .314159 3 ,數字部分爲.314159,是小於1的
字符型
字符型在內存中存儲的是ASCII碼,也是整型,故而可以把字符型賦給整型
字符串後面,編譯系統會加個'\0'作爲結束符
符號常量
用符號代表一個常量,如#define PI 3.14159
在編譯時,系統會把符號常量替換成具體的值
2.變量
變量:程序運行期間,值可變的量
變量名:代表內存中的一個存儲單元,在編譯連接時由系統給每一個變量分配一個地址
標識符:標識實體名字的有效字符序列,字母、數字、下劃線
常變量:定義變量時加上const,運行期間值不可變,也即只讀變量
區別#define 定義的符號常量與const定義的常變量
符號常量只是用一個符號代表一個常量,在編譯時把所有符號常量替換爲指定的值,它沒有類型,在內存中不存在以符號常量命名的存儲單元
常變量具有變量的特徵,具有類型,在內存中有以它命名的存儲單元,與一般變量不同的是,常變量代表的存儲單元值不可變。
強定義的好處
1.保證變量名使用的正確,不正確會在編譯時報錯
2.每個變量指定爲一確定類型,在編譯時就能爲其分配存儲單元
3.編譯時即可檢查變量進行的運算是否合法。
3. 運算符
二進制位運算
& 二進制 按位與
| 二進制按位或
^ 按位異或
<< 左移位
>> 右移位++ -- 自加自減運算符
++i 使用i之前,i先自加
i++ 使用i之後,i再自加
++ -- 結合方向爲自右向左
例:
!x++ 先取非,再++
(i++)+6 先i+6,後i++,不管有無括號,都是先運算,再自加
(++i)+6 先自加,再加6
-i++ :i左面是符號運算符,右面是自加運算符,設i等於3,運算過程相當於 -(i++),即 -i=-3 -3+1=-2
a = -i++:a結果爲-3,先賦值,再自加;
5-i++ =? 答案2 ?待測試
i=1,j=2,則a = i+++j ? 答案:3 因爲相當於a=(i++)+j;
i=1,j=2,則a=i+(++j)? 答案:4
賦值運算符=的優先級小於++ -- 運算符
示例:
int arr[] = {6,7,8,9,10};
sint *ptr = arr;
*(ptr++) += 123;
printf("%d,%d",*ptr,*(++ptr));
解:
*(ptr++) += 123; 相當於 *ptr +=123; *ptr++; 故arr[0] = 129; ptr指向arr[1]
printf函數從右向左壓棧,運算順序:++ptr; 輸出結果: 8 8
cout也是自右向左壓棧。
逗號運算符
又稱順序求值運算符
a = 3*4,a*5 則 a=? 答案 12 ? 注意逗號運算符優先級最低。注:整個逗號表達式的值爲60(a=3*4=12,12*5 =60)
x=(a=3,6*3) 則 x=18
x=a=3,6*a 則 x=3
3.內存存儲
浮點數在內存裏和整數存儲方式不同
float a =1.0f;
cout<<(int)a==(int&a);(int&a) 相當於把該浮點數地址開始的sizeof(int)個字節當成int型數據輸出,其值並不爲1
(int)a顯示轉換等於1
4.類型轉換
轉換本質:按存儲單元中的存儲形式直接傳送
(1)浮點型賦給整型,捨棄小數部分
(2)double型賦給float,防止溢出錯誤
(3)int, short, long賦給char,原封不動取低八位
(4)signed賦給unsigned,符號位照搬。負數以補碼形式存放,-1賦給unsigned int,結果爲65536.整數不會變,除非兩個長度不同(int,long)發生截斷
5.C++輸入輸出
C++輸入輸出包含三個方面的內容
(1)對系統指定的標準設備的輸入輸出。即從鍵盤輸入、輸出到顯示器屏幕,稱標準輸入輸出,簡稱標準I/O
(2)以外出磁盤文件爲對象進行輸入輸出,稱文件I/O
(3)對內存中指定空間進行輸入輸出,通常指定一個字符數組作爲存儲空間,稱字符串輸入輸出,簡稱串I/O
在C++中,輸入輸出流被定義爲類。C++的I/O庫中的類稱爲流類,用流類定義的對象稱流對象。
C++中輸入輸出是調用輸入輸出流庫中的流對象cin、cout實現的,即I/O不是C++本身定義的,而是編譯系統的I/O庫中定義的。
I/O控制符#include <iomanip>
setprecision(n) 設置精度爲n,
十進制輸出時,n代表有效數字位數包括整數和小數;
fixed(固定小數位數)和scientific(指數)形式輸出時,n指小數位數(不包括整數部分)
double a = 123.4567890123456
cout << a; //十進制輸出,輸出123.456 默認精度爲6
cout<<setprecision(9)<<a; //十進制,輸出123.456789 精度爲9
cout<<setprecision(6); //恢復默認精度
cout<<setioflags(ios::fixed)<<a; //固定位數,123.456789 ,此時精度表示小數位數,精度爲默認的6
6.getchar() 和 putchar()
cout<<getchar(); //讀入的實際是ASCII碼,故輸出爲字符ASCII碼,97,而非讀入的字符
cout<<(c=getchar()); //輸出爲字符
while((c=getchar())!='\n'){} //循環讀入字符的控制
7.函數與模版
函數原型:不同具體形參的函數聲明
如:float add(float,float)
主要作用:根據函數原型,在程序編譯階段對調用函數的合法性進行全面檢查。
函數重載:同一函數名定義的多個函數,這些函數的參數個數,參數類型,參數順序至少有一項不同,一個函數不能既是重載函數,又是帶默認參數的函數。
函數模版:適用於函數個數相同,函數體相同,而只有類型不同的情況
#include <iostream>
using namespace std;
template <typename T> // template <class T>
T max(T a, T b, T c)
{
if(b>a) a = b;
if(c>a) a = c;
return a;
}
int main()
{
int a=1,b=2,c=3;
cout<<T(a,b,c);
float d=1.1,e=2.2,f=3.3;
cout<< T(d,e,f);
}
變量作用域:變量有效範圍,有四種:
文件作用域 file scope 函數作用域 function scope
塊作用域 block scope 函數原型作用域 function prototype scope
遞歸函數:函數體中,直接或間接調用函數本身的函數。
變量的存儲類別:外部、局部(相對於函數而言)
全局變量(也即外部變量)
靜態局部變量(static)
自動變量(不加static的局部變量)
寄存器變量(register) 存放在CPU中,而非內存中,這樣在使用時就省去了從內存中載入寄存器的過程。但只是建議性的,優化編譯系統自動識別使用頻繁的變量,從而自動將變量放入寄存器中。
extern聲明的外部變量
即提前引用申明,表示該變量是將在下面定義的全局變量或在其它文件中定義(本文件中不用extern,引用該變量的外部文件用extern進行聲明)
static聲明的靜態外部變量
只能被本文件使用,而不能被外部文件使用的全局變量,這樣不同文件中的全局變量不會相互干擾,爲程序模塊化、通用化提供方便。
注:全局變量也是靜態存儲的。
內部函數與外部函數
內部函數:static 聲明,文件內使用
外部函數:另一個文件裏extern聲明,表示是其它文件的函數,extern可以省略
宏定義
#define PI 3.14 定義符號常量
#define Area(a,b) a*b //定義函數功能,下面當作函數來用。
#include <iostream> 'iostream' 區別
<> 在系統目錄尋找,找不到報錯
' ' 在當前目錄尋找,找不到報錯
字符數組
(1) char str[] = "i am happy";
數組長度爲11,而非10,因爲後面有一個'\0'
(2) char str[] = {'i','a','m','h','y'}
數組長度爲5,系統不會自動爲其在後面加'\0'
因此,(1),(2)是不同的
輸出字符數組:cout<<str;
string類
字符數組是C中的處理方式,C++中用string類,#include <string>
字符串變量中不會存放'\0',只存放字符串本身,故string str ="hello"; 的長度爲5,要注意。
字符串變量存儲的實際是字符串的指針,4個字節,
sizeof(string) = 4;
string name[]={"i","am","happy"}; sizeof(name) = 3*4 = 12;
變量與指針:
int *p = &i; //int型指針變量,定義時的*只是表示指針類型
p是指針變量,其值是變量i的地址,*p則是存儲單元,*&a與*p同,都表示變量a
指向數組的指針
int a[10] = {};
int *p;
p = &a[0]; //與下面等價,都指向數組第一個元素,因爲數組名本身就是表示數組的地址
p = a;
*************************
*p++ 相當於*(p++),先得到*p的值,p再++移到下一個元素
(*p)++則是使*p的值+1
二維數組的指針表示: *(*(p+i)+j) 表示 a[i,j]
*************************
int (*p)[n] p爲指向含n個元素的數組的指針
int *p[n] 定義指針數組P
函數指針 指向函數的指針,主要用作形參
int max(int,int);
int (*p)(int,int);
p = max; 賦值(地址)
p(1,2) //調用
引用
int a = 10;
int &b = a; b是對a的引用
引用傳遞,引用型變量作爲函數形參
//值會改變
main{
int i=5,j=6;
swap(i,j)
}
void swap(int &a, int &b) //這裏的&不是“a的地址”,而是指“a是一個引用型變量”,&是個聲明符
{
int temp;
temp = a;
a= b;
b=temp;
}
傳遞變量地址:形參是指針變量,實參是變量地址,這種虛實結合的方法仍然是“值傳遞”方式,只是實參的值是變量地址而已。//值會改變
main()
{
int i=5,j=6;
swap(&i,&j)
}
void swap(int *p1, int *p2) //這裏的*號也只表示是指針類型
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
結構體變量 struct
作函數參數時有三種形式
(1)用結構體變量名作形參
這時形參要開闢內存單元,實參中全部內容通過值傳遞方式一一傳遞給形參,時空開銷大,效率低
(2)用指向結構體變量的指針作形參,只有四個字節
void printed(student *p)
{
cout<<p->num;
}
(3)用結構體變量的引用變量作形參
Student stu;
print(stu);
void print(Student &stu)
{
cout<stu.num;
}
new delete 動態內存分配
new 類型(初值),返回地址,分配失敗返回NULL
float *f = new float(3.14);
int *i = new int(6);
int *k = new int[5][4]; //數組
delete 變量 delete f; delete i;
數組 delete [] k;
Enum 枚舉類型
聲明枚舉類型 enum weekday{sun,mon,tue,wed,thu,fri,sat};
定義枚舉變量 weekday workday,week_end;
變量賦值: workday = mon; 或 workday = weekday(2);
枚舉常量對應值從0開始,0,1,2,3..
typedef 聲明新類型
typedef int INTEGER ,相當於爲int起了個別名,下面程序中就可以直接用INTEGER作int用了
主要爲了方便系統移植,如long int在VC中4個字節,在GCC中佔8個字節,直接用int的話可能會溢出,用INTEGER就不用擔心了,只要把ypedef int INTEGER 聲明語句一改就行
運算符重載
方法是定義一個重載運算符的函數,在需要執行被重載的運算符時,系統就自動調用該函數,以實現響應運算。即運算符重載是通過定義函數實現的,運算符重載實際上是函數重載。
格式:
函數類型 operator 運算符名稱 (形參表列)
{對運算符的重載處理}
例如:將 + 用於Complex類(複數)的加法運算,函數原型如下:
Complex operator + (Complex& c1, Complex& c2);
注:operator 是關鍵字, operator + 就是函數名,可以描述爲: 函數operator +重載了運算符+
整數加可以想象爲調用如下函數
int operator + (int a,int b)
{ return a+b; }
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(){real=0;imag=0;}
Complex(double r, double r){real=r;imag=i;}
Complex operator + (Complex &c2); //聲明重載運算符的函數
void display();
private:
double rea;
double imag;
};
Complex Complex::operator + (Complex &c2) //定義重載運算符的函數
{
Complex c;
c.real = real + c2.real;
c.imag = imag + c2.imag;
return c;
}
void Complex::display()
{
cout<<real<<imag;
}
int main()
{
Complex c1(3,4), c2(5,-10),c3;
c3 = c1 +c2; //運算符+ 用於複數運算
cout<<"c1=";c1.display;
cout<<"c2=";c2.display;
cout<<"c1+c2=";c3.display;
return 0;
}
運行結果:
c1 = (3,4i)
c2 = (5,-10i)
c1+c2 = (8,-6i)
重載運算符的規則(1)C++不允許用戶自己定義新的運算符,只能對已有的C++運算符進行重載。
(2)C++允許重載絕大部分的運算符
(3)重載不能改變運算符運算對象的個數
(4)重載不能改變運算符的優先級別
(5)重載不能改變運算符的結合性
(6)重載運算符的函數不能有默認的參數
(7)重載的運算符必須和用戶定義的自定義類型的對象一起使用,其參數至少一個是類對象(或類對象的引用)。也就是說參數不能全部是C++的標準類型,以防止用戶修改用於標準類型數據的運算符的性質。
(8)用於類對象的運算符一般必須重載,但有兩個例外,運算符“=”和“&”不必用戶重載
(9)應當使重載運算符的功能類似於該運算符作用於標準類型數據時所實現的功能,否則不易使人理解程序
(10)運算符重載函數可以是類的成員函數,也可以是類的友元函數,還是計費成員函數也非友元函數的普通函數。