1. 程式人生 > >2018《程式設計實習》錯誤集錦

2018《程式設計實習》錯誤集錦

      由於本人在學習演算法時理論基礎與程式設計能力過於不匹配(理論基礎差,程式設計能力——沒有),經常會犯各種各樣腦殘的錯誤,寫出各種各樣醜陋的程式碼(比我還醜),故開此長更部落格,希望能幫到自己,也希望提醒大家不要犯類似錯誤,否則智商就會變成我這種水平。

        最後更新:04月05日

       1:C++ 變數名不能以數字開頭    報錯關鍵詞:expecting unqualified … (此對映非單射,即還有其他原因也會這樣報錯)

       2:凡是出現不給定保留位數的浮點數輸出要求,一律用cout,慢點就慢點。(%g的功能聽說不只是捨去無用0那麼簡單)

       3:蘋果

Apple Fun(const Apple & a) {
    	a.PrintTotal();
    	return a;//第二個數是5而不是6是因為此處返回時會二進位制複製建立一個物件之後析構,不呼叫建構函式
    }

Apple(){cout<<"construct"<<endl;nTotalNumber++;}
	~Apple(){cout<<"destruct"<<endl;nTotalNumber--;}//改一下程式碼跑一下就能看出來
construct
construct
construct
construct
4
destruct
construct
construct
5
destruct
destruct
destruct
destruct
1
destruct
destruct


4:Big and Base

Big(int n): b(n),v(n) {}
Big(const Big &a): b(a.b.k),v(a.v) {} //一個類的物件作為另一個的成員變數,務必使用列表式初始化

5:奇怪的建構函式

int main()
    {
        Sample a(5);//轉換
    //cout<<a.v<<endl;
        Sample b = a;//複製
    //cout<<b.v<<endl;
        PrintAndDouble(b);//在這裡還使用了一次複製建構函式
        Sample c = 20;//轉換
        PrintAndDouble(c);//複製
        Sample d;
        d = a;//什麼也沒呼叫,直接二進位制複製
        cout << d.v;
        return 0;
    }

6:MyString

MyString(const MyString &a){//務必深拷貝,否則會出現神祕的記憶體洩漏
	if(a.p){
		p = new char[strlen(a.p)+1];
		strcpy(p,a.p);
	}else
		p = NULL;
}
MyString &operator = (const MyString &a){//這裡也是,務必深拷貝
        if(p) delete [] p;
        if(a.p == NULL) p = NULL;
        else{
            p = new char[strlen(a.p) + 1];
            strcpy(p,a.p);
        }
 }//總而言之,出現了指標,迅速寫好深拷貝的複製建構函式以及等號的過載,別自己到草紙上猜指標都指到哪裡。我替你猜了,它們指向了遠方。
friend ostream &operator << (ostream &s, const MyString &a){
        s<<a.p;
        return s;
    }//流運算子必須記為友元函式

7:神祕的輸出

    #include <iostream>
    using namespace std;
    class A {
    public:
    	int val;

    	A(int a) {this->val = a;}
	A &GetObj(){
		return *this;
	}
	A(){this->val = 123;}
    };
    int main()
    {
    	int m,n;
    	A a;
    	cout << a.val << endl;
    	while(cin >> m >> n) {
    		a.GetObj() = m;
    		cout << a.val << endl;
    		a.GetObj() = A(n);//總結:凡是出現神祕的給一個函式賦值,通常都是返回了一個引用。(神祕啊)
    		cout << a.val<< endl;
    	}
    	return 0;
    }

8:過載加號
include <iostream> 
    using namespace std;
    class MyInt 
    { 
    	int nVal; 
    	public: 
    	MyInt( int n) { cout<<"num_construct"<<endl;nVal = n ;}
	MyInt( const MyInt &source) {cout<<"copy_construct"<<endl; this->nVal = source.nVal;}
	operator int() const{ return nVal; }
	MyInt &operator - (const int &a){
		nVal -= a;
		return *this;
	}
    }; 
    int Inc(int n) {
    	return n + 1;
    }
    int main () { 
    	int n;
    	while(cin >>n) {
    		MyInt objInt(n); 
    		objInt-2-1-3; 
    		cout << Inc(objInt);
    		cout <<","; 
    		objInt-2-1; 
    		cout << Inc(objInt) << endl;
    	}
    	return 0;
    }//過載運算子,如果想修改呼叫它的函式,同時還想連加連減,就務必返回個引用。我把原始碼改了改,就能更好地看出連加連減時的工作細節。20
