2018《程式設計實習》錯誤集錦
阿新 • • 發佈:2018-11-25
由於本人在學習演算法時理論基礎與程式設計能力過於不匹配(理論基礎差,程式設計能力——沒有),經常會犯各種各樣腦殘的錯誤,寫出各種各樣醜陋的程式碼(比我還醜),故開此長更部落格,希望能幫到自己,也希望提醒大家不要犯類似錯誤,否則智商就會變成我這種水平。
最後更新: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這麼多年的老玩家,我第一次感覺到玩夠了……
沒啥說的,請移步我的獨立博文