C++語法入門刷題筆記(三)
1.scanf()函式
scanf()函式接收輸入資料時,遇以下情況結束一個數據的輸入:
① 遇空格、“回車”、“跳格”鍵。
② 遇寬度結束。
③ 遇非法輸入。
cin遇到空格或者回車也會結束讀取!!!
scanf接收包含空格的字串
#include <stdio.h>
int main()
{
char str[80];
scanf("%s",str);
printf("%s",str);
return 0;
}
輸入:I love you!
輸出:I
原因:scanf遇空格結束讀取。
2.ASCII碼
每個常用字元都對應一個-128~127的數字,二者之間可以相互轉化。
ASCII碼 | 字元 |
---|---|
48 | ‘0’ |
65 | ‘A’ |
97 | ‘a’ |
3.字元陣列
3.1
字串就是字元陣列加上結束符’\0’。沒有’\0’不算字串,只是普通的字元陣列。
可以使用字串來初始化字元陣列,但此時要注意,每個字串結尾會暗含一個’\0’字元,因此字元陣列的長度至少要比字串的長度多1!
這裡第二、三種初始化方式是等價的。
3.2
char s[100]; cin >> s + 1; cout << s + 1 << endl; cout << s[1] << endl; // 輸入:abc /* 輸出: abc a */ // 這樣就可以讓讀取的字串的陣列從1開始 // 使用scanf函式有同樣的效果,scanf("%s",s + 1)
3.3
3.3.1
讀入一行字串(包括空格),可以使用gets函式,但由於它不安全,已經被淘汰。
3.3.2
現在使用fgets函式
char s[100];
fgets(s,100,stdin);
原型 char * fgets(char * s, int n,FILE *stream);
引數:
s: 字元型指標,指向儲存讀入資料的緩衝區的地址。
n: 從流中讀入n-1個字元
stream : 指向讀取的流。
返回值:
- 當n<=0 時返回NULL,即空指標。
- 當n=1 時,返回空串””。
- 如果讀入成功,則返回緩衝區的地址。
- 如果讀入錯誤或遇到檔案結尾(EOF),則返回NULL。
3.3.3
在用fgets(..)讀入資料時,先定義一個字元陣列或字元指標,如果定義了字元指標 ,那麼一定要初始化。
example:
char s[100]; //可以。
char *s; //不可以,因為只是聲明瞭一個指標。但並沒有為它分配記憶體緩衝區。
所以,如果要用指標,則 char *s=(char*)malloc(100*sizeof(char));
為其分配記憶體空間,c++中用char *s=new char [100];
如果未分配記憶體空間,編譯時不會檢查出問題,但執行時會出現未知錯誤。。
3.3.4
fgets(…)讀入文字行時的兩種情況。
1. 如果n大於一行的字串長度,那麼當讀到字串末尾的換行符時,fgets(..)會返回。並且在s的最後插入字串結束標誌’\0’。 而s緩衝區剩餘的位置不會再填充。
example:
123abc
fgets(s,10,fp);
此時,讀入七個字元,123abc\n,實際上還有最後的’\0’,所以,strlen(s)=7; 如果要去除末尾的\n,s[strlen(s)-1]=’\0’;便可。
2. 如果n小於等於一行的字串的長度,那麼讀入n-1個字元,此時並沒有讀入\n因為並沒有到行尾 ,同樣在最後會插入’\0’.
example:
123abc
char s[5];
fgets(s,5,fp);
這時讀入4個字元,123a,並沒有換行符,所以strlen(s)=4.
3.4
用getline函式來讀取字串中的空格。(定義在標頭檔案中)
getline 函式如下所示:
getline(cin, inputLine);
其中 cin 是正在讀取的輸入流,而 inputLine 是接收輸入字串的 string 變數的名稱。
注意:第二個引數不能是字元陣列,必須是string變數!!它將繼續讀取,直到它讀取至最大指定的字元數,或直到按下了回車鍵。
string name;
string city;
cout << "Please enter your name: ";
getline(cin, name);
cout << "Enter the city you live in: ";
getline(cin, city);// 上一次使用者輸入的'\n'被去除了,沒有讀入city
cout << "Hello, " << name << endl;
cout << "You live in " << city << endl;
// 輸出如下
Please enter your name: John Doe
Enter the city you live in: Chicago
Hello, John Doe
You live in Chicago
補充:getline()中讀入結束的回車後,結束符不放入快取區,會將讀入的\n直接去除,下一個輸入前,緩衝區為空,並不會因為回車留下\n。而cin的結束後,以及getchar()此類的讀入結束後,按下回車或者使用空格讀入下一個,此時按下的回車或空格會還在快取區,繼續用getline()就會出現前面所提到的情況。
scanf函式並不會清空緩衝區回車!!
// 用scanf過濾空格
char str[30],c;
scanf("%s",s);
scanf("\n%c",&c);
3.5
cin.getline函式。
與 getline 一樣,cin.getline 允許讀取包含空格的字串。它將繼續讀取,直到它讀取至最大指定的字元數,或直到按下了回車鍵。
char s[100];
cin.getline(s,100);// 最多讀取99個字元,最後一個位置放'\0'
3.6
puts函式。(引入)
char name[] = "asaf";
printf("%s\n",name);
puts(name);// 兩者是完全等價的
4.字元陣列常用操作
下面幾個函式需要引入標頭檔案:
#include <string.h>
或者也可以
(1) strlen(str),求字串的長度,注意:不包括最後的’\0’
// 自己實現程式碼
char s[100];
scanf("%s",s);
int len = 0;
for (int i = 0;s[i];i++) len++;// 用s[i]作為判斷條件,因為'\0'代表停止
cout << len << endl;
(2) strcmp(a, b),比較兩個字串的大小,a < b 返回-1,a == b 返回0,a > b返回1。這裡的比較方式是字典序!
(3) strcpy(a, b),將字串b複製給從a開始的字元陣列。
5.acwing772.只出現一次的字元
#include <iostream>
// 巧妙的做法
using namespace std;
int main()
{
string str;cin >> str;
int s[300] = {0};
for (char &c : str) s[c]++;// 遍歷string
char p = -1;
for (char &c: str)// 注意這裡還是遍歷str,不是s
// 因為題目要求第一個出現的滿足要求的字元
{
if (s[c] == 1) {p = c;break;}
}
if (p == -1) cout << "no";
else
{
cout << p;
}
return 0;
}
6.acwing763.迴圈相剋令
// 原解法,太過低效,直接暴力列舉
// y總題解
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;// 這行程式碼最後緊跟著include
int get(string s)
{
if (s == "Hunter") return 0;
if (s == "Bear") return 1;
else return 2;
}
int main()
{
int n;cin >> n;
while (n--)
{
string a,b;
cin >> a >> b;
int x = get(a),y = get(b);
if (x == y) puts("Tie");
else if ((y+1)%3 == x) puts("Player1");
else puts("Player2");
}
return 0;
}
// 巧妙的解題思路,利用字母的長度之差,讀題能力實在佩服
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
string x, y;
while (n --)
{
cin >> x >> y;
int a = x.size(), b = y.size();
if (a - b == -1 || a - b == -2 || a - b == 3)
cout << "Player1" << endl;
else if (a == b)
cout << "Tie" << endl;
else cout << "Player2" << endl;
}
return 0;
}
7.acwing765.字串加空格
給定一個字串,在字串的每個字元之間都加一個空格。
輸出修改後的新字串。
輸入格式
共一行,包含一個字串。注意字串中可能包含空格。
輸出格式
輸出增加空格後的字串。
資料範圍
1≤字串長度≤100
樣例
輸入樣例:
test case
輸出樣例:
t e s t c a s e
// 遍歷字串的非常巧妙的做法
#include<iostream>
using namespace std;
int main()
{
string a;
getline(cin, a);
for(char &c : a) cout << c << ' '; // 遍歷字串
}
8.acwing773.字串插入
有兩個不包含空白字元的字串str和substr,str的字元個數不超過10,substr的字元個數為3(字元個數不包括字串結尾處的’\0’。)
將substr插入到str中ASCII碼最大的那個字元後面,若有多個最大則只考慮第一個。
輸入格式
輸入包括若干行,每一行為一組測試資料,格式為
str substr
輸出格式
對於每一組測試資料,輸出插入之後的字串。
輸入樣例:
abcab eee
12343 555
輸出樣例:
abceeeab
12345553
關於substr的說明:
-
用途:一種構造string的方法
-
形式:s.substr(pos, n)
-
解釋:返回一個string,包含s中從pos開始的n個字元的拷貝(pos的預設值是0,n的預設值是s.size() - pos,即不加引數會預設拷貝整個s)
當只有一個數字pos表示從下標為pos開始一直到結尾 -
補充:若pos的值超過了string的大小,則substr函式會丟擲一個out_of_range異常;若pos+n的值超過了string的大小,則substr會調整n的值,只拷貝到string的末尾
string s = "0123456789";
cout << s.substr(0,3) << endl << s.substr(3) << endl;
// 第一個引數代表下標,第二個引數代表長度(可以不加)
/* 輸出如下
012
3456789
*/
// 原解法TLE了,超時,寫錯了
// y總題解
#include <iostream>
using namespace std;
int main()
{
string a,b;
while (cin >> a >> b)
{
int p = 0;
for (int i = 1;i < a.size();i++)
{
if (a[i] > a[p]) p = i;
}
cout << a.substr(0,p + 1) + b + a.substr(p + 1) << endl;
}
return 0;
}
// 題解2
#include <bits/stdc++.h>
using namespace std;
int main()
{
char str[11], substr[4];
int n = 2;
while(scanf("%s %s", str, substr) != EOF){
int cnt = str[0], res = 0;
for(int i = 0; i < strlen(str); i++){
if(str[i] > cnt) cnt = str[i], res = i;
else if(str[i] == cnt) continue;
}
for(int i = 0; i <= res; i ++){
cout<< str[i];
}
for(int i = 0; i < strlen(substr); i++){
cout<< substr[i];
}
for(int i = res + 1; i < strlen(str); i++){
cout<< str[i];
}
puts("");
}
return 0;
}