最近乙個同學在寫個銀行管理系統,然後問我怎麼從檔案搜尋帳戶,給了方法後又不懂檔案裡面的密碼怎麼與輸入的匹配。一般來說,高效的做法是用鍊錶實現。用陣列實現不是高效的方法,而且浪費空間。再者,對於賬戶類有個人資訊集合的,一般用結構體,**寫起來也方便簡單。
但是他卻用陣列來做,而且沒有用結構體。對於這種情況下如何搜尋帳戶,如何驗證密碼呢? 我嘗試了一下,發現不難解決。
解決這個問題的方法:用檔案資料的排序定位來做。
第一步:檔案資訊讀入
用fscanf 實現檔案讀出檔案資訊。
1 char a[20];
2 3 file* fp;
4 fp = fopen("test.txt","rb");
5 fscanf (fp, "%s", a);
6 fclose(fp);
fcanf讀取資料,以空格為分割點。比如對於檔案內容為「abc abc」(雙引號之內)的情況,用如下**:
fscanf (fp, "%s", a);
fscanf (fp, "%s", b);
得到字元陣列a 為abc;字元陣列b為 abc;
若檔案內容為「abcabc」(雙引號之內)的情況,即abc和abc之間沒有空格隔開,用以上**,得到的結果將是:
字元陣列a 為abcabc;字元陣列b 為亂碼。
fscanf();還有乙個特點,就是在乙個程式裡面是順序讀入的。
在此舉個例子:
txt檔案(每個資料一行)內容:
abcabc
ruby
然後執行下面的**:
複製**
int main()
複製**
得到的結果是:
字元陣列a為 abc,b為abc,c為ruby;
第二步:搜尋賬號
賬號搜尋的方法是遍歷檔案資料,找到與輸入匹配的賬號就停止搜尋。
用 while(fscanf(fp,"%s",a) > 0) 實現遍歷檔案資料。
作用是把檔案內容一行一行讀入賦值給字元陣列a,然後再與輸入的賬號進行比較。
同時使用標記 flag 判斷是否找到匹配的賬號,以便後續處理各種不同情況。
**如下:
複製**
char a[20];
char shuru[20] = ; //輸入
int flag = 0;
cout << "請輸入賬號名: ";
cin >> shuru;
file* fp;
fp = fopen("test.txt","rb");
while(fscanf(fp,"%s",a) > 0) //遍歷檔案資料}
if (flag == 0)
else
//下一步;
fclose(fp);
複製**
**中判斷資料相同用strcmp(str1,str2); 如果兩個字元陣列儲存的內容相同,則 strcmp(str1,str2)== 0
此時停止搜尋,用break;跳出迴圈。
現在舉例一下:
其中第三行為賬號,第五行為密碼。其他的為姓名,位址,年齡等其他資訊。
執行如下:
第三步:定位檔案密碼資料
如果是用結構體,當檢測到帳號的時候,再用結構體的 「.」 也就是 「點」密碼 來解決。簡單方便。但是用的不是結構體,所以只能用其他方法。隨筆開頭寫了用「排序定位」來做,如何實現?
從這個檔案資料來看,賬號與密碼分別是第三行, 第五行,中間隔了個第四行。下面另乙個帳戶也是同樣的排序。
那麼就定位到第五行,然後再進行 輸入密碼 與 檔案資料的比較。
**如下:
複製**
if (strcmp(shuru,a) == 0)
複製**
這裡面當檢測到帳號的時 flag = 1;表示找到匹配賬號。
然後用了 兩個fscanf(fp,"%s",a); 這不是**錯誤,前面提到了fscanf(); 是順序讀入,並且舉了 a,b,c三個字元陣列的例子。
這裡再說明一下為何用兩個fscanf();
第乙個fscanf();是把賬號下面的第乙個資料賦值給了 字元陣列a;
第二個fscanf();是把賬號下面的第二個資料賦值給了 字元陣列a;
由於密碼資料是賬號資料下面的第二個資料,所以必須用兩個fscanf(); 因為fscanf();為順序讀入,無法進行跳躍。
第四步:驗證密碼
定位了密碼資料,那麼就可以進行密碼驗證了。為了實現當密碼輸入錯誤時,能重新輸入,我們必須把驗證密碼這個環節寫成乙個函式,然後自身迴圈呼叫,類似遞迴的用法。
**如下:
複製**
void checkkey(char a[20])
return;
}複製**
第五步:demo執行
初步完成了這個功能,現在把完整**貼出來。
複製**
1 #include
2 #include
3 #include
4 #include
5 using namespace std;
6 7 //檢測密碼
8 void checkkey(char a[20])
9 21
22 return;
23 }
24 25 int main()
26 ;
29 30 int flag = 0;
31 32 cout << "請輸入賬號名: ";
33 cin >> shuru;
34 35 file* fp;
36 fp = fopen("test.txt","rb");
37 38 while(fscanf(fp,"%s",a) > 0)
39
49
50 }
51 if (flag == 0)
52 cout << "使用者不存在,請註冊!" << endl;
53 else
54 checkkey(a);
55 56 fclose(fp);
57 return 0;
58 }
複製**
我們來執行一下。
首先檔案資料如下:(每個帳戶的第三行為帳號,第五行為密碼)
執行結果:
第六步:bug修復
看上去好像完成了相應預期功能,但是細心觀察,不難發現乙個bug。舉例說明一下:
當檔案內容為:
可以看出,第乙個帳戶的密碼和第二個帳戶的賬號相同,都是aabbcc,此時程式執行就有錯誤,當搜尋到了aabbcc,程式就把他當成了賬號,於是出錯。
修復bug也很簡單,用一種特殊字元對賬號進行處理。比如在賬號後面追加乙個 「@」。
因此,程式要修改兩個地方
1. 帳戶註冊後把資訊寫入檔案時,在賬號後面追加乙個 「@」
2. 登入時,當輸入賬號完畢後,也給輸入的賬號後面追加乙個「@」
第乙個地方不是我們討論的範圍,我們來看看與本篇隨筆有關的要修改的第二個地方:
相關函式: strcat(str1,str2);實現把字元陣列 str2 追加到 str1 後面。
**如下:
cout << "請輸入賬號名: ";
cin >> shuru;
strcat(shuru,"@");
所以,當你登入時,輸入賬號完成按回車鍵時,程式會自動給你輸入的賬號後面追加乙個字元」@「,然後再與檔案資料進行比較。
修改後的完整**如下:
複製**
1 #include
2 #include
3 #include
4 #include
5 using namespace std;
6 7 //檢測密碼
8 void checkkey(char a[20])
9 21
22 return;
23 }
24 25 int main()
26 ;
29 30 int flag = 0;
31 32 cout << "請輸入賬號名: ";
33 cin >> shuru;
34 strcat(shuru,"@");
35 36 file* fp;
37 fp = fopen("test.txt","rb");
38 39 while(fscanf(fp,"%s",a) > 0)
40
50
51 }
52 if (flag == 0)
53 cout << "使用者不存在,請註冊!" << endl;
54
55 else
56 checkkey(a);
57 58 fclose(fp);
59 return 0;
60 }
複製**
密碼匹配成功。
總結:對於沒有用鍊錶 + 結構體的來寫帳戶登記的程式,屬於純檔案資訊處理。那麼就只能差強人意的用一些方法來解決。用的是」排序定位「的方法。
**是追求高效,簡潔的。一開始沒有用好的方法去解決,雖然也能通向羅馬,從程式的維護和更新的角度來看,是不推薦的。
用陣列和鍊錶實現棧
完成乙個棧總共需要完成以下操作 初始化入棧 出棧檢視棧頂元素 檢視棧的容量 清空棧。首先是簡單的,用陣列做的,會有越界的可能。include include typedef struct stack stack stack s 生成棧 void initstack 入棧,push void push...
用C 實現pdf檔案的完整性驗證
現在對檔案的完整性驗證,防止檔案被篡改的技術已經比較成熟,一般使用數字簽名,數字水印等,最近我在乙個專案中也遇到了防篡改的需求。該專案要求使用者將原始發票用專門的掃瞄程式掃瞄成pdf檔案,然後將該pdf檔案傳到伺服器上,在上傳的同時必須要驗證這個pdf是沒有被手工修改過的。我剛一接觸到這個需求想到的...
用JS實現簡單敏感詞過濾和表單驗證
首先完成html輸入框 10 cols 30 name id txt1 textarea button onclick btnclick 發布 button msg div body css text css msg style 事件驅動函式 function btnclick omsg.inner...