【C語言基礎學習筆記】七、初始結構體(詳細講解+程式碼舉例+圖解)

2021-05-21 10:03:55

本章內容是初始結構體的全部內容,希望小夥伴們能靜下心來,仔細看完並看懂,一定會收穫滿滿~
說明:在後續的資料結構與演演算法、C語言進階或者C++的學習當中,指標以及結構體這部分內容至關重要!如果這兩大塊內容沒有學好,學懂,真正融合貫通去運用,那麼在後續的資料結構與演演算法、C語言進階或者C++的學習會非常艱難,尤其是資料結構和演演算法!

有關初始指標內容的部分請參考:【C語言基礎學習筆記】六、初始指標(重點必看)(詳細講解+程式碼舉例+練習鞏固)



一、結構體型別的宣告

結構體的基礎知識:結構體是一些值的集合,這些值稱為成員變數。
結構體的每個成員可以是不同型別的變數。
結構體的由來 / 意義 / 作用:
現實生活中,我們會遇到很多複雜的物件,這些複雜的物件僅通過c語言中的整型資料型別或者浮點數資料型別是無法全面且準確的描述的,這時候我們就需要用到結構體來描述這些複雜的物件。

結構體的宣告:

struct tag  //struct---結構體關鍵字  tag---結構體標籤   struct tag---結構體型別
{
	member - list;//結構體成員列表
}variable - list;//結構體變數列表

例如描述一個學生:

#include<stdio.h>
//描述一個學生---一些資料
//名字、年齡、電話、性別
//struct---結構體關鍵字  Stu---結構體標籤  struct Stu---結構體型別
struct Stu
{
	//成員變數
	char name[20];
	short age;
	char tele[12];
	char sex[5];
}s1, s2, s3;//s1,s2,s3 是三個全域性的結構體變數,但是一般不推薦使用全域性變數
//因為全域性變數可以隨意更改,不便於控制管理
int main()
{
	struct Stu s;//建立結構體變數
	return 0;
}

說明:結構體型別相當於 int 本身不佔據空間,只有當用結構體型別建立結構體變數的時候(利用int建立整型變數)才佔據記憶體空間。
比喻:生活中蓋房子的時候,房屋構建的圖紙本身不佔用土地,只有根據圖紙去實際建造房子的時候才佔用土地。 舉例中結構體型別是 struct
Stu,如果我們嫌棄這個名字太長了,可以對其進行一個型別重定義,使用型別重定義關鍵字 typedef 將struct Stu 重定義成
Stu;重定義型別名稱後,結構體變數的建立僅需使用Stu,如圖:

在這裡插入圖片描述

結構體成員的型別: 結構體成員可以是變數、陣列、指標、甚至是其它結構體。


二、結構體變數的定義和初始化

①建立結構體型別的同時定義結構體變數

struct Point
{
	int x;
	int y;
}p1;//宣告型別的同時定義變數p1

②先建立結構體型別,再定義結構體變數

struct Point p2;  //先建立結構體型別,再定義結構體變數

③初始化:定義變數的同時賦初值

struct Point p3 = { 1,1 };
Stu s = { "張同學",20,"11011912011","保密" };

#include<stdio.h>
struct S
{
	int a;
	char c;
	char arr[20];
	double d;
};
struct T
{
	char ch[10];
	struct S s;
	char* pc;
};
int main()
{
	//建立一個struct T 型別的結構體變數
	//初始化的時候,成員如果是結構體,需要用{ }括起來。
	struct T t = { "hello",{100,'w',"hello world",3.14},NULL };//指標不知道賦什麼值的時候,可以賦NULL
	printf("%s\n", t.ch);
	printf("%s\n", t.s.arr);//先用t.s 找到結構體型別成員 再用 .去存取結構體成員裡面的成員 t.s.arr
	printf("%lf\n", t.s.d);
	printf("%p\n", t.pc);
	return 0;
}

在這裡插入圖片描述


三、結構體成員的存取

①結構體變數存取成員結構變數的成員是通過點操作符(.)存取的。點操作符接收兩個運算元。
在這裡插入圖片描述

②結構體指標存取指向變數的成員有時候我們得到的不是一個結構體變數,而是指向一個結構體的指標。
在這裡插入圖片描述


四、結構體傳參

#include<stdio.>
typedef struct Stu
{
	//成員變數
	char name[20];
	short age;
	char tele[12];
	char sex[5];
}Stu;
void Print1(Stu s)
{
	printf("name:  %s\n", s.name);
	printf("age:   %d\n", s.age);
	printf("tele:  %s\n", s.tele);
	printf("sex:   %s\n", s.sex);
}
void Print2(Stu* ps)
{
	printf("name:  %s\n", ps->name);
	printf("age:   %d\n", ps->age);
	printf("tele:  %s\n", ps->tele);
	printf("sex:   %s\n", ps->sex);
}
int main()
{
	//struct Stu s;//建立結構體變數,區域性結構體變數
	Stu s = { "張同學",20,"11011912011","保密" };
	Print1(s);
	Print2(&s);
	return 0;
}

結果展示:
在這裡插入圖片描述


提問環節:上面的兩種列印函數Print1和Print2,哪種方式更好?為什麼?
答:Print2函數更好。
函數傳參的時候,引數是需要壓棧的。如果傳遞一個結構體物件的時候,結構體過大,引數壓棧的的系統開銷比較大,所以會導致效能的下降。

結論 : 結構體傳參的時候,要傳結構體的地址。

這裡我們說到了一個概念:壓棧
之前的學習我們知道,程式記憶體主要分為三個區域,棧區、堆區、靜態區
在這裡插入圖片描述

棧區:區域性變數、函數的形式引數、函數呼叫也開闢空間
堆區:動態記憶體分配、malloc / free、realloc、calloc
靜態區:全域性變數、靜態變數
棧:
①插入一個元素-- - 壓棧
② 刪除一個元素-- - 出棧
棧的特點:先進後出,後進先出。


結尾:以上就是C語言初始結構體的全部內容,結構體的進階內容會在後面的【C語言進階學習筆記】有關結構體的部分詳細講解!