|這個作業屬於哪個課程|2024-2025-1-計算機基礎與程式設計|
|這個作業要求在哪裡|2024-2025-1計算機基礎與程式設計第一週作業|
|這個作業的目標|<複習知識,鞏固基礎>|
|作業正文|https://www.cnblogs.com/HonJo/p/18593475|
一、教材學習內容
(一)共用體
C語言中的共用體(Union)是一種特殊的資料型別,允許在相同的記憶體位置儲存不同的資料型別。這意味著一個共用體變數可以儲存多種不同型別的資料,但是一次只能儲存其中的一種。共用體的主要特點是節省記憶體空間,因為它只佔用最大的成員所需的空間。
以下是共用體的基本用法和特點:
-
定義共用體型別:
在C語言中,可以透過typedef
關鍵字定義一個新的共用體型別。例如:typedef union { int i; float f; char str[20]; } Data;
這裡定義了一個名為
Data
的共用體型別,它可以儲存一個整數(int
)、一個浮點數(float
)或一個字元陣列(char
)。 -
宣告共用體變數:
使用定義好的共用體型別來宣告變數:Data data;
-
訪問共用體成員:
可以透過點(.
)運算子來訪問共用體的成員:data.i = 10; // 儲存一個整數 data.f = 220.5; // 儲存一個浮點數 strcpy(data.str, "C Programming"); // 儲存一個字串
-
共用體成員的記憶體共享:
共用體的所有成員共享同一塊記憶體空間,因此修改一個成員會影響其他成員的值。例如:data.i = 10; // 此時記憶體中儲存的是整數10 data.f = 220.5; // 此時記憶體中儲存的是浮點數220.5,整數10被覆蓋
-
共用體的大小:
共用體的大小等於其最大成員的大小。在上面的例子中,Data
的大小將取決於int
、float
和char[20]
中最大的那個。 -
使用共用體的注意事項:
- 共用體變數在記憶體中沒有固定的偏移量,因此不能作為函式引數傳遞。
- 共用體成員的訪問方式與結構體成員的訪問方式相同,但是共用體的所有成員共享記憶體。
- 共用體可以包含指標,但是必須小心使用,因為它們指向的是共用體的記憶體位置。
共用體在需要節省記憶體或者需要將同一塊記憶體用於不同目的時非常有用,比如在嵌入式程式設計中。但是,由於其成員共享記憶體的特性,使用時必須小心,以避免資料覆蓋和不一致的問題。
(二)單向連結串列
C語言中的單向連結串列是一種動態資料結構,由一系列節點組成,每個節點包含資料部分和指向下一個節點的指標。單向連結串列的特點是節點的連結方向是單向的,即每個節點只指向下一個節點,而不知道前一個節點。這種結構在插入和刪除操作中非常靈活,但不支援反向遍歷。
以下是單向連結串列的基本組成和操作:
1. 節點定義
單向連結串列的每個節點通常包含兩個部分:資料域和指標域。資料域用於儲存資料,指標域用於儲存指向下一個節點的指標。
typedef struct Node {
int data; // 資料域,用於儲存資料
struct Node* next; // 指標域,指向下一個節點
} Node;
2. 建立節點
建立一個新的節點,通常需要為資料域賦值,並初始化指標域。
Node* createNode(int data) {
Node* newNode = (Node*)malloc(sizeof(Node)); // 分配記憶體
if (newNode == NULL) {
// 處理記憶體分配失敗
exit(1);
}
newNode->data = data; // 設定資料
newNode->next = NULL; // 初始化指標域為NULL
return newNode;
}
3. 初始化連結串列
初始化一個空連結串列,通常設定頭節點為NULL
。
Node* initList() {
return NULL; // 空連結串列的頭節點為NULL
}
4. 插入節點
在單向連結串列中插入節點通常有三種情況:在連結串列頭部插入、在連結串列尾部插入和在連結串列中間插入。
-
在頭部插入:
void insertAtHead(Node** head, int data) { Node* newNode = createNode(data); newNode->next = *head; *head = newNode; }
-
在尾部插入:
void insertAtTail(Node** head, int data) { Node* newNode = createNode(data); if (*head == NULL) { *head = newNode; } else { Node* temp = *head; while (temp->next != NULL) { temp = temp->next; } temp->next = newNode; } }
-
在中間插入(例如,插入到值為
prevData
的節點之後):void insertAfter(Node* prevNode, int data) { if (prevNode == NULL) { printf("Previous node cannot be NULL\n"); return; } Node* newNode = createNode(data); newNode->next = prevNode->next; prevNode->next = newNode; }
5. 刪除節點
刪除節點通常需要找到該節點的前一個節點,並將其next
指標指向要刪除節點的下一個節點。
void deleteNode(Node** head, int key) {
Node* temp = *head, *prev = NULL;
if (temp != NULL && temp->data == key) {
*head = temp->next;
free(temp);
return;
}
while (temp != NULL && temp->data != key) {
prev = temp;
temp = temp->next;
}
if (temp == NULL) return;
prev->next = temp->next;
free(temp);
}
6. 遍歷連結串列
遍歷單向連結串列以訪問每個節點的資料。
void printList(Node* node) {
while (node != NULL) {
printf("%d ", node->data);
node = node->next;
}
printf("\n");
}
單向連結串列的優點是插入和刪除操作靈活,不需要像陣列那樣移動元素。缺點是不支援反向遍歷,且每個節點需要額外的記憶體空間來儲存指標。單向連結串列在實現某些演算法和資料結構時非常有用,如佇列、棧(作為實現方式之一)等。
(三)檔案
在C語言中,檔案操作是一個重要的部分,允許程式讀取和寫入檔案。C語言提供了一組標準的庫函式,用於處理檔案的開啟、關閉、讀取、寫入和其他相關操作。這些函式定義在stdio.h
標頭檔案中。
1. 檔案指標
在C語言中,每個開啟的檔案都與一個檔案指標(FILE*
型別)關聯。檔案指標是一個指向FILE
結構的指標,該結構包含了檔案的狀態資訊。
2. 開啟檔案
使用fopen
函式開啟檔案,並返回一個檔案指標。
FILE *fp;
// 以只讀模式開啟檔案
fp = fopen("example.txt", "r");
// 以寫入模式開啟檔案
fp = fopen("example.txt", "w");
// 以追加模式開啟檔案
fp = fopen("example.txt", "a");
// 以讀/寫模式開啟檔案
fp = fopen("example.txt", "r+");
模式字串可以包含以下字元:
r
:只讀模式開啟檔案。w
:只寫模式開啟檔案,如果檔案存在,則截斷為零長度,如果檔案不存在,則建立新檔案。a
:追加模式開啟檔案,寫操作會在檔案末尾追加資料,如果檔案不存在,則建立新檔案。b
:二進位制模式,可以與其他模式組合使用(如rb
、wb
)。+
:更新模式,允許讀寫。
3. 讀取檔案
使用fgetc
、fgets
、fread
等函式從檔案中讀取資料。
// 讀取單個字元
char ch = fgetc(fp);
// 讀取一行
char buffer[100];
fgets(buffer, sizeof(buffer), fp);
// 讀取指定數量的元素
int items_read = fread(buffer, sizeof(char), 100, fp);
4. 寫入檔案
使用fputc
、fputs
、fwrite
等函式向檔案寫入資料。
// 寫入單個字元
fputc('A', fp);
// 寫入字串
fputs("Hello, World!", fp);
// 寫入指定數量的元素
int items_written = fwrite(buffer, sizeof(char), 100, fp);
5. 檔案定位
使用rewind
、fseek
、ftell
等函式在檔案中定位。
// 將檔案指標重置到檔案開頭
rewind(fp);
// 移動檔案指標到指定位置
fseek(fp, offset, whence);
// 獲取當前檔案指標的位置
long position = ftell(fp);
whence
引數可以是SEEK_SET
(檔案開頭)、SEEK_CUR
(當前位置)、SEEK_END
(檔案末尾)。
6. 關閉檔案
使用fclose
函式關閉檔案,並釋放資源。
fclose(fp);
7. 錯誤檢查
使用ferror
和clearerr
函式檢查和清除檔案錯誤。
if (ferror(fp)) {
// 處理錯誤
}
clearerr(fp); // 清除錯誤標誌
8. 檔案結束檢測
使用feof
函式檢查是否到達檔案末尾。
if (feof(fp)) {
// 到達檔案末尾
}
9. 臨時檔案
使用tmpfile
建立臨時檔案,該檔案在關閉時會自動刪除。
FILE *temp = tmpfile();
10. 二進位制檔案操作
C語言中的檔案操作函式也可以用於二進位制檔案,只需在模式字串中新增b
字元。
檔案操作是C語言中處理資料持久化的基本方式,掌握這些操作對於編寫能夠讀寫檔案的程式至關重要。
二、教材學習中的問題
(一)結構體和共用體的區別
共用體(Union)和結構體(Structure)在C語言中都是複合資料型別,但它們之間存在幾個關鍵的區別:
-
記憶體分配:
- 結構體:結構體的每個成員都佔用自己的記憶體空間。因此,結構體的大小是其所有成員大小之和加上可能的填充(padding)。
- 共用體:共用體的所有成員共享同一塊記憶體空間。共用體的大小等於其最大成員的大小,而不是所有成員大小之和。
-
成員訪問:
- 結構體:結構體的成員可以獨立訪問,互不影響。
- 共用體:共用體的成員共享記憶體,因此訪問一個成員會影響其他成員的值。在任何時候只能有效訪問一個成員。
-
使用目的:
- 結構體:結構體用於需要儲存多個不同型別資料項的情況,這些資料項之間沒有共享記憶體的需求。
- 共用體:共用體用於節省記憶體,適用於需要在相同記憶體位置儲存不同型別的資料,但一次只能使用其中一種型別。
-
初始化:
- 結構體:結構體可以被初始化為一個特定的值集合。
- 共用體:共用體只能初始化其第一個成員,或者在宣告時指定某個特定成員的值。
-
陣列和指標:
- 結構體:可以建立結構體陣列和指向結構體的指標,這在處理大量結構體資料時非常有用。
- 共用體:雖然也可以建立共用體陣列和指標,但由於記憶體共享的特性,使用時需要更加小心。
-
記憶體對齊:
- 結構體:編譯器可能會在結構體中新增填充位元組(padding)以滿足記憶體對齊要求,這可能會導致結構體的實際佔用空間大於成員大小之和。
- 共用體:由於所有成員共享記憶體,共用體不受記憶體對齊的影響,其大小僅取決於最大成員的大小。
-
函式引數:
- 結構體:結構體可以作為函式引數傳遞,通常透過值或引用。
- 共用體:由於共用體的記憶體共享特性,它通常不作為函式引數傳遞,因為引數傳遞可能會破壞記憶體中的資料。
-
可移植性:
- 結構體:結構體的佈局(layout)在不同編譯器或不同平臺上是可移植的,只要成員的型別和順序相同。
- 共用體:共用體的佈局可能在不同的編譯器或平臺上有所不同,因為它們依賴於特定的記憶體佈局規則。
總的來說,結構體和共用體在C語言中扮演著不同的角色,選擇使用哪一個取決於具體的應用場景和需求。結構體提供了一種安全的方式來儲存和訪問不同型別的資料,而共用體則提供了一種節省記憶體的方式來儲存不同的資料型別,但需要程式設計師小心管理記憶體訪問。
三、基於AI的學習