前端學習C語言 - 數組和位元組序

来源:https://www.cnblogs.com/pengjiali/archive/2023/06/16/17485725.html
-Advertisement-
Play Games

## 數組 本篇主要介紹:`一維二維數組`、`字元數組`、`數組名和初始化註意點`以及`位元組序`。 ### 一維數組 #### 初始化 有以下幾種方式對數組初始化: ```c // 定義一個有5個元素的數組,未初始化 int a[5]; // 定義一個有5個元素的數組,將第一個初始化0,後面幾個元素 ...


數組

本篇主要介紹:一維二維數組字元數組數組名和初始化註意點以及位元組序

一維數組

初始化

有以下幾種方式對數組初始化:

// 定義一個有5個元素的數組,未初始化
int a[5];

// 定義一個有5個元素的數組,將第一個初始化0,後面幾個元素預設初始化為0
int a[5] = {0};

// 定義一個有5個元素的數組,5個元素都初始化為:2,3,4,5,6
int a[5] = {2, 3, 4, 5, 6};

// 【推薦】
// 和上一種在功能上是相同的。編譯器會根據初始化列表中的元素個數(5個)自動確定數組a的大小為5
int a[] = {2,3,4,5,6};

Tip:以上寫法創建的數組都是不可變大小的

練習1

題目int a[5] = {1},請問 a 的每個值是多少?

#include <stdio.h>
int main() {
    // 將第一個初始化1,後面幾個元素預設初始化為0
    int a[5] = {1};
    int i;
    for (i = 0; i < 5; i++) {
        printf("%d ", a[i]);
    }
    return 0;
}

輸出:1 0 0 0 0

在C和C++中,當我們創建數組時,如果沒有為數組的所有元素提供初始值,那麼剩下未被初始化指定初始值的元素會被預設初始化。對於基本數據類型(如int、float、double等),預設情況下,未初始化的元素將被設置為0

練習2

題目:如果不對 a[5] 進行初始化,將輸出什麼?

#include <stdio.h>
int main() {
 -  int a[5] = {1};
 +  int a[5];
    int i;
    for (i = 0; i < 5; i++) {
        printf("%d\n", a[i]);
    }
    return 0;
}

輸出隨機數:

開始運行...

4198784
0
4198464
0
-2014700240

運行結束。
練習3

題目:如果將int a[5]; 提到全局作用於中,輸出什麼?

#include <stdio.h>
int a[5];
int main() {
    int i;
    for(i =  0; i <  5; i++){
         printf("%d ", a[i]);
     }
    return  0;
}

輸出: 0 0 0 0 0

練習4

題目:這段代碼有什麼錯誤?

#include <stdio.h>

int main() {
    int i = 10;
    int a[i] = {0};

    return 0;
}

運行:

開始運行...

# 不允許初始化可變大小的對象。即 i 是可變的。
/workspace/CProject-test/main.c:5:11: error: variable-sized object may not be initialized
    int a[i] = {0};
          ^
1 error generated.

運行結束。

結論:數組長度不能是變數。

如果換成 #define 常量 還有問題嗎?

#include <stdio.h>
#define i 10
int main() {
    // int i = 10;
    int a[i] = {0};
    return 0;
}

如果換成 #define 常量就正常,前面我們知道 #define 是文本替換

數組名

題目:定義一個數組a,請問 a&a[0]&a的含義是什麼?

#include <stdio.h>

int  main() {
    int a[5] ={1};

    printf("%p\n", a); 
    printf("%p\n", &a[0]);
    printf("%p\n", &a);
  
    printf("-----\n");

    printf("%p\n", a +  1);
    printf("%p\n", &a[0] +  1);
    printf("%p\n", &a +  1);
    return  0;
}

運行:

開始運行...

0x7ffdfb131f00
0x7ffdfb131f00
0x7ffdfb131f00
-----
0x7ffdfb131f04
0x7ffdfb131f04
0x7ffdfb131f14

運行結束。

