第四章 數組和指針
1、數組的維數必須用大於等於1的常量表達式定義。此常量表達式只能包含整型字面值常量、枚舉常量或者用常量表達式初始化的整型const對象。非const變量以及要到運行階段才知道其值的const變量都不能用於定義數組的維數。
2、字符數組
<span style="font-size:18px;"> char ca1[] = {'C','+','+'}; //沒有結束符,size = 3,但是用strlen測試不出正確的結果!
char ca2[] = "C++"; //自動添加了NULL結束符,size = 4
char ca3[] = {'C','+','+','\0'}; //顯式添加了NULL結束符
char ca4[6] = "Daniel"; //編譯時錯誤!</span><span style="font-size:24px;">
</span>
3、數組之間不允許直接複製和賦值。
4、數組下標的正確類型是size_t
//初始化
const size_t array_size = 10;
int ia[array_size] = {0};
for (size_t ix=0; ix != array_size ; ++ix)
ia[ix] = ix;
//複製數組
const size_t arr_size=7;
int ia1[] = {0,1,2,3,4,5,6};
int ia2[arr_size] = {0};
for (size_t iy=0; iy != arr_size; ++iy)
ia2[iy] = ia1[iy];
//習題4.7
//複製數組
const size_t arr_size=7;
int ia1[] = {0,1,2,3,4,5,6};
int ia2[arr_size] = {0};
for (size_t iy=0; iy != arr_size; ++iy)
ia2[iy] = ia1[iy];
vector<int> ivec;
for (int i=0; i != arr_size; ++i)
ivec.push_back(i);
vector<int> ivec1(ivec);
for (vector<int>::iterator iter = ivec1.begin(); iter != ivec1.end(); )
{
cout << *iter++ << endl;
}
//習題4.8
const size_t arr_size=7;
int ia1[] = {0,1,2,3,4,5,6};
int ia2[arr_size] = {0,1,2,3,4,5,7};
for (size_t iy=0; iy != arr_size; ++iy)
{
if (ia2[iy] != ia1[iy])
{
cout << "ia1 is not equal to ia2" << endl;
break;
}
}
vector<int> ivec;
for (int i=0; i != arr_size; ++i)
ivec.push_back(i);
vector<int> ivec1;
for (int j=arr_size; j != 0; --j)
ivec1.push_back(j);
if (ivec != ivec1)
{
cout << "ivec is not equal to ivec1" << endl;
}
cout << "ivec is equal to ivec1" << endl;
//習題4.9
const size_t arr_size=10;
int ia1[] = {0};
for (size_t iy=0; iy != arr_size; ++iy)
ia1[iy] = iy;
5.指針。指針說白了就是地址。C++Primer建議儘量避免使用指針和數組,但是我個人覺得,指針和數組還是必須要掌握的且今後要熟悉至精通的知識。
6.避免使用未初始化的指針。最好養成在定義時就初始化的習慣,指針也好,其他類型的變量也好。
int* pi = NULL;
7.void*指針。它能保存任何類型的指針。它支持
1.與另一個指針進行比較
2.向函數傳遞void*指針或者從函數返回void*指針
3.給另一個void*指針賦值
<span style="font-size:10px;"> //4.11
int* pi = NULL;//
string s,*sp=0;//請注意s是字符串變量,sp是指向字符串變量的指針
int i;
//double* dp = &i;//error 類型不一致
int* ip1,ip2;//ip1是指針,ip2是整型變量
const int ii=0,*p=ii;//因爲ii是const類型的變量,所以是可以這樣賦值的
string *pp=NULL;//這是一個完全正確並習慣良好的語句</span>
4.12運行一下就確定了,呵呵呵...
<span style="font-size:10px;"> //4.13
int i=42;
void* p = &i;
long *ip = &i;//類型不匹配</span>
8.指針和引用的區別。 一、引用總是指向某個對象,定義引用時沒有初始化是錯誤的。引用一經初始化,就始終指向同一個特定對象。
二、給引用賦值修改的是該引用所關聯的對象的值,而不是使引用與另一個對象關聯。
9.指向指針的指針。也即,指針本身也是可用指針指向的內存對象。
<span style="font-size:10px;"> int ival1=1024,ival2=2048;
int *ip1=&ival1,*ip2=&ival2;
ip1 = ip2;//ival1的值沒變,ip1的值變了,ip1現在指向ival2
int &ri = ival1,r2=ival2;
ri=r2;//ival1的值變了,ri依然指向ival1</span>
9.指向指針的指針。也即,指針本身也是可用指針指向的內存對象。
<span style="font-size:10px;"> int ival1=1024 ;
int *ip1=&ival1 ;
int **ppi = &ip1;
int *pi2 = *ppi;
cout <<"the value of ival1\n"
<< "direct value:" << ival1 << "\n"
<< "indirect value:" << *ip1 << "\n"
<< "doubly direct value:" << **ppi << "\n"
<< "*pi2 value:" << *pi2 << "\n"
<< endl;</span>
<span style="font-size:12px;"> //4.16
int i=2,j=1024;
int *p1=&i,*p2=&j;
*p2 = *p1 * *p2;
cout<<"the j value:"<< j << "\n"
<< "*p2 value:" << *p2 << "\n"
<<endl;
*p1 *= *p1;
cout <<"the i value:"<< i << "\n"
<< "*p1 value:" << *p1 << "\n"
<<endl;</span>
10.指向const對象的指針。
<pre name="code" class="cpp">const double *cptr = NULL;
cptr是一個指向double類型const對象的指針,const限定了cptr指針所指向的對象類型,而非cptr本身,也即cptr本身並不是const。不能使用void*指針保存const對象的地址,而必須使用const void*類型的指針保存const對象的地址。
把一個const對象的地址賦給一個普通的、非const對象的指針會導致編譯錯誤。
但允許把非const對象的地址賦給const對象的指針。
這裏有一點需要注意的是:指向const的指針(自以爲指向const的指針),即使該指針指向的不是const對象,任何企圖通過該指針修改其對象的值的行爲都會導致編譯時錯誤。
在實際程序中,指向const的指針常用作函數的形參。將形參定義爲指向const的指針,可確保傳遞給函數的實際對象在函數中不因爲形參而被修改。
11.指針和typedef。
<span style="font-size:14px;"> const pstring cstr;//cstr是什麼類型的呢?
//在理解const定義的變量時,要從右向左閱讀,
//即等價於
const pstring cstr; << == >> pstring const cstr;
//然後再將pstring代入,即
string *const cstr;//也即cstr是指向string類型對象的const指針</span>
//4.19
int i;
const int ic=0;//ic是int類型的const變量,必須要初始化
const int *pic;//pic是指向int類型const變量的指針,pic本身不是const類型,故可以不初始化,但任何想通過pic來修改其所指對象的值的行爲都是錯的
int *const cpi = NULL;//cpi是指向int類型變量的const指針,cpi本身是const類型,必須要初始化
const int *const cpic = NULL;//cpic是指向int類型const變量的const指針,cpic與其所指的對象均爲const類型,故必須初始化
//4.20
int i = -1;
const int ic=i;//ic是int類型的const變量,必須要初始化
const int *pic = //pic是指向int類型const變量的指針,pic本身不是const類型,故可以不初始化,但任何想通過pic來修改其所指對象的值的行爲都是錯的
int *const cpi = //cpi是指向int類型變量的const指針,cpi本身是const類型,必須要初始化
//error C2440: “初始化”: 無法從“const int *”轉換爲“int *const ”
//cpi是const類型的指針,必須用const類型的指針來初始化它
const int *const cpic = //cpic是指向int類型const變量的const指針,cpic與其所指的對象均爲const類型,故必須初始化
//4.21
//發現VC給的報錯已經說的很清楚了哦
i = ic;
pic =
cpi = pic;//error C2440: “=”: 無法從“const int *”轉換爲“int *const ”
pic = cpic;
cpic = //error C3892: “cpic”: 不能給常量賦值
ic = cpic;//error C2440: “=”: 無法從“const int *const ”轉換爲“const int”
//4.22
const char* cp = "hello";
int cnt=0;
// while(cp) {
// cout << "cnt is :" <<cnt << endl;
// cout << "cp is :" << cp << endl;
// cout << "*cp is :" << *cp << endl;
// ++cnt;
// ++cp;
// break;
// }//會一直運行,死循環,爲什麼呢?注意:cp是一個指針,指針也就是一個地址哦!
cnt = 0;
while(*cp) {
cout << "cnt is :" <<cnt << endl;
cout << "cp is :" << cp << endl;
cout << "*cp is :" << *cp << endl;
++cnt;
++cp;
}//這個循環能正確運行,爲什麼呢?跟字符串結尾的空字符有沒有關係呢?
第二個循環運行的結果: //4.23
const char ca[] = {'h','e','l','l','o'};//注意,結束符不是空字符!
const char *cp = ca;//這裏直接將ca賦值給cp,是因爲字符數組的名字就是字符數組的地址哦
while(*cp)
{
cout << "*cp is : " << *cp << endl;
++cp;
}//注意,結束符不是空字符帶來的安全隱患!
運行結果: //4.25
const char* str1 = "hello world";
const char* str2 = "hello My world";
int i = strcmp( str1, str2);
cout << i << endl;//i=1
char str3[] = {'h','e','l','l','o','\0'};
char str4[] = {'w','e','l','l','o','\0'};
if (str3 > str4)//這裏比較的是兩個字符數組的地址,不是比較裏面的內容
cout << "str3 > str4" << endl;
else
cout << "str3 < str4" << endl;
cout << "str3 is :" << str3 << endl;
cout << "str4 is :" << str4 << endl;
cout << "*str3 is :" << *str3 << endl;
cout << "*str4 is :" << *str4 << endl;
cout << "&str3 is :" << &str3 << endl;
cout << "&str4 is :" << &str4 << endl;
運行結果:12.動態數組
堆:每一個程序在執行時都佔用一塊可用的內存空間,用於存放動態分配的對象,此內存的稱爲程序的自由存儲區或堆
//4.27
int *pa = new int[10];
delete[] pa;
//4.28
vector<int> v_int;
int i=0;
int tmp=0;
while(i < 10)
{
cin >> tmp;
v_int.push_back(tmp);
++i;
}
int len = v_int.size();
int *p = new int[len];
for(size_t dwI=0;dwI < v_int.size();++dwI)
{
p[dwI] = v_int.at(dwI);
cout << "v_int.at(" << dwI << ") is :" << v_int.at(dwI) << endl;
}
for(i=0;i<len;++i,++p)
cout << "p[" << i << "] is :" << *p <<endl;
//4.30
//C style
const char* pc1 = "a very long string";
const char* pc2 = "it is impossible";
int len1 = strlen(pc1);
int len2 = strlen(pc2);
char* pc3 = new char[len1+len2+2];
memset(pc3,0,len1+len2+2);
strncat(pc3,pc1,len1);
strncat(pc3," ",1);
strncat(pc3,pc2,len2);
<span style="white-space:pre"> </span>strncat(pc3,"\0",1);
cout << pc3 << endl;
//string
string str1 = "a very long string";
string str2 = "it is impossible";
string str3 = str1 + " " + str2;
cout << str3 << endl;
if (NULL != pc3)
{
delete[] pc3;
pc3 = NULL;
}
13.新舊代碼兼容
1).string 與C風格字符串轉換
2).用數組初始化vector對象
//4.31
string str;
cin >> str;
int len = str.length();
const char* p = new char[len+1];
p = str.c_str();
cout << p <<endl;
//4.32
const size_t arr_size = 4;
int arr[arr_size] = {1,2,3,4};
vector<int> v_int(arr,arr+arr_size);
//4.33
int arr2[arr_size] = {0};
for (size_t i=0;i< v_int.size();++i)
{
arr2[i] = v_int.at(i);
cout << v_int.at(i) << endl;
cout << arr2[i] << endl;
}
//4.34,4.35
string str;
vector<string> v_str;
int len =0;
while(cin >> str)
{
if(str.compare("0000") == 0)
break;
v_str.push_back(str);
len += str.length();
}
char *p = new char[len+1];//把vector對象複製給一個字符數組
memset(p,0,len+1);
for (size_t i=0;i<v_str.size();++i)
{
const char* tmp = v_str.at(i).c_str();
strncat(p,tmp,v_str.at(i).length());
cout << tmp << endl;
}
strncat(p,"\0",1);
cout << "p is :" << p << endl;
char **pp = new char *[v_str.size()];//指向指針的指針,字符指針數組
memset(pp,0,v_str.size());
for (size_t i=0;i<v_str.size();++i)
{
char* newp = new char[v_str.at(i).length()];
memset(newp,0,v_str.at(i).length());
const char* tmp = v_str.at(i).c_str();
strncat(newp,tmp,v_str.at(i).length());
pp[i] = newp;
cout << "pp[" << i << "] is " << pp[i] << endl;
}
if (p != NULL)
{
delete[] p;
p = NULL;
}
// for(int dwI=0;dwI < v_str.size() ; ++ dwI)
// {
// char* tmp = NULL;
// if (pp[dwI] != NULL)
// {
// tmp = pp[dwI];
// delete[] tmp;
// tmp = NULL;
// }
// }//感覺不這樣一個一個的刪除,會有內存泄漏,但是我這個語句有錯
if (pp != NULL)
{
delete[] pp;
pp = NULL;
}