C語言結構體

1、結構體的概念

前面的教程中咱們講解了變量和數組(array),變量是一個一個定義的,數組是一組具備相同類型的變量的集合。但在實際的工做和生活中,爲了表達一個數據集,須要用不一樣數據類型的變量。例如超女基本信息,姓名爲字符串,身高和年齡爲整數,體重爲浮點數,身材和顏值爲字符串,由於數據集各要素的數據類型不一樣,不能用一個數組來存放。程序員

用咱們以前學過的知識,若是要存放超女信息,能夠用多個變量,以下:數組

char name[51];   // 姓名
  int  age;        // 年齡
  int  height;     // 身高,單位:cm
  double weight;     // 體重,單位:kg
  char sc[31];     // 身材,火辣;普通;飛機場
  char yz[31];     // 顏值,漂亮;通常;歪瓜裂棗

這種方式有一個缺陷,若是某數據集有100個要素,就要定義100個變量,對100個變量初始化,把100個變量做爲函數的參數傳遞,實在太麻煩。markdown

在C語言中,使用結構體(struct)來存放一組不一樣類型的數據,語法以下:數據結構

struct 結構體名
{
  結構體成員變量一的聲明;
  結構體成員變量二的聲明;
  結構體成員變量三的聲明;
  ......
  結構體成員變量四的聲明;
};

結構體是一個集合,是一種構造的數據類型,是程序員爲了描述一個數據集本身定義出來的數據類型。結構體的成員(member)能夠是任意類型的變量,也能夠是結構體變量。以超女爲例:ide

struct st_girl
{
  char name[51];   // 姓名
  int  age;        // 年齡
  int  height;     // 身高,單位:cm
  int  weight;     // 體重,單位:kg
  char sc[31];     // 身材,火辣;普通;飛機場
  char yz[31];     // 顏值,漂亮;通常;歪瓜裂棗
};

2、結構體變量

結構體是一種程序員自定義的數據類型,是模板,能夠用它來定義變量。例如:函數

struct st_girl queen, princess, waiting, workers;

定義了四個結構體變量,queen王后、princess王妃,waiting宮女和workers侍者。學習

3、佔用內存的狀況

理論上講結構體的各個成員在內存中是連續存放的,和數組很是相似,可是,結構體的佔用內存的總大小不必定等於所有成員變量佔用內存大小之和。在編譯器的具體實現中,爲了提升內存尋址的效率,各個成員之間可能會存在縫隙。用sizeof能夠獲得結構體佔用內容在總大小,sizeof(結構體名)或sizeof(結構體變量名)均可以。.net

示例(book90.c)3d

