第一章

hisun9發表於2024-11-06

借鑑github上一位大佬的

1.1 節練習

練習 1.1

在Linux終端裡面:

首先利用vim編輯器寫一個test.cpp檔案

內容如下:

img

透過g++ -o test test.cpp生成了一個可執行檔案test

img

img

在UNIX和Windows系統中,執行完一個程式後,都可以透過echo命令獲得其返回值。

在UNIX系統中(Linux其實是類UNIX系統,也適用),透過如下命令獲得狀態:

echo $?

img

發現返回值為1,這肯定不正常。

然後這樣做了:

img

明確指定檔案位置,用一個“.”後跟一個斜線來指出可執行檔案位於當前目錄中。

發現返回0,這表明程式沒有遇到任何錯誤,並且成功執行完畢。

補充:

在Windows系統中,執行完一個程式後,透過echo %errorlevel%命令獲得其返回值。

補充(自己按照書上實驗了一下):

如果省略了-o test,在UNIX系統中編譯器會生成一個名為a.out的可執行檔案。

img

真的自動生成了一個可執行檔案a.out

img

然後執行這個檔案,發現返回值為0,這表明程式沒有遇到任何錯誤,並且成功執行完畢。

img

練習 1.2

改寫test.cpp檔案

img

img

居然返回255

換了a.out試了下,發現也是返回255,然後問了gpt

附上gpt的回答:

在Linux系統中,程式的返回值實際上是透過程序的退出狀態碼來傳遞的。C++程式的return語句返回的值會被轉換成一個8位無符號整數,並且在程序退出時,這個返回值會被傳遞給作業系統。

具體來說,Linux中的程序退出狀態碼由兩部分組成:

- 退出狀態(exit status):這是程式的返回值,範圍是0-255。

- 訊號狀態(signal status):如果程式是由於某個訊號而終止的,訊號會影響退出狀態。

當你的程式返回-1時,它會被轉換為255,這是因為-1在轉換為無符號整數時的值是255。

然後在Windows系統下試了一下:

test.cpp內容如下:

img

在visual studio自帶的編輯器執行,發現返回值為-1。

img

1.2 節練習

練習 1.3

img

透過使用作用域運算子(::)來指出我們想使用定義在名稱空間std中的名字cout

endl是一個被稱為操縱符(manipulator)的特殊值。寫入endl的效果是結束當前行,並將與裝置關聯的緩衝區(buffer)中的內容刷到裝置中。

練習 1.4

img

練習 1.5

img

練習 1.6

不合法

img

改成:

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內容如下:

img

img

1.3 節練習

練習 1.7

img

練習 1.8

img

補充:

發現第一個warning警告: [Warning] command line option '-std=c99' is valid for C/ObjC but not for C++

如何去除?

原先這樣:
img

改成這樣:

img

即指定-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;	
}

img

練習 1.10

#include <iostream>

int main()
{
	int i = 11;
	while (i)
	{
		i --;
		std::cout << i << ' ';
	}
	
	std::cout << std::endl;
	return 0;
}

img

也可:

#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; 
}

img

記得要先判斷輸入的兩個數之間的大小,避免迴圈出不來(死迴圈)的情況。

也看到了一種值得學習的寫法:

#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;
}

img

雖然對於這個程式碼,當輸入的第一個數大於輸入的第二個數時,不能實現由第一個輸入的數從大到小列印至輸入的第二個數(即逆序輸出),但是這個程式碼結構還是值得學習的。

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;
}

img

img

補充:

  • 當我們使用一個istream物件作為條件時,其效果是檢測流的狀態。

    如果流是有效的,即流未遇到錯誤,那麼檢測成功。

    當遇到檔案結束符(end-ofFfile),或遇到一個無效輸入時,istream物件的狀態會變為無效。處於無效狀態的istream物件會使條件變為假。

  • 檔案結束符

    當從鍵盤向程式輸入資料時,對於如何指出檔案結束,不同作業系統有不同的約定。

    在Windows系統中,輸入檔案結束符的方法是敲Ctrl+Z(按住Ctrl鍵的同時按Z鍵), 然後按Enter或Retum鍵。

    在UNIX系統中,包括MacOSX系統中,檔案結束符輸入是用Ctrl+D。

1.4.4 節練習

img

img

img

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;
}

img

練習 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;
}

img

其中compareIsbn函式是在Sales_item.h檔案中定義的,如下:

img

練習 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;
}

img

img

這個程式和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;
}

輸出如下:

img

補充

這裡我用了檔案重定向(因為不想重複輸入銷售記錄)

詳細的請看這篇部落格:對C++程式使用輸入輸出重定向

練習 1.24

在練習 1.23演示過了

練習 1.25

前面差不多了