多此一舉?定義只有一個數組成員的C語言結構體有什麼用?

2021-01-15 IT劉小虎

在C語言程序開發中,有經驗的程式設計師有時會定義只有一個數組成員的結構體,雖然語法簡單,但是卻常常讓初學者感到迷惑:這麼做有什麼好處嗎?

struct ABC {

unsigned long array[MAX];

} abc;

這麼做有什麼好處嗎?

答案是肯定的,這樣做主要有兩個好處:一是便於值傳遞,二是便於後期擴展。

方便的數組值傳遞

看過我之前文章的讀者應該明白,調用C語言函數時,如果將數組作為參數傳遞給函數,那麼在被調用函數內部,數組常常會退化成指針。下面是一段C語言代碼示例:

#include <stdio.h>

void fun(char arr[16]){

printf("sizeof arr is %d\n", (int)sizeof(arr));

}

int main(){

char a[16] = {0};

fun(a);

return 0;

}

C語言代碼示例

編譯並執行上述C語言代碼,得到如下輸出:

# gcc t.c

# ./a.out

sizeof arr is 8

可見,在函數 fun() 內部,sizeof(arr) 並不等於數組長度 16,而是等於 8(指針長度,我的機器是 64 位的,指針佔用內存空間為 8 個字節),這說明即使函數 fun() 的參數C語言代碼明確指定為 fun(char arr[16]),在函數內部,arr 還是退化成指針了。

而如果將數組封裝在結構體內部,將結構體作為參數,那麼在函數內部,我們依然可以獲得完整的數組,請看下面的C語言代碼示例:

#include <stdio.h>

typedef struct{

char arr[16];

}String;

void fun(String *str){

printf("sizeof arr is %d\n", (int)sizeof(str->arr));

}

int main(){

String s;

fun(&s);

return 0;

}

將結構體作為參數

編譯並執行上述C語言代碼,得到如下輸出:

# gcc t.c

# ./a.out

sizeof arr is 16

一切與預期一致。上面的C語言代碼有意將結構體 typedef 為 String,因為它的行為很像用於描述字符串的「新類型」。讀者應該明白,C語言中的數組是不支持直接賦值的:

char a[16], b[16];

...

a = b; // 非法

但是藉助於C語言的結構體語法,String 類型是可以直接賦值的,這使得編寫代碼方便不少:

String a, b = {1,2,3,4,5};

a = b; // 合法

printf("%d %d %d %d %d\n",

a.arr[0], a.arr[1],

a.arr[2], a.arr[3], a.arr[4]);

// 輸出 1 2 3 4 5

方便後續擴展

方便後續擴展

C語言中的結構體可用於將一些基本類型的數據封裝成一個具有內在聯繫的數據結構,而且結構體並不限制自身成員的數目和佔用內存空間的大小,這樣的特性使得在C語言項目後續開發中添加數據方便不少。

例如,可能剛開始 fun() 方法需要完成的需求比較簡單,可能它只需要接收一個數組就可以:

void fun(char arr[]);

char a[16];

...

fun(a);

隨著項目的繼續推進,我們發現 fun() 函數不僅需要數組 arr 的地址,還需要知道 arr 中究竟有多少有用的數據,因此需要對 fun() 函數做如下修改:

void fun(char arr[], int size);

char a[16];

...

fun(a, size);

顯然,如果一開始 fun() 函數接收到的參數是裸數組,那麼在後續開發中,要擴展參數就必須修改 fun() 函數原型,相應的調用處也需要修改,如果 fun() 函數的調用處特別多,那麼擴展工作將會無比痛苦,並且很容易出錯。

另外一個問題是,void fun(char arr[], int size); 中的 arr 和 size 是對應關係,但是卻沒有語法規則約束這種對應關係,因此在複雜的項目開發中,將數組 b 的 size 誤認為是數組 a 的 size 使用的情況是極有可能存在的,這樣的錯誤發現和排查都相當困難。

如果,我們一開始就將數組封裝在結構體裡,在創建 fun() 函數時,其實並未增加多少工作量:

typedef struct{

char arr[16];

}String;

void fun(String *a);

String a;

...

fun(&a);

現在需要對 fun() 方法擴展,增加 size 參數:

typedef struct{

char arr[16];

int size;

}String;

void fun(String *a);

String a;

...

fun(&a);