/*
 * 程序名:book90.c,此程序用於演示C語言的結構體佔用內存的狀況
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>

struct st_girl
{
  char name[50];     // 姓名
  int  age;          // 年齡
  int  height;       // 身高,單位:釐米cm
  char sc[30];       // 身材,火辣;普通;飛機場。
  char yz[30];       // 顏值,漂亮;通常;歪瓜裂棗。
};

int main()
{
  struct st_girl queen;
  printf("sizeof(struct st_girl) %d\n",sizeof(struct st_girl));
  printf("sizeof(queen) %d\n",sizeof(queen));
}

運行效果指針

在這裏插入圖片描述

從上面的示例能夠看出,struct st_girl所有成員變量佔用的內存是50+4+4+30+30=118,可是結構體佔用的內存是120。

注意,C語言提供告終構體成員內存對齊的方法,可使結構體成員變量之間的內存沒有空隙,我暫時不介紹。

4、結構體的變量名

和數組不同,結構體變量名不是結構體變量的地址,結構體變量名就是變量名,就象int ii同樣,只是不能直接輸出,直接輸出沒有意義。取地址要用&,不用鑽牛角尖,不直接輸出就好了。

struct st_girl stgirl;
  printf("%d\n",stgirl);   // 沒有意義。
  printf("%p\n",stgirl);   // 沒有意義,結構體變量名不是結構體變量的地址。
  printf("%p\n",&stgirl);  // 這纔是結構體的地址。

5、結構體初始化

採用memset函數初始化結構體,所有成員變量的值清零。

memset(&queen,0,sizeof(struct st_girl));

memset(&queen,0,sizeof(queen));

注意事項,若是把一個結構體的地址傳給子函數,子函數用一個結構體指針(如struct st_girl *pst)來存放傳入的結構體的地址,那麼,在子函數中只能用如下方法來初始化結構體:

memset(pst,0,sizeof(struct st_girl));

不能用如下方法來初始化結構體:

memset(pst,0,sizeof(pst));

由於子函數中用sizeof(pst),獲得的不是結構體佔用內存的字節數,而是結構體指針變量佔用內存的字節數(8字節)。

6、成員的訪問(使用)

使用使用圓點.運算符能夠訪問(使用)結構的成員,結構體成員變量的使用與普通變量的使用相同。

示例(book92.c)

/*
 * 程序名:book92.c,此程序演示結構體的訪問(使用)。
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>

struct st_girl
{
  char name[50];     // 姓名
  int  age;          // 年齡
  int  height;       // 身高,單位:釐米cm
  char sc[30];       // 身材,火辣;普通;飛機場。
  char yz[30];       // 顏值,漂亮;通常;歪瓜裂棗。
};

int main()
{
  struct st_girl queen;  // 定義結構體變量

  // 初始化結構體變量
  memset(&queen,0,sizeof(struct st_girl));

  // 對結構體每一個成員賦值
  strcpy(queen.name,"武則天");
  queen.age=28;
  queen.height=168;
  strcpy(queen.sc,"火辣");
  strcpy(queen.yz,"漂亮");

  printf("姓名:%s\n",queen.name);
  printf("年齡:%d\n",queen.age);
  printf("身高:%d\n",queen.height);
  printf("身材:%s\n",queen.sc);
  printf("顏值:%s\n",queen.yz);
}

運行效果

在這裏插入圖片描述

7、結構體數組

結構體能夠被定義成數組變量,本質上與其它類型的數組變量沒有區別。

struct st_girl princess[6];
memset(princess,0,sizeof(princess));
strcpy(princess[0].name,"楊玉環");
princess[0].age=18;
strcpy(princess[1].name,"西施");
princess[1].age=28;
……

在實際開發中,咱們不多用結構體數組,C++標準庫的vector容器是一個動態的結構體數組,比結構體數組更方便。

8、結構體指針

結構體是一種自定義的數據類型,結構體變量是內存變量,有內存地址,也就有結構體指針。

在指針章節中咱們已經學習過,採用不一樣數據類型的指針指向不一樣數據類型的變量的地址,這一規則也適用於結構體。以下:

struct st_girl queen;
struct st_girl *pst=& queen;

經過結構體指針可使用結構體成員,通常形式爲:

(*pointer).memberName

或者:

pointer->memberName

第一種寫法中,圓點.的優先級高於*,(*pointer)兩邊的括號不能少。若是去掉括號寫做*pointer.memberName,那麼就等效於*(pointer.memberName),這樣意義就徹底不對了。

第二種寫法中,-\>是一個新的運算符,習慣稱它爲「箭頭」,有了它,能夠經過結構體指針直接使用結構體成員;這也是-\>在C語言中的惟一用途。

上面的兩種寫法是等效的,程序員一般採用後面的寫法,這樣更加直觀。

示例(book93.c)

/*
 * 程序名:book93.c,此程序演示結構體的指針
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>

struct st_girl
{
  char name[50];     // 姓名
  int  age;          // 年齡
};

int main()
{
  struct st_girl *pst,queen;  // 定義結構體變量

  // 初始化結構體變量
  memset(&queen,0,sizeof(struct st_girl));

  pst=&queen;

  // 對結構體每一個成員賦值
  strcpy(pst->name,"武則天");
  pst->age=28;

  printf("姓名:%s,年齡:%d\n",queen.name,queen.age);
  printf("姓名:%s,年齡:%d\n",pst->name,pst->age);
  printf("姓名:%s,年齡:%d\n",(*pst).name,(*pst).age);
}

運行效果

在這裏插入圖片描述

9、結構體的複製

在C語言中,結構體的成員若是是基本數據類型(int、char、double)能夠用=號賦值,若是是字符串,字符串不是基本數據類型,能夠用strcpy函數賦值,若是要把結構體變量的值賦給另外一個結構體變量,有兩種方法:1)一種是把結構體變量成員的值逐個賦值給另外一個結構體變量的成員,這種方法太笨,沒人使用;2)另外一種方法是內存拷貝,C語言提供了memcpy(memory copy的簡寫)實現內存拷貝功能。

函數聲明:

void *memcpy(void *dest, const void *src, size_t n);

參數說明:

src 源內存變量的起始地址。

dest 目的內存變量的起始地址。

n 須要複製內容的字節數。

函數返回指向dest的地址,函數的返回值意義不大,程序員通常不關心這個返回值。

示例(book94.c)

/*
 * 程序名:book94.c, 此程序演示採用memcpy函數複製結構體
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>

struct st_girl
{
  char name[50];     // 姓名
  int  age;          // 年齡
};

void main()
{
  struct st_girl girl1,girl2;

  strcpy(girl1.name,"西施");  // 對girl1的成員賦值
  girl1.age=18;

  // 把girl1的內容複製到girl2中
  memcpy(&girl2,&girl1,sizeof(struct st_girl));

  printf("girl1.name=%s,girl1.age=%d\n",girl1.name,girl1.age);
  printf("girl2.name=%s,girl2.age=%d\n",girl2.name,girl2.age);
}

運行效果

在這裏插入圖片描述
你們可能想起了strcpy函數,與memcpy有類似之處,實際上這兩個函數從功能和實現原理上完本不一樣,甚至不該該放在一塊兒比較。

1)複製的內容不一樣,strcpy只能複製字符串,而memcpy能夠複製任意內容,例如字符數組、整型、結構體、類等。

2)用途不一樣,一般在複製字符串時用strcpy,而須要複製其餘類型數據時則通常用memcpy。

3)複製的方法不一樣,strcpy不須要指定長度,它遇到被複制字符的串結尾符0才結束,memcpy則是根據其第3個參數決定複製的長度。

10、結構體做爲函數的參數

結構體是多個變量集合,做爲函數參數時就能夠傳遞整個集合,也就是全部成員。若是結構體成員較多,函數參數的初始化和賦值的內存開銷會很大,影響程序的運行效率。因此最好的辦法就是傳遞結構體變量的地址。

示例(book95.c)

/*
 * 程序名:book95.c,此程序演示結構體做爲函數的參數。
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>

struct st_girl
{
  char name[50];     // 姓名
  int  age;          // 年齡
};

// 對結構體賦值的函數
void setvalue(struct st_girl *pst);

int main()
{
  struct st_girl queen;  // 定義結構體變量

  // 初始化結構體變量
  memset(&queen,0,sizeof(struct st_girl));

  setvalue(&queen);  // 調用函數,傳結構體的地址

  printf("姓名:%s,年齡:%d\n",queen.name,queen.age);
}

void setvalue(struct st_girl *pst)
{
  // 對結構體每一個成員賦值
  strcpy(pst->name,"武則天");
  pst->age=28;
}

運行效果

在這裏插入圖片描述

11、枚舉和共同體

C語言還有兩種數據結構:枚舉和共同體,這兩種數據結構的應用太少了,少到我已經記不起它們的定義,二十年來,我從未使用過,也不介紹了。

12、memset和bzero函數

一、memset函數

memset 函數是內存空間賦值函數,用來給某一塊內存空間進行賦值的。

包含在\<string.h\>頭文件中。

函數的聲明以下:

void *memset(void *s, int v, size_t n);

s爲內存空間的地址,通常是數組名或結構體的地址。

v爲要填充的值,填0就是初始化。

n爲要填充的字節數。

在實際開發中,程序員用memset函數對數組或結構體清零,在以前的章節中,咱們已經用過不少次了。

二、bzero函數

bzero函數是內存空間清零。

包含在\<string.h\>頭文件中。

函數的聲明以下:

void bzero(void *s, size_t n);

s爲內存空間的地址,通常是數組名或結構體的地址。

n爲要清零的字節數。

若是要對數組或結構體清零,用memset和bzero均可以,沒什麼差異,看程序員的習慣。

十3、課後做業

編寫示例程序,把本章節介紹的知識點所有演示一遍,用程序演示能夠加深您的理解和映象。

十4、版權聲明

C語言技術網原創文章,轉載請說明文章的來源、做者和原文的連接。
來源:C語言技術網(www.freecplus.net)
做者:碼農有道

若是這篇文章對您有幫助,請點贊支持,或在您的博客中轉發個人文章,謝謝!!!若是文章有錯別字,或者內容有錯誤,或其餘的建議和意見,請您留言指正,很是感謝!!!

相關文章
相關標籤/搜索