Tip: printf 中的 %p 列印的就是記憶體地址。記憶體地址通常以十六進位形式表示。

上半部分都是輸出的都是 0x7ffdfb131f00

但下半部分加1後,結果明顯不同。其中:

  • 0x7ffdfb131f04 - 0x7ffdfb131f00 = 0x4,轉為十進位是4,一個 int 就是4個位元組
  • 0x7ffdfb131f14 - 0x7ffdfb131f00 = 0x14,轉為十進位數是20,剛好是數組 a 的位元組數(5*4)

結論:

  • a - 數組名。表示首元素的地址,加 1 是加一個元素(比如這裡4個位元組)
  • &a[0] - 表示首元素地址,加 1 是加一個元素(比如這裡4個位元組)
  • &a - 表示整個數組。加1相當於跨越了整個數組

冒泡排序

之前我們寫過冒泡排序的例子,我們將該示例用 C 語言重寫如下(函數部分後文會講):

#include <stdio.h>
  
void bubbleSort(int arr[], int n) {
    // 比較輪數,每輪都會將一個值冒泡到正確的位置
    for (int i = 0; i < n; i++) {             // 第i輪冒泡
        for (int j = 0; j < n - i - 1; j++) { // 第i輪冒泡需要比較n-i-1次
            // 出界則為 false,不會交換
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
  
int main() {
    int arr[] = {4, 3, 2, 1};
    // 計算數組長度。sizeof(arr) - 返回數據類型或變數所占記憶體大小(位元組);arr[0] - 一個元素的位元組數。
    int length = sizeof(arr) / sizeof(arr[0]);
    bubbleSort(arr, length);
    // 輸出
    for (int i = 0; i < length; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}
// Output: 1 2 3 4

位元組序

位元組序(Byte Order)是指在存儲和表示多位元組數據時,位元組的順序排列方式。

思考這樣一個問題

int a[5] 有5個元素,每個元素4個位元組,在記憶體中是一塊連續的空間。表示如下:

索引 a[0] a[1] a[2] a[3] a[4]
地址 0x100 0x104 0x108 0x10C 0x110

我們可以將a[0]稱作低地址a[4]稱作高地址。a數組中每個元素的四個位元組,最左側位元組稱作低地址,最右側位元組稱作高地址。就像這樣:

低地址     高地址
________ ________ ________ ________

數組 a 中每個元素中是一個整數,比如 a[0] = 1,在記憶體中是4個位元組,共32位,其二進位表示為:00000000 00000000 00000000 00000001。最左側是高位元組,最右側是低位元組,就像這樣:

高位元組     低位元組
00000000 00000000 00000000 00000001

請問 1 的高位元組(00000000)放在低地址還是高地址?

大端序和小端序

不同的電腦架構和處理器採用不同的位元組序(Byte Order)。常見的位元組序有兩種:

  • 大端序(Big Endian),低位元組對應高地址,高位元組對應低地址。1 對應 00000000  00000000  00000000  00000001
  • 小端序(Little Endian),低位元組對應低地址,高位元組對應高地址。1 對應 00000001  00000000  00000000  00000000
低地址     高地址
大端序 00000000 00000000 00000000 00000001
小端序 00000001 00000000 00000000 00000000

Tip: 不同位元組序的選擇涉及到如何組織和解釋二進位數據。位元組序的重要性體現在跨平臺數據交互和網路通信上。如果兩個設備使用不同的位元組序,就需要進行適當的數據轉換才能正確解讀和處理數據

二維數組

可以理解成一維數組中每個元素又是一個一維數組。例如 a[3][4] 就像這樣:

0 1 2 3
0 行
1 行
2 行

a[0]a[1]a[2],每一行就是一個一維數組。

初始化

有多種方式進行二維數組的初始化,效果也不盡相同。請看示例:

  • int a[3][4]; 未初始化,數組 a 中都是隨機值。請看示例:
#include <stdio.h>
  
int main() {
    int a[3][4];
  
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", a[i][j]);
        }
        printf("\n");
    }
  
    return 0;
}

輸出:

開始運行...

-1833069321 32764 4198917 0 
0 0 0 0 
4198848 0 4198464 0 

運行結束。
  • 部分初始化。示例如下:
// 輸出:1 2 3 4 5 6 7 8 9 10 11 12
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
  
// 輸出:1 0 0 0 5 6 0 0 0 0 0 0
int a[3][4] = {{1}, {5, 6}};
  • 全部初始化。示例如下:
// 輸出:1 2 3 4 5 6 7 8 9 10 11 12
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};

// 0 0 0 0 0 0 0 0 0 0 0 0 
// 此種寫法不能保證所有編譯器
int a[3][4] = {}
  • 行數可以省略。以下兩行代碼等效:
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
  
// 省略行。類似一維數組中省略元素個數。
int a[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};

數組名

題目:定義一個二維數組a,請問 &a[0][0]a&a[0]&a的含義是什麼?

#include <stdio.h>
  
int main() {
    int a[3][4];
  
    printf("%p\n", &a[0][0]); 
    printf("%p\n", a); 
    printf("%p\n", a[0]); 
    printf("%p\n", &a); 
  
    printf("-----\n");
  
    printf("%p\n", &a[0][0] + 1);
    printf("%p\n", a + 1);
    printf("%p\n", a[0] + 1);
    printf("%p\n", &a + 1);
  
    return 0;
}

輸出:

開始運行...

0x7fffadc7d310
0x7fffadc7d310
0x7fffadc7d310
0x7fffadc7d310
-----
0x7fffadc7d314
0x7fffadc7d320
0x7fffadc7d314
0x7fffadc7d340

運行結束。

上半部分都是輸出的都是 0x7fffadc7d310

下半部分每個加1,差異就顯現出來。

0x7fffadc7d314 - 0x7fffadc7d310 = 0x4,轉為十進位是4個位元組
&a[0][0] + 1

0x7fffadc7d320 - 0x7fffadc7d310 = 0x10,轉為十進位是16個位元組,每個元素是4個位元組,也就是4(16/4)個元素,表示一行
a + 1

0x7fffadc7d314 - 0x7fffadc7d310 = 0x4,轉為十進位是4個位元組
a[0] + 1

0x7fffadc7d340 - 0x7fffadc7d310 = 0x30,轉為十進位是48個位元組,每個元素是4個位元組,也就是 12(48/4)個元素,表示整個數組
&a + 1

結論:

  • &a[0][0] - 首行首元素地址,加 1 是加一個元素(比如這裡4個位元組)
  • a - 地址名,表示首行地址,加 1 就是加一行
  • a[0] - 首行首元素地址,加 1 是加一個元素(比如這裡4個位元組)
  • &a - 表示整個數組。加1相當於跨越了一個數組
練習

題目:數組 a[3][4],哪個不能表示a[1][1]的地址?

A、a[1] + 1
B、&a[1][1]
C、(*(a + 1)) + 1
D、a + 5

答案:D。

分析:根據上文學習,我們知道 A和B能表示,其中D是加5行,肯定錯。C由於沒學指針,暫時不管。

字元數組

在 C 語言中,字元串可以用字元數組來表示,即用一個數組來保存一串字元,每個字元用一個位元組來存儲,末尾有一個特殊的空字元 '\0' 來表示字元串的結束。

#include <stdio.h>
  
int main() {
    char str[] = {'h', 'e', 'l', 'l', 'o', '\0'};
    printf("%s", str);
  
    return 0;
}

在字元數組的初始化末尾一定要添加空字元 '\0'(筆者使用的線上編輯器沒報錯),否則在使用字元串函數處理字元串時,可能會出現意外的錯誤。也可以將上面的代碼簡化為以下形式:

char str[] = "hello";

這樣就可以不用手動添加空字元了,編譯器會自動為字元串添加結尾的空字元。

練習

題目:在輸入的字元串中,在指定位置插入指定字元

實現:

#include <stdio.h>
// string.h 是 C 語言中的頭文件,用於提供一些字元串處理操作的函數和巨集定義
#include <string.h>
  
void insertChar(char str[], int pos, char ch) {
    // 獲取字元串的長度
    int len = strlen(str);
  
    // 檢查插入位置是否有效
    if (pos < 0 || pos > len)
        return;
  
    // 將指定位置後的字元往後移動一位
    for (int i = len; i >= pos; i--) {
        str[i + 1] = str[i];
    }
  
    // 在指定位置插入字元
    str[pos] = ch;
}
  
int main() {
    char str[100];
    int pos;
    char ch;
  
    printf("請輸入字元串。例如 hello world:\n");
    scanf("%[^\n]", str);
    printf("請輸入要插入的位置:");
    scanf("%d", &pos);
    printf("請輸入要插入的字元:");
    scanf(" %c", &ch);
  
    insertChar(str, pos, ch);
  
    printf("\n修改後的字元串:%s\n", str);
  
    return 0;
}

運行:

開始運行...

請輸入字元串。例如 hello world:
a-b-c d e-f-g
請輸入要插入的位置:4
請輸入要插入的字元:x

修改後的字元串:a-b-xc d e-f-g

運行結束。
作者:彭加李
出處:https://www.cnblogs.com/pengjiali/p/17485725.html
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • > 最近項目中使用到了 lua,因為之前沒怎麼接觸過,特此記錄下自己在學習過程中疑惑的地方。 在使用`lua` 進行編碼的過程中,我們經常會使用到`.`和`:`,但是對於剛開始接觸`lua`的我來說,對這兩者的使用還是感到時常感到疑惑,接下來我們一起看看幾個例子,來感受兩者的區別。如果發現文中錯誤的 ...
  • # Go Redis 管道和事務之 go-redis ## [Go Redis 管道和事務官方文檔介紹](https://redis.uptrace.dev/zh/guide/go-redis-pipelines.html) Redis pipelines(管道) 允許一次性發送多個命令來提高性能, ...
  • 本篇博客的內容為RabbitMQ在開發過程中的快速上手使用,側重於代碼部分,幾乎沒有相關概念的介紹,相關概念請參考以下csdn博客,兩篇都是我找的精華帖,供大家學習。本篇博客也持續更新~~~ ...
  • 上篇文章講解了requests模塊的基礎使用,其中有get、put、post等多種請求方式,使用data、json等格式做為請求參數,在請求體中添加請求頭部信息的常見信息,如:headers、cookies,以及對請求響應的處理方法。接下來講解一下requests的高級用法。 ...
  • ## 前言 在C語言中,指針是一項重要的概念,它允許我們直接訪問和操作記憶體地址。 可以說,指針是C語言一大優勢。用得好,你寫程式如同趙子龍百萬軍中取上將首級;用得不好,則各種問題層出不窮,有種雙拳難敵四手的感覺。 本文將介紹指針的基礎知識,包括指針的定義、初始化、訪問和運算。 ## 一、人物簡介 - ...
  • Python中什麼是配置文件,配置文件如何使用,有哪些支持的配置文件等內容,話不多說,讓我們一起看看吧~ ## 1 什麼是配置文件? 配置文件是用於配置電腦程式的參數和初始化設置的文件,如果沒有這些配置程式可能無法運行或是影響運行(運行速度、便捷性等),使用配置文件的好處在於,部分內容以及環境運行 ...
  • 最近組裡安排了新內網,又要配環境。 眾所周知,內網安裝python庫需要先到www.pypi.org找到對應版本的包,然後再下載whl文件,上傳到內網,再用`pip install "文件地址"`去安裝。 這樣就會出現一個問題,鬼知道這個包需要的前置依賴是什麼,pip會自動檢查前置依賴,然後自動從源 ...
  • # Servlet重要類及其方法的應用 ## Servlet重要類及其方法的應用 ### 1.1 HttpServlet的一些方法介紹 ```java // this.getInitParameter();得到初始化參數 // this.getServletConfig();得到servlet配置就 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...