1. 程式人生 > 其它 >C語言學習筆記之結構體

C語言學習筆記之結構體

技術標籤:語言c語言

10.3 C語言結構體指標

定義:當一個指標變數指向結構體時,我們就稱它為結構體指標(指標變數指向的是結構體)
一般結構:struct 結構體標籤名 *變數名
struct stu *pstu=&stu1;

注:結構體變數名和陣列名不同,陣列名在表示式中會被轉換成指標,而結構體變數名不會,它時鐘表示的是整個集合本身,要想取得結構體變數的地址,就需要用&

還應該注意,結構體和結構體變數是兩個不同的概念:結構體是一種資料型別,是一種建立變數的模板,編譯器不會為它分配記憶體空間,就像 int、float、char 這些關鍵字本身不佔用記憶體一樣;結構體變數才包含實實在在的資料,才需要記憶體來儲存。下面的寫法是錯誤的,不可能去取一個結構體名的地址,也不能將它賦值給其他變數:

struct stu *pstu = &stu;
struct stu *pstu = stu;

獲取結構體成員採用:
(*pointer).Member
p->Member
注:結構體成員訪問運算子.
結構體指標成員訪問運算子

結構體陣列指標的使用:

#include<stdio.h>
#include<stdlib.h>

struct stu
{
	char *name;
	int age;
	float score;
}
stus[] = {
	{"ybb",24,99.8},{"ld",25,88.9}
,{"zds",26,99.9} }, *ps; int main() { int len; len = sizeof(stus) / sizeof(struct stu); printf("name\tage\tscore\t\n"); for (ps = stus; ps <stus + len; ps++)//這個語句是什麼意思??? { printf("%s\t%d\t%.2f\t\n", ps->name, ps->age, ps->score); } return 0; }

10.4 CC語言列舉型別(enum的使用)

先用最簡單的巨集定義實現:define A with B

#include<stdio.h>
#include<stdlib.h>

#define mon 1
#define tue 2
#define wed 3

int main()
{
	int day;
	scanf_s("%d",&day);
	switch (day)
	{
	default:printf("error");
		break;
	case mon:
		printf("monday");
		break;
	case tue:
		printf("tuesday");
		break;
	case wed:
		{
			printf("wednesday");
			break;
		}
	}
	return 0;

}

不拿發現,如果數量很多就很麻煩,而且數字的增長是有規律的,可以考慮利用enum實現。

printf()與puts()
scanf()與gets()

那麼就來學習一下enum的使用:

enum 列舉型別名 {value1name,value2name} a,b,c;
列舉是一種型別,通過它可以定義列舉變數:
enum week a,b,c;

#include<stdio.h>
#include<stdlib.h>

int main()
{
	enum week
	{
		mon=1,tue,wed
	}day;
	scanf_s("%d",&day);
	switch (day)
	{
	default:printf("error\n");
		break;
	case mon:
		printf("monday");
		break;
	case tue:
		printf("tuesday");
		break;
	case wed:
		printf("wednesday");
		break;
	}
	return 0;
}

需要注意的兩點是:

  1. 列舉列表中的 Mon、Tues、Wed 這些識別符號的作用範圍是全域性的(嚴格來說是 main()
    函式內部),不能再定義與它們名字相同的變數。

  2. Mon、Tues、Wed 等都是常量,不能對它們賦值,只能將它們的值賦給其他的變數。

巨集定義在預處理階段將名字替換成對應的值;
列舉在編譯階段將名字替換成對應的值;
因此列舉可以理解為發生在編譯階段的巨集。

case 關鍵字後面必須是一個整數,或者是結果為整數的表示式,但不能包含任何變數

談到C語言最關鍵的指標、陣列、結構體與記憶體管理,C語言執行的高效性需要對記憶體管理深入學習,這樣才可以掌握C語言的精髓。

10.5 C語言共用體

結構體與共用體的區別:
結構體的各個成員佔據不同的記憶體,當然為了記憶體對齊加快定址效率,各個成員佔據長度相同的記憶體空間;
共用體的所有成員佔據同一段記憶體,修改其中的一個會影響其他的成員。

10.6 大端小端及判別方式

大端和小端是指資料在記憶體中的儲存模式,它由 CPU 決定:

  1. 大端模式(Big-endian)是指將資料的低位(比如 1234 中的 34 就是低位)放在記憶體的高地址上,而資料的高位(比如 1234 中的 12 就是高位)放在記憶體的低地址上。這種儲存模式有點兒類似於把資料當作字串順序處理,地址由小到大增加,而資料從高位往低位存放。

  2. 小端模式(Little-endian)是指將資料的低位放在記憶體的低地址上,而資料的高位放在記憶體的高地址上。這種儲存模式將地址的高低和資料的大小結合起來,高地址存放數值較大的部分,低地址存放數值較小的部分,這和我們的思維習慣是一致,比較容易理解。

PC 機上使用的是 X86 結構的 CPU,它是小端模式(正常模式)
很多 ARM、DSP 也是小端模式(部分 ARM 處理器還可以由硬體來選擇是大端模式還是小端模式)
51 微控制器大端模式

10.7 C語言位域

C語言標準規定,位域的寬度不能超過它所依附的資料型別的長度。通俗地講,成員變數都是有型別的,這個型別限制了成員變數的最大長度,:後面的數字不能超過這個長度

原則:超出部分被直接截去
結構體使用的不熟練,需要加強。
那些是資料型別、那些是變數、如何分開定義、如何在宣告的時候就定義,這些都是需要掌握的。

什麼是位域:
位域技術就是在成員變數所佔用的記憶體中選出一部分位寬來儲存資料。

我們發現位域成員往往不佔用完整的位元組,有時候也不處於位元組的開頭位置,因此使用&獲取位域成員的地址是沒有意義的,C語言也禁止這樣做。地址是位元組(Byte)的編號,而不是位(Bit)的編號。

無名位域:
無名位域一般用來作填充或者調整成員位置。因為沒有名稱,無名位域不能使用。

10.8 C語言位運算

C語言的六種位運算子;
C語言的六種位運算子
區分邏輯運算子與位運算子
區分原碼 反碼 補碼
注:&是根據記憶體中的二進位制位進行運算的,而不是資料的二進位制形式。
再強調一遍,&是根據記憶體中的二進位制位進行運算的,而不是資料的二進位制形式;其他位運算子也一樣。以-9&5為例,-9 的在記憶體中的儲存和 -9 的二進位制形式截然不同:
1111 1111 – 1111 1111 – 1111 1111 – 1111 0111 (-9 在記憶體中的儲存)
-0000 0000 – 0000 0000 – 0000 0000 – 0000 1001 (-9 的二進位制形式,前面多餘的 0 可以抹掉)

  1. 整數在記憶體中是如何儲存的?
  2. 小數在記憶體中是如何儲存的?
  3. 正數和負數在記憶體中是如何儲存的?
  4. 複數在記憶體中是如何儲存的?
  5. 資料在記憶體中的儲存方式?

10.9 使用位運算對資料進行加密

通過一次異或運算,生成密文,密文沒有可讀性,與原文風馬牛不相及,這就是加密;
密文再經過一次異或運算,就會還原成原文,這就是解密的過程;
加密和解密需要相同的金鑰,如果金鑰不對,是無法成功解密的。

如果加密和解密的金鑰不同,則稱為非對稱加密演算法。在非對稱演算法中,加密的金鑰稱為公鑰,解密的金鑰稱為私鑰,只知道公鑰是無法解密的,還必須知道私鑰。