C++Primer筆記3(第四章-數組和指針)

第四章  數組和指針


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.指針和引用的區別。
          一、引用總是指向某個對象,定義引用時沒有初始化是錯誤的。引用一經初始化,就始終指向同一個特定對象。
         二、給引用賦值修改的是該引用所關聯的對象的值,而不是使引用與另一個對象關聯。
<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;
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章