顯然,唯一要做的就是為結構體 String 新增了一個 size 成員以及相應的方法實現,fun() 函數原型不動,因此所有調用 fun() 函數的代碼也就不需要修改了,這樣的擴展無疑是方便的。另外,size 和 arr 的對應關係由C語言結構體語法約束,這也在最大程度上避免了程式設計師錯用 size。

小結

C語言語法本身是非常簡單的,代碼本身是易懂的,但是簡單的組合背後常常隱藏著程式設計師匠心的一面,這些組合常常能為項目開發帶來意想不到的好處。

點個關注再走吧

歡迎在評論區一起討論,質疑。文章都是手打原創,每天最淺顯的介紹C語言、linux等嵌入式開發,喜歡我的文章就關注一波吧,可以看到最新更新和之前的文章哦。

未經許可,禁止轉載。

相關焦點

  • c語言結構體數組初始化
    有關結構體數組初始化的問題struct _m_usmart_nametab usmart_nametab[]=本文引用地址:http://www.eepw.com.cn/article/201611/322298.htm{#if USMART_USE_WRFUNS==1 //如果使能了讀寫操作(void
  • C語言程序開發中,定義結構體時,為什麼交換下成員順序會報錯?
    在我之前的文章裡,曾討論過可以在C語言結構體裡定義不指定長度的數組,以便後期根據需要擴展。小明看了這樣的文章後,立刻就在自己的代碼中使用了,但是他遇到了一個問題。遇到了一個問題C語言定義結構體成員,有順序要求嗎?
  • 快速上手系列-C語言之數組
    類似這樣的問題,用數組就很好解決,同樣的問題我們可以用 int ages[50]; 來表示,簡單明了。繼上一篇《快速上手系列-C語言之基礎篇(二)》寫數據類型和運算符相關內容之後,這裡簡單介紹一下C語言中非常常用的一種數據結構,即數組。
  • 單片機的C語言中數組的用法
    數組是由具有相同類型的數據元素組成的有序集合。數組是由數組名來表示的,數組中的數據由特定的下標來唯一確定。引入數組的目的,是使用一塊連續的內存空間存儲多個類型相同的數據,以解決一批相關數據的存儲問題。數組與普通變量一樣,也必須先定義,後使用。數組在C51語言的地位舉足輕重,因此深入地了解數組是很有必要的。
  • C語言編程技巧:跟我學如何定義及使用一個字符串數組
    實現目的我們在用C語言編寫程序時,經常會遇到使用字符串數組的情況,這種數組的特點是, 數組中的每個元素都是一個字符串,但每個字符串的長度卻不相同。如果你使用C++語言進行編程的話,實現起來相對比較簡單,只需直接選擇標準模板庫的字符串string類,在代碼中定義該類的一個數組即可實現。現在的問題是,在純C語言中如何定義這樣的一個字符串數組呢?如對於下面的一個字符串數組:str = {「I love C.」,「I love C++.」,「I love JAVA.」
  • 嵌入式C中的結構是什麼?
    可以在程序中將這些變量視為一個組嗎?例如,假設需要指定生成上述語音 陣列的ADC的採樣率。可以定義一個浮點變量來存儲採樣率:float sample_rate;儘管變量voice和sample_rate彼此相關,但它們被定義為兩個獨立變量。為了將這兩個變量相互關聯,我們可以使用稱為結構的C語言的強大數據結構。
  • 第三篇:C語言中數組與變量的不同,一個更好用的存儲空間
    在程式語言中,有一個非常核心的概念「變量」。雖然變量中保存的數據可以發生變化,但還是存在著一定的局限性。比如:當要保存一個班多個學員的成績。雖然使用變量可以實現,但操作起來非常繁瑣,特別是當學生的人數越來越多的時候。
  • 計算機二級考試C語言高頻考點
    一,C語言概述C語言基礎知識1.C語言的構成(1)源程序由函數構成,每個函數完成相對獨立的功能(2)每個源程序中必須有且只能有一個主函數可以放在任何位置C語言的標識符可以分為3類。①關鍵字:C語言規定的專用的標識符,它們有著固定的含義,不能更改②預定義標識符:和「關鍵字」一樣也有特定的變量要有變量名,在使用前必須先定義。③用戶標識符:由用戶根據需要定義的標識符。
  • C語言基礎知識學習(一)
    b) 預定義標識符包括C語言提供的庫函數、預編譯處理命令。c) 用戶標識符根據需要定義的標識符。一般用來給變量、函數、數組、文件等命名。用戶標誌符如果與C語言的關鍵字重名,系統報錯;若與標準庫函數重名,系統不報錯,但預定義標識符將會失去原意,代之以用戶新定義的含義。顯然如果後面用到這個函數將會報錯。
  • C/C+編程筆記:零基礎講解C語言——基本字符集
    標識符的命名規則 1. 1 什麼是標識符? 在C語言中,符號常量,變量,數組,函數等都需要一定的名稱,我們把這種名稱成為標識符。也就是說,標識符我們為C語言中出現的所有元素取得名字。
  • 第六篇:C語言中結構體與文件操作相關知識點梳理
    前面總結過,C語言中的基本數據類型有四種,分別是整型、浮點型和字符型;後面又講到可以保存字符串的字符數組。但這遠遠不夠實際應用的需要。注意:這個學生信息是一個整體,用前面學到的基本數據類型是無法實現的。有沒有一種學生的數據類型可以使用?系統沒有定義,就只能自行設計了。這就是本文要總結的第一個核心知識點:結構體。在C語言中結構體是對數據類型的無限擴展。
  • C語言編程技巧:控制臺程序中自定義函數實現數組內容的特定顯示
    在用C語言編寫算法調試方面的程序中,經常會遇到這種情況,在不同地方需要對處理後的數組內容多次進行顯示,並且很多情況下並非顯示數組裡面的全部內容,而僅僅是想觀察數組中的部分數據內容,若每次顯示時都用printf函數寫的話,未免太過麻煩了。
  • C語言中的「不透明」指針是什麼,它有什麼用呢?
    雖說指針是C語言中比較複雜的語法,但是確實非常好用,因此我寫過不少文章討論C語言中的指針,相信對初學者理解指針有一定的幫助。事實上,的確有讀者私信我說看了這些文章,「總算不再畏懼指針了」。不過他同時也問了一個問題:C語言有「不透明指針(opaque pointer)」嗎?
  • 結構體字節對齊詳解(C/C++)
    開篇明義,在討論結構體字節對齊問題前,我們需知道,什麼是結構體,大家可以把結構體比喻成一籮筐,這個籮筐會隨著裡面放的東西的體積的增加而變大
  • c語言中malloc申請的空間和直接定義變量申請的空間有什麼區別?
    有很大區別。根據以前的編程經驗,要點有三點:一是空間分配的連續性;二是動態內存申請;三是防止程序執行中出現異常錯誤。以下分別說明。直接定義變量與malloc定義變量的編程含義;malloc事先分配好了內存空間。
  • C語言的指針,簡介
    指針,是一個表示變量或函數的地址的無符號整數。指針的字節數,與CPU的位數有關,32位機是4位元組,64位機是8位元組。與高級語言的long類型的大小是一致的。所以在java的JNI庫裡,如果需要把native層的C結構體的指針保存到java層,一般是定義一個long類型的變量。指針指向的變量,可以是普通變量、數組變量、結構體變量,以及數組元素、結構體的成員變量,還可以是指針變量。指針還可以指向函數,叫做函數指針。
  • C語言程序設計試題與答案B卷
    每小題1分,共20分)1、一個C語言程序是由( )。A)a[2] B)&(a+1) C)a[5] D)&p9、對二維數組的正確定義是(    )。
  • 自考「C語言程序設計」模擬試題十一
    「c」    B.『\\』『    C.』W『   D. 』『  14.若有代數式3ae/bc,則不正確的c語言表達式是(     )  A.a/b/c*e*3    B.3*a*e/b/c    C.3*a*e/b*c    D.a*e/c/c*3  15.在C語言中,要求運算數必須是整型的運算符是(   )  A./    B.++   C
  • C語言程序設計試題及答案
    A) 'a'&&'b' B) a<=b C) a||b+c&&b-c D) !((a<b)&&!c||1)14、設有數組定義:char array[]=「student」;則數組所佔的存貯空間為( )。
  • C語言編程技巧:以實例跟我學動態數組的創建及使用方法
    問題提出在C語言編程中,對於普通數組的定義,如定義一個包含10個int類型元素的一維數組a,我們採用下面的方式:int a[10];這種方式定義的數組是靜態數組,其特點是定義方便,無需管理其內存的佔用情況,但其缺點是一旦定義後,其數組的長度就固定了,而不能動態的改變其大小