日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C語言自定義類型全解析_C 語言

作者:誠摯的喬治 ? 更新時間: 2022-04-16 編程語言

前言

初學C語言

我們先接觸的都是內置的類型

比如說int char short float double long等等

這一期就來聊一聊自定義類型的知識

結構體類型

首先我們要知道什么是結構體

結構體就是各種值集合

這些值被稱作結構體成員,這些成員可包括各種不同的類型

struct tag         //這里的struct是結構體的關鍵字,tag是結構體標簽,也就是結構體的名稱
{
	number - list; //結構體成員列表
}veriable-list;    //結構體的變量 

結構體的聲明

如果結構體的標簽是student,我拿student來舉例子

結構體的完整聲明

struct Student
{
    char name[20];//姓名
    char sex;//性別
    int age;//年齡
    int num;//學號
};   //這里的分號不能丟

結構體的不完全聲明(匿名結構體類型)

struct
{
	int a;
	char b;
	double c;
}s;   //這s不能省略

匿名結構體的特點就是沒有結構體標簽

但這樣寫用戶使用時只能使用一次,也就是說只能在結構體聲明時就定義變量

因為你找不到結構體標簽,就相當于找不到門牌號一樣,無法再對其定義一個變量

結構體變量的定義與初始化

結構體的定義大致分為三種情況

<1>結構體聲明的同時定義

struct Student 
{
    char name[20];//姓名
    char sex[20];//性別
    int age;//年齡
}s={"zhangsan","nan",20};

<2>結構體先聲明,再定義

#include<stdio.h>
struct Student
{
    char name[20];//姓名
    char sex;//性別
    int age;//年齡
    int num;//學號
};
 
 
int main()
{
    struct Student s = { "zhangsan",'w',20,111 };
	return 0;
}

<3>匿名結構體定義

struct 
{
    char name[20];//姓名
    char sex[20];//性別
    int age;//年齡
} s = { "zhangsan","nan",20};

注意:結構體初始化與數組相同,都必須整體進行賦值。

結構體的自引用

struct Node //初始話鏈表
{
	int a;
	struct Node next;
};

結構體的自引用就是結構體再套用自己

學過數據結構的朋友應該知道這是初始化鏈表

不過這一個代碼有問題的

問題在于無法求出這個結構體的大小,不清楚這個結構體有多大,因為無法求出自引用的結構體有多大

所有自引用的結構體要用指針來訪問

struct Node //初始話鏈表
{
	int a;
	struct Node* next;
};

故就可以通過指針來訪問每一個結點

結構體的訪問

當結構體定義且變量初始化完成后,就可以通過操作符來訪問變量中的成員

當然,這里給出了兩個操作符

分別是? .操作符和 -> 操作符

當使用結構體變量時,就用點操作符,當訪問結構體指針變量就用箭頭操作符

(1)通過結構體變量進行訪問:

printf("%s\n",s.name);

(2)通過結構體指針進行訪問:

printf("%s\n",ps->name);

結構體的傳參

函數的調用有時候需要傳一些參數

參數的類型可以是不同的類型,可以是數組,也可以是指針

同樣結構體的傳參也可通過傳結構體或者傳指針

傳結構體

#include<stdio.h>  
struct tag
{
	int a;
	char b[20];
}s1 = { 100,"abcdef" };
void print()
{
	printf("%d", s1.a);
}
int main()
{
	print(s1);
	return 0;
}

傳地址

#include<stdio.h>
struct tag
{
	int a;
	char b[20];
}s2 = { 100,"abcdef" };
void print(struct tag*s2)
{
	printf("%d", s2->a);
}
int main()
{
	print(&s2);
	return 0;
}

我們要知道函數傳參是形參就是實參的臨時拷貝

參數是要壓棧的(向系統申請空間),既然是臨時拷貝,就會再次再棧上開辟空間,當實參足夠大時,顯然會浪費一定的空間和時間

相比較與傳結構體,傳指針會更好?

結構體的內存對齊(強烈建議觀看)

在另外一篇文章詳細講過——C語言結構體中內存對齊的問題理解

位段

可能有人沒有聽過什么是位段

位段的結構類型跟結構體有些類似可以類似結構體去學習

也可以說

位段是結構體特殊的實現

位段的聲明

相較于結構體,位段的聲明有兩點不同

<1>規定位段的成員的必須是int,unsigned int ,signed int (但是寫成char類型也沒什么大的問題)

<2>位段的成員后面有一個冒號和一個數字

