借鑑github上一位大佬的
1.1 節練習
練習 1.1
在Linux終端裡面:
首先利用vim編輯器寫一個test.cpp檔案
內容如下:
透過g++ -o test test.cpp
生成了一個可執行檔案test
。
在UNIX和Windows系統中,執行完一個程式後,都可以透過echo
命令獲得其返回值。
在UNIX系統中(Linux其實是類UNIX系統,也適用),透過如下命令獲得狀態:
echo $?
發現返回值為1,這肯定不正常。
然後這樣做了:
明確指定檔案位置,用一個“.”後跟一個斜線來指出可執行檔案位於當前目錄中。
發現返回0,這表明程式沒有遇到任何錯誤,並且成功執行完畢。
補充:
在Windows系統中,執行完一個程式後,透過echo %errorlevel%
命令獲得其返回值。
補充(自己按照書上實驗了一下):
如果省略了-o test
,在UNIX系統中編譯器會生成一個名為a.out
的可執行檔案。
真的自動生成了一個可執行檔案a.out
。
然後執行這個檔案,發現返回值為0,這表明程式沒有遇到任何錯誤,並且成功執行完畢。
練習 1.2
改寫test.cpp
檔案
居然返回255
換了a.out
試了下,發現也是返回255,然後問了gpt
附上gpt的回答:
在Linux系統中,程式的返回值實際上是透過程序的退出狀態碼來傳遞的。C++程式的return語句返回的值會被轉換成一個8位無符號整數,並且在程序退出時,這個返回值會被傳遞給作業系統。
具體來說,Linux中的程序退出狀態碼由兩部分組成:
- 退出狀態(exit status):這是程式的返回值,範圍是0-255。
- 訊號狀態(signal status):如果程式是由於某個訊號而終止的,訊號會影響退出狀態。
當你的程式返回-1時,它會被轉換為255,這是因為-1在轉換為無符號整數時的值是255。
然後在Windows系統下試了一下:
test.cpp
內容如下:
在visual studio自帶的編輯器執行,發現返回值為-1。
1.2 節練習
練習 1.3
透過使用作用域運算子(::)來指出我們想使用定義在名稱空間std
中的名字cout
。
endl
是一個被稱為操縱符(manipulator)的特殊值。寫入endl
的效果是結束當前行,並將與裝置關聯的緩衝區(buffer)中的內容刷到裝置中。
練習 1.4
練習 1.5
練習 1.6
不合法
改成:
std::cout << "The sum of " << v1
<< " and " << v2
<< " is " << v1 + v2 << std::endl;
或者改成:
std::cout << "The sum of " << v1;
std::cout << " and " << v2;
std::cout << " is " << v1 + v2 << std::endl;
補充:
在Linux環境下也試了下:
demo.cpp
內容如下:
1.3 節練習
練習 1.7
練習 1.8
補充:
發現第一個warning警告: [Warning] command line option '-std=c99' is valid for C/ObjC but not for C++
如何去除?
原先這樣:
改成這樣:
即指定-std=c++0x
引數來開啟對C++11的支援,或者使用-std=c++11
引數來開啟對C++11的支援。
chatgpt是這樣介紹的:
C++0x是C++11標準的一個早期名稱。在C++標準化過程中,C++11最初被稱為C++0x,因為它的最終版本在2011年之前尚未釋出。這個標準引入了許多新特性,如自動型別推導、範圍for迴圈、智慧指標等,極大增強了C++的功能和易用性。
C++11是C++標準的正式名稱,包含了C++0x的所有特性。C++0x是一個過渡名稱,表示當時尚未正式釋出的標準。C++11引入了許多新特性,如:
自動型別推導(auto)
範圍for迴圈
智慧指標(std::unique_ptr和std::shared_ptr)
執行緒支援
lambda表示式
因此,C++0x和C++11指的是同一個標準,但C++11是其正式名稱。
1.4.1 節練習
練習 1.9
#include <iostream>
int main()
{
int sum = 0;
int i = 50;
while (i <= 100)
{
sum += i;
i ++;
}
std::cout << sum << std::endl;
return 0;
}
練習 1.10
#include <iostream>
int main()
{
int i = 11;
while (i)
{
i --;
std::cout << i << ' ';
}
std::cout << std::endl;
return 0;
}
也可:
#include <iostream>
int main()
{
int i = 10;
while (i >= 0) {
std::cout << i << " ";
i--;
}
std::cout << std::endl;
return 0;
}
練習 1.11
#include <iostream>
int main()
{
std::cout << "請輸入兩個數";
std::cout << std::endl;
int v1, v2;
std::cin >> v1 >> v2;
if (v1 > v2) // 由大至小列印
while (v1 >= v2) {
std::cout << v1 << " ";
v1--;
}
else // 由小至大列印
while (v1 <= v2) {
std::cout << v1 << " ";
v1++;
}
std::cout << std::endl;
return 0;
}
記得要先判斷輸入的兩個數之間的大小,避免迴圈出不來(死迴圈)的情況。
也看到了一種值得學習的寫法:
#include <iostream>
void print_range(int lo, int hi)
{
if (lo > hi)
{
print_range(hi, lo);
return;
}
while (lo <= hi)
{
std::cout << lo << std::endl;
++lo;
}
}
int main()
{
int low, high;
std::cout << "please input two numbers : " << std::endl;
std::cin >> low >> high;
print_range(low, high);
return 0;
}
雖然對於這個程式碼,當輸入的第一個數大於輸入的第二個數時,不能實現由第一個輸入的數從大到小列印至輸入的第二個數(即逆序輸出),但是這個程式碼結構還是值得學習的。
1.4.2 節練習
練習 1.12
此迴圈將 −100 到 100 之間(包含 −100 和 100)的整數相加(即從 -100 加到 100 ),sum 的終值是 0。
練習 1.13
比較簡單,不贅敘了
練習 1.14
在StackOverflow有類似的問題
蠻有意思的,可以看下
練習 1.15
不贅敘
1.4.3 節練習
練習 1.16
#include <iostream>
int main()
{
int sum = 0, value = 0;
while (std::cin >> value)
{
sum += value;
}
std::cout << sum << std::endl;
return 0;
}
補充:
-
當我們使用一個
istream物件
作為條件時,其效果是檢測流的狀態。如果流是有效的,即流未遇到錯誤,那麼檢測成功。
當遇到檔案結束符(end-ofFfile),或遇到一個無效輸入時,
istream物件
的狀態會變為無效。處於無效狀態的istream物件會使條件變為假。 -
檔案結束符
當從鍵盤向程式輸入資料時,對於如何指出檔案結束,不同作業系統有不同的約定。
在Windows系統中,輸入檔案結束符的方法是敲Ctrl+Z(按住Ctrl鍵的同時按Z鍵), 然後按Enter或Retum鍵。
在UNIX系統中,包括MacOSX系統中,檔案結束符輸入是用Ctrl+D。
1.4.4 節練習
1.5.1 節練習
練習 1.20
#include <iostream>
#include "Sales_item.h"
int main()
{
Sales_item book;
std::cout << "請輸入銷售記錄:"
<< std::endl;
while (std::cin >> book) {
std::cout << "ISBN、售出本數、銷售額和平均售價為 "
<< book << std::endl;
}
return 0;
}
練習 1.21
#include <iostream>
#include "Sales_item.h"
int main()
{
Sales_item trans1, trans2;
std::cout << "請輸入兩條 ISBN 相同的銷售記錄:"
<< std::endl;
std::cin >> trans1 >> trans2;
if (compareIsbn(trans1, trans2))
std::cout << "彙總資訊:ISBN、售出本數、銷售額和平均售價為 "
<< trans1 + trans2 << std::endl;
else
std::cout << "兩條銷售記錄的 ISBN 不同" << std::endl;
return 0;
}
其中compareIsbn
函式是在Sales_item.h
檔案中定義的,如下:
練習 1.22
#include <iostream>
#include "Sales_item.h"
int main()
{
Sales_item total, trans;
std::cout << "請輸入幾條 ISBN 相同的銷售記錄:"
<< std::endl;
if (std::cin >> total) {
while (std::cin >> trans)
if (compareIsbn(total, trans)) // ISBN 相同
total = total + trans;
else { // ISBN 不同
std::cout << "ISBN 不同" << std::endl;
return -1;
}
std::cout << "彙總資訊:ISBN、售出本數、銷售額和平均售價為 "
<< total << std::endl;
}
else {
std::cout << "沒有資料" << std::endl;
return -1;
}
return 0;
}
這個程式和1.4.4 節練習中的程式巧妙處有點像,但是又不完全一樣
看了一位大佬寫的:
#include <iostream>
#include "Sales_item.h"
int main()
{
Sales_item currItem, valItem;
if (std::cin >> currItem)
{
int cnt = 1;
while (std::cin >> valItem)
{
if (valItem.isbn() == currItem.isbn())
{
++cnt;
}
else
{
std::cout << currItem << " occurs " << cnt << " times " << std::endl;
currItem = valItem;
cnt = 1;
}
}
std::cout << currItem << " occurs " << cnt << " times " << std::endl;
}
return 0;
}
這個程式和1.4.4 節練習中的程式就基本一樣了
練習 1.23
#include <iostream>
#include <cstdio>
#include "Sales_item.h"
int main()
{
FILE* file = nullptr;
errno_t err = freopen_s(&file, "input.txt", "r", stdin);
if (err != 0) {
std::cerr << "Failed to redirect input." << std::endl;
return 1;
}
Sales_item trans1, trans2;
int num = 1;
std::cout << "若干銷售記錄在input.txt裡,已檔案重定向到輸入:" << std::endl;
if (std::cin >> trans1)
{
while (std::cin >> trans2)
if (compareIsbn(trans1, trans2)) // ISBN相同
num++;
else
{
//ISBN不同
std::cout << trans1.isbn() << " 共有 "
<< num << " 條銷售記錄" << std::endl;
trans1 = trans2;
num = 1;
}
std::cout << trans1.isbn() << " 共有 "
<< num << " 條銷售記錄" << std::endl;
}
else
{
std::cout << "沒有資料" << std::endl;
return -1;
}
return 0;
}
輸出如下:
補充
這裡我用了檔案重定向(因為不想重複輸入銷售記錄)
詳細的請看這篇部落格:對C++程式使用輸入輸出重定向
練習 1.24
在練習 1.23演示過了
練習 1.25
前面差不多了