scanf 和 cin 對string 的輸入 和坑點
寫這個源於 一道題 《1028 人口普查(20)(20 分)》
前言:在網路上 我常常會看見有人說 cin>>的效率慢 不如 scanf 。經過測試 的確是這樣子。既然cin>>輸入慢 為什麼還要用呢?拋開很多很多的問題比如:
1.cin>>可以對類似string 型別進行直接輸入。
2.cin>>可以自動轉換型別,不需要像scanf寫的那麼麻煩。
3.等等
// 實驗之前 先說下一些已知的結論 因為考慮到 可能有些人不願意看我實驗的內容,可能是因為我太水了吧。--哭~
1. string使用 scanf進行輸入是這樣輸入的:
直接string s; scanf("%s",&s[0]);
scanf("%s",s); //無法完成賦值 賦值結束後字串 s 為空
2.使用scanf給 string 直接結構體賦值後 無法傳遞給 下一 string的變數。
struct sn {
string t;
}K,P;
void solve() {
string s;
scanf("%s",&K.t[0]);
P = K;
s = K.t;
}
答案是:當K.t被正常賦值以後P.t 為空 s也為 空
造成這個原因的是 沒有加上 resize(num);這個函式 num是正整數 表示初始化string多少空間。
接下來不想講太多 我還要留一些下面講 , 不想看的 可以關掉頁面了。== (今天怎麼啦?)(不說。。~)
//
那麼問題來了 我如何使用 scanf()對string進行輸入呢?又有什麼不同的地方,適不適用 gets ?
這次主要做一個實驗:
實驗工具: VS2017 , codeblock 17,VC++6.0 不一定全部用上。因為我記得 2017裡是沒辦法使用 gets的 ,它提供了一個叫做gets_s的安全函式 一會也會進行測試。
一般情況之下 我們對 string 型別的變數賦值的時候會使用 cin>> 賦值 兩個string值之間可以 使用等於號進行賦值,這個是我們的常識:
比如:
string s,t;
cin>>s;
t = s;
那麼 string 型別的資料 在輸入後其實也可以像 char 型別的陣列一樣是一個連續的空間 那麼就是因為這個特性 才能用scanf進行輸入。那麼輸入的方法是:對空間的第一個元素所在的地址進行輸入。那麼我們早就知道對char 陣列 或是 char* 空間陣列的賦值方法是
char s1[900];
scanf("%s",s1);
scanf_s("%s",s1,sizeof(s1)); // 新版編譯器 OJ 不支援
gets(s1);
gets_s(s1,sizeof(s1)); // 新版編譯器 OJ 不支援
那麼我們推出 使用 scanf對 string 進行輸入的方法:
string s;
s.resize(10000);
scanf("%s", &s[0]);
有些人會說 s.resize(10000);這條語句我不加 也可以賦值成功啊~ 他們給我看的是這樣的情況(輸入NTSD)
賦值成功!! 但是 這是很危險的 我們使用更長的字串的時候就會賦值失敗 比如:
但是我們 啟用 resize 的話情況就會不一樣。如圖:
這樣才是正規的寫法,但是我們今天不僅研究這個。我們來看看賦值的操作吧。
直接使用等號賦值的是成功的!!!那今天的實驗到此為止麼?不是 因為賦值成功還有特例 讓它賦值不成功
我們來看 那個最特殊的 特例 讓這種方法徹底失敗。當然也是犯了一個錯誤所導致的 resize(num);
這個最特殊的特例就是 --- 結構體的整體賦值下。或是 結構體中的string賦值給區域性(全域性)變數下。
如果不加 resize(num);就會出現賦值失敗的問題。
加上就會好了:
RT
由於 VS2017上沒有 gets 那麼我們使用 vc++6.0來看一下吧!gets也是能正常的賦值的。
然後我使用子函式 在VS2017上模擬了一下 gets
int gets(char *s) {
for (char t, *p = s; t = getchar(), s!=NULL&&t != '\n'; p++, *p = 0)
*p = t;
return s != NULL ? strlen(s) : 0;
}
也能成功賦值。我覺得這個也是一個替代方案吧 畢竟擺著 cin>>不用 用這個還是很多坑點的啊!!~~
本來想上一下反彙編的~~~但是我也不精反彙編 怕說錯被笑 哈哈~~
好好學習,天天向上,加油哦~