struct A  //位段的聲明
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

位段的內存管理

#include<stdio.h>
struct A
{
	int a : 2;
	int b : 5;
	int c : 10;
	int d : 30;
};
int main()
{
	
	printf("大小是%d字節", sizeof(struct A));
	return 0;
}

為什么位段的大小是八個字節呢?

成員內包含的數字代表的是這個成員需要利用的內存,單位是bit。

位段成員申請內存時都是以四個字節或者一個字節單位(當成員是char類型時)

int a : 2; //申請4個字節,也就是32個bit位,利用兩個還剩30個
int b : 5; //利用5個,還剩25個
int c : 10; //利用10個,還剩15個
int d : 30; //這里的十五不夠,所以再申請了4個字節

最終的結果就是八字節

但問題是,變量d利用的空間是留下的15個bit加上重新申請的空間呢

這個結果在不同的環境的結果是不同的,所以位段的跨平臺性比較差

位段使用的前提是你知道存儲的內存大概有多大

就比如說年齡

十個bit位0111111111,最大值就可以達到1023

就不需要再申請一次利用一個int類型的空間大小

這就達到了節省內存的作用,存在即合理

位段的應用?

struct A
{
	char a : 3;
	char b : 4;
	char c : 5;
};
main()
{
	struct A s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	return 0;
}

位段的跨平臺性

1.int位段被當成有符號數還是無符號數是不確定的,有時候系統會自動轉化為無符號整形。

2.位段中最大位的數目不能確定。(因為在早期的16位機器int最大16,而32位機器int最大32)

3.位段中的成員在內存中從左向右分配,還是從右向左分配標準尚未定義。

意思當內存一個字節00000000,存入01010,可能會出現00001010或者01010000

4.當一個結構包含兩個位段,第二個位段成員比較大,無法容納于第一個位段剩余的位時,是 舍棄剩余的位還是利用,這是不確定的。

?枚舉類型

枚舉類型適用于可以一一列舉的類型

比如說星期、性別

枚舉類型的定義

enum Day   //星期
{
	//枚舉的可能取值
	Mon,
	Tues,
	Wed,
	Thir,
	Fri,
	Sta,
	Sun
};
enum Sex  //性別
{
	MALE,//0
	FEMALE,//1
	SECRET//2
};

枚舉類型是有初始值的

如果你沒賦予它初始值,就會默認從零開始,依次加一

枚舉類型賦予初始值

#include<stdio.h>
enum Sex  //性別
{
	MALE = 4,
	FEMALE=10,
	SECRET//
};
main()
{
	printf("%d %d %d", MALE,FEMALE,SECRET);
	return 0;
}

可以看到,其實默認的值是可以改的

當某個成員被賦予某個值的時候,后續的成員就在此基礎上加一

枚舉類型的優點

1.相較于數字,枚舉增加代碼的可讀性和可維護性

2.和#define定義的標識符比較枚舉有類型檢查,更加嚴謹。

3.防止了命名污染(封裝)

4.便于調試

5.使用方便,一次可以定義多個常量

聯合體類型

聯合體類型也叫共用體

聯合體的定義

union Un  
{
	int a;
	char b;
};

union是聯合體關鍵字,Un是聯合體的標簽

聯合體的特點

共用體,顧名思義,這里的共用就是公用內存

內存的也可被折疊

#include<stdio.h>
union Un
{
	char c;
	int i;
};
int main()
{
	union Un u = {0};
	printf("%d\n", sizeof(u));
	printf("%p\n", &u);
	printf("%p\n", &(u.c));
	printf("%p\n", &(u.i));
	return 0;
}

他們有相同的地址

c和i存放在同一塊內存空間上,修改c或者i都會影響到另一個成員。

?聯合體內存大小的計算

<1>聯合體內存大小是最大成員的大小

<2>最大成員的大小如果不是最大對齊數的整數倍,就會對齊到最大對齊數的整數倍

(聯合體也存在內存對齊)

#include<stdio.h>
union Un1
{
	char c[5];  
	int i;
};          
//Un1成員最大成員大小5,最大對齊數是4,所以Un1的大小是8;
union Un2
{
	char c[7];
		int i;
};
//Un2成員最大成員大小7,最大對齊數是4,所以Un2的大小是8;
int main()
{
	printf("%d\n", sizeof(union Un1));
	printf("%d\n", sizeof(union Un2));
	return 0;
}

原文鏈接:https://z-ming.blog.csdn.net/article/details/122755619

欄目分類
最近更新