-----------------------------這是加了引用的輸出---------------------------
num_construct
15,12
-----------------------------這是沒加引用的輸出---------------------------
20
num_construct
copy_construct
copy_construct
copy_construct
19,copy_construct
copy_construct
17


9:BigInt

    #include <iostream> 
    #include <cstring> 
    #include <cstdlib> 
    #include <cstdio> 
    using namespace std;
    const int MAX = 110; 
    class CHugeInt {
	public:
		int len;
		char *p;
		CHugeInt(){p=NULL;}
		CHugeInt(const char* s){
			this->len = strlen(s);
			p = new char[this->len];
			for(int i=0; i<this->len; i++){
				*(p+i) = *(s+len-i-1);
			}
			*(p+len) = '\0';//可要注意型別轉換建構函式裡已經完成了翻轉
		}
		CHugeInt(const int &n){
			char tmp[100];
			sprintf(tmp,"%d",n);
			this->len = strlen(tmp);
			p = new char[this->len];
			for(int i=0; i<this->len; i++){
				*(p+i) = tmp[len-i-1];
			}
			*(p+len) = '\0';//可要注意型別轉換建構函式裡已經完成了翻轉
		}
		CHugeInt(const CHugeInt &a){
			this->len = a.len;
			p = new char[this->len];
			for(int i=0; i<this->len; i++){
				*(p+i) = *(a.p+i);
			}
			*(p+len) = '\0';
		} 
		~CHugeInt(){
			delete []p;
			p = NULL;
		}
		int min(const CHugeInt &b){
			if(this->len < b.len) return this->len;
			else return b.len;
		}
		int max(const CHugeInt &b){
			if(this->len > b.len) return this->len;
			else return b.len;
		}
		CHugeInt operator + (const CHugeInt &a){
			int tmp[220];
			char temp[220];
			int tmpl;
			memset(tmp,0,sizeof(tmp));
			for(int i=0; i<min(a); i++){
				tmp[i] += (int) ((this->p[i]) + a.p[i] - 2 * '0'); 
				tmp[i+1] += tmp[i] / 10;
				tmp[i] = tmp[i] % 10;
			}
			if(min(a)==this->len){
				for(int i=this->len; i<a.len; i++){
					tmp[i] += (int)(a.p[i] - '0');
					tmp[i+1] += tmp[i] / 10;
					tmp[i] = tmp[i] % 10;
				}
			}else{
				for(int i=a.len; i<this->len; i++){
					tmp[i] += (int)(this->p[i] - '0');
					tmp[i+1] = tmp[i] / 10;
					tmp[i] = tmp[i] % 10;
				}
			}
			if(tmp[max(a)] == 0) tmpl = max(a);
			else tmpl = max(a) + 1;
			for(int i=0; i<tmpl; i++) temp[i] = (char)tmp[tmpl-i-1] + '0';
			temp[tmpl] = '\0';
			CHugeInt ret(temp);
			return ret;
		}
		CHugeInt &operator = (const CHugeInt &a){
			if(this->p) delete []this->p;
			this->len = a.len;
			p = new char[a.len];
			for(int i=0;i<this->len;i++) this->p[i] = a.p[i];
			*(p+len) = '\0';
			return *this;
		}
		friend ostream &operator << (ostream &s, CHugeInt a){
			char tmp[220];
			for(int i=0;i<a.len;i++)
				tmp[i] = a.p[a.len-i-1];
			tmp[a.len]='\0';//凡是後面出亂碼的都是沒加‘\0';
			s<<tmp;
			return s;
		} 
		friend CHugeInt operator + (const int &n, const CHugeInt &a){
			CHugeInt ret = CHugeInt(n) + a;
			return ret;
		} 
		CHugeInt operator + (const int &n){
			CHugeInt ret = CHugeInt(n) + *this;
			return ret;
		}
		CHugeInt &operator += (const int &n){
			CHugeInt ret = *this + n;
			*this = ret;
			return *this;
		}
		CHugeInt &operator ++ (){
			*this = *this + 1;
			return *this;
		}
		CHugeInt operator ++ (int rub){//傳回區域性變數pre時千萬不能用引用,一定要深拷貝後返回這些值,因為傳回的引用所指向的那個位置在函式執行結束後就被釋放掉了
			CHugeInt pre(*this);
			*this = *this + 1;
			return pre;
		} 
    };
    int  main() 
    { 
    	char s[210];
    	int n;

    	while (cin >> s >> n) {
    		CHugeInt a(s);
    		CHugeInt b(n);
    		cout << a + b << endl;
		cout << n + a << endl;
		cout << a + n << endl;
		b += n;
		cout  << ++ b << endl;
		cout << b++ << endl;
		cout << b << endl;
    	}
    	return 0;
    }//有一個要點:想給指標做一些變動的話,一定要注意是不是需要先清空原先指向的東西。
    //牢記指標四部曲:delete掉原來的空間,指向NULL,申請新空間,指向新空間。要注意指標被Delete之後還會指向被釋放的空間,這種指標叫野指標,在析構的時候會發生段錯誤(Segment Fault)
    //所以在delete空間之後一定要指標一定要紀律性指向NULL,不管之後要不要賦值,這是個好習慣。還有,這題的加號過載有點多,其實只要過載好物件+物件,剩下的套用一下就好了。注意一下建構函式的細節。



3月23日

手寫string類:有了前一次大整數的基礎,這次就順利很多了。

    #include <cstdlib>
    #include <iostream>
    using namespace std;
    int strlen(const char * s)
    {	int i = 0;
    	for(; s[i]; ++i);
    	return i;
    }
    void strcpy(char * d,const char * s)
    {
    	int i = 0;
    	for( i = 0; s[i]; ++i)
    		d[i] = s[i];
    	d[i] = 0;

    }
    int strcmp(const char * s1,const char * s2)
    {
    	for(int i = 0; s1[i] && s2[i] ; ++i) {
    		if( s1[i] < s2[i] )
    			return -1;
    		else if( s1[i] > s2[i])
    			return 1;
    	}
    	return 0;
    }
    void strcat(char * d,const char * s)
    {
    	int len = strlen(d);
    	strcpy(d+len,s);
    }
    class MyString
   {
    private:
    	char *p;
    	int l;
    public:
    	char *sub;
    	int lsub;
    	void init(){
    		if(l!=0) delete []p;//如果之前沒手動讓p指向什麼亂七八糟的東西,就不要呼叫這個函式。如果簡單地問p是否指向空指標,在第一次使用p時會報錯。
    		p = NULL;
    		l = 0;
    	}
    	MyString(){
    		p = NULL;
    		sub = NULL;
    		l = 0;
    		lsub = 0;
    	}
    	MyString(const char *s){
    		p = NULL;
    		sub = NULL;
    		l = 0;
    		lsub = 0;
    		this->l = strlen(s);
    		if(this->l!=0){
    			this->p = new char(this->l+1);
    			for(int i=0;i<this->l;i++) *(this->p+i) = *(s+i);
    			*(this->p+l) = '\0'; //very important
    		}
    	}
    	MyString(const MyString &a){
    		p = NULL;
    		sub = NULL;
    		l = 0;
    		lsub = 0;
    		this->l = a.l;
    		if(this->l!=0){
    			this->p = new char(this->l+1);
    			for(int i=0;i<this->l;i++) *(this->p+i) = *(a.p+i);
    			*(this->p+l) = '\0';
    		}
    	}
    	~MyString(){
    		init();
    	}
    	MyString &operator = (const MyString &a){//必須有返回值。等號的顯式表達尚待探討
    		init();
    		this->l = a.l;
    		if(this->l!=0){
    			this->p = new char(this->l+1);
    			for(int i=0;i<this->l;i++) *(this->p+i) = *(a.p+i);
    			*(this->p+l) = '\0';
    		}
    		return *this;
    	}
    	friend ostream &operator << (ostream &s, MyString &tmp){
    		if(tmp.p==NULL) s<<"";//非常重要,否則流會間斷
    		else s<<tmp.p;
    		return s;
    	}
    	friend MyString operator + (const MyString &a, const MyString &b){
    		MyString ret;
    		ret.l = a.l + b.l;
    		if(ret.l!=0) ret.p = new char(ret.l+1);
    		for(int i=0;i<a.l;i++) *(ret.p+i) = *(a.p+i);
    		for(int i=0;i<b.l;i++) *(ret.p+a.l+i) = *(b.p+i);
    		*(ret.p+ret.l) = '\0';
    		return ret;
    	}
    	char &operator [] (int idx){
    		return *(this->p+idx);
    	}
    	MyString &operator += (const MyString &a){
    		*(this) = *(this) + a;
    		return *(this);
    	}
    	friend MyString operator + (const char *s, const MyString &a){
    		MyString ret(s);
    		ret = ret + a;
    		return ret;
    	}
    	friend MyString operator + (const MyString &a, const char *s){
    		MyString ret(s);
    	    ret = a + ret;
    		return ret;
    	}
    	friend bool operator == (const MyString &a, const MyString &b){
    		int tmp = strcmp(a.p, b.p);
    		if(tmp==0) return true;
    		else return false;
    	}
    	friend bool operator < (const MyString &a, const MyString &b){
    		int tmp = strcmp(a.p, b.p);
    		if(tmp==-1) return true;
    		else return false;
    	}
    	friend bool operator > (const MyString &a, const MyString &b){
    		int tmp = strcmp(a.p, b.p);
    		if(tmp==1) return true;
    		else return false;
    	}
    	char *operator () (const int s_idx, const int s_len){//傳整數的過程是什麼樣的呢
    		if(lsub!=0){
    			lsub = 0;
    			sub = NULL;
    		}
    		lsub = s_len;
    		sub = new char(lsub+1);
    		for(int i=0;i<lsub;i++)
    			*(sub+i) = *(p+s_idx+i);
    		*(sub+lsub) = '\0';
    		return sub;
    	}
    };


    int CompareString( const void * e1, const void * e2)
    {
    	MyString * s1 = (MyString * ) e1;
    	MyString * s2 = (MyString * ) e2;
    	if( * s1 < *s2 )
    	return -1;
    	else if( *s1 == *s2)
    	return 0;
    	else if( *s1 > *s2 )
    	return 1;
    }
    int main()
    {
    	MyString s1("abcd-"),s2,s3("efgh-"),s4(s1);
    	MyString SArray[4] = {"big","me","about","take"};
    	cout << "1. " << s1 << s2 << s3<< s4<< endl;
    	s4 = s3;
        s3 = s1 + s3;
    	cout << "2. " << s1 << endl;
    	cout << "3. " << s2 << endl;
    	cout << "4. " << s3 << endl;
    	cout << "5. " << s4 << endl;
    	cout << "6. " << s1[2] << endl;
    	s2 = s1;
    	s1 = "ijkl-";
    	s1[2] = 'A' ;
    	cout << "7. " << s2 << endl;
    	cout << "8. " << s1 << endl;
    	s1 += "mnop";
    	cout << "9. " << s1 << endl;
    	s4 = "qrst-" + s2;
    	cout << "10. " << s4 << endl;
    	s1 = s2 + s4 + " uvw " + "xyz";
    	cout << "11. " << s1 << endl;
    	qsort(SArray,4,sizeof(MyString),CompareString);
    	for( int i = 0;i < 4;i ++ )
    	cout << SArray[i] << endl;
    	//s1的從下標0開始長度為4的子串
    	cout << s1(0,4) << endl;
    	//s1的從下標5開始長度為10的子串
    	cout << s1(5,10) << endl;
    	return 0;
    }

4月5日

在清明的早晨的03:22,我終於肝完了魔獸……作為War3這麼多年的老玩家,我第一次感覺到玩夠了……

沒啥說的,請移步我的獨立博文