網(wǎng)上哪些網(wǎng)站可以做兼職湖北seo
前言
從0開始記錄我的學(xué)習(xí)歷程,我會盡我所能,寫出最最大白話的文章,希望能夠幫到你,謝謝。
1.結(jié)構(gòu)體類型的概念及定義
1.1、概念:
1.2、 結(jié)構(gòu)體類型的定義方法?
咱們在使用結(jié)構(gòu)體之前必須先有類型,然后用類型定義數(shù)據(jù)結(jié)構(gòu),這個類型相當(dāng)于一個模具
(1).先定義結(jié)構(gòu)體類型,再去定義結(jié)構(gòu)體變量
struct 結(jié)構(gòu)體類型名{
成員列表(允許我們組合多個基本數(shù)據(jù)類型(如整數(shù)、浮點數(shù)、字符等))
};
例1:
struct stu{
int num;
char name[20];
char sex;
};
我們看這個例子。
我們定義了一個名為stu
的結(jié)構(gòu)體類型。這個結(jié)構(gòu)體類型包含了三個成員:一個整數(shù)num
,一個字符數(shù)組name
,和一個字符sex
。這些成員代表了學(xué)生的學(xué)號、姓名和性別。
struct stu lucy, bob, lilei;
一旦我們定義了這個結(jié)構(gòu)體類型,就可以創(chuàng)建變量來存儲實際的學(xué)生信息了。在這個例子中,我們創(chuàng)建了三個變量:lucy
、bob
和lilei
。每個變量都是一個結(jié)構(gòu)體類型的實例,它們都有三個成員:num
、name
和sex
。
在定義結(jié)構(gòu)體類型的時候順便定義結(jié)構(gòu)體變量,以后還可以定義結(jié)構(gòu)體變量struct 結(jié)構(gòu)體類型名 {成員列表 ;} 結(jié)構(gòu)體變量 1, 變量 2;struct 結(jié)構(gòu)體類型名 變量 3 ,變量 4 ;
例如看下面這個例子,實際上是和上面的例子是一個意思的。
struct stu{
int num;
char name[20];
char sex;
}lucy;
struct stu bob, lilei;
在定義結(jié)構(gòu)體類型的時候,沒有結(jié)構(gòu)體類型名,順便定義結(jié)構(gòu)體變量,
因為沒有類型名,所以以后不能再定義相關(guān)類型的數(shù)據(jù)了。也就是不可以往成員列表里面添加?xùn)|西了。struct {成員列表 ;} 變量 1 ,變量 2;
?2 結(jié)構(gòu)體變量的定義初始化及使用
?1、結(jié)構(gòu)體變量的定義和初始化
結(jié)構(gòu)體變量,是個變量,這個變量是若干個數(shù)據(jù)的集合
注:(1): 在定義結(jié)構(gòu)體變量之前首先得有結(jié)構(gòu)體類型,然后在定義變量(2): 在定義結(jié)構(gòu)體變量的時候,可以順便給結(jié)構(gòu)體變量賦初值,被稱為結(jié)構(gòu)體的初始化(3): 結(jié)構(gòu)體變量初始化的時候,各個成員順序初始化
struct stu{
int num;
char name[20];
char sex;
};
struct stu boy;
struct stu lucy={101,"lucy",'f'};
我們創(chuàng)建了兩個變量來存儲實際的學(xué)生信息。第一個變量boy它
是一個未初始化的結(jié)構(gòu)體變量,它沒有任何成員的值被賦定。第二個變量lucy
是一個已經(jīng)初始化的結(jié)構(gòu)體變量。在聲明時,我們直接給它賦初值。這里,我們給了學(xué)號、姓名和性別的值。
在這個初始化中,我們按照成員的順序給了值:
101
?是?num
?成員的值。"lucy"
?是?name
?成員的值。由于?name
?是一個字符數(shù)組,我們使用引號括起來來表示字符串。'f'
?是?sex
?成員的值。
?1、結(jié)構(gòu)體變量的使用
定義了結(jié)構(gòu)體變量后,要使用變量
(1). 結(jié)構(gòu)體變量成員的引用方法????????結(jié)構(gòu)體變量. 成員名
struct stu{
int num;
char name[20];
int age;
}bob;
int main(int argc, char *argv[])
{
lihua={10,"bob",10};
printf("%d\n",bob.num);
printf("%s\n",bob.name);
printf("%d\n",bob.age);
return 0;
}
?可以看到 通過.
操作符,我們可以訪問結(jié)構(gòu)體變量的各個成員。上面的代碼分別打印出了bob
的學(xué)號、姓名和年齡。
2、結(jié)構(gòu)體成員多級引用
????????首先,我們有一個名為date
的結(jié)構(gòu)體,它包含了三個整數(shù)字段:year
、month
和day
。這些字段代表了一個特定的日期。
struct date{int year;int month;int day;
};
????????接下來,我們有一個名為stu
的結(jié)構(gòu)體,它包含了四個字段:一個整數(shù)num
、一個字符數(shù)組name
、一個字符sex
和一個子結(jié)構(gòu)體birthday
。子結(jié)構(gòu)體birthday
是我們之前定義的date
結(jié)構(gòu)體。
struct stu{int num;char name[20];char sex;struct date birthday;
};
????????現(xiàn)在,我們在主函數(shù)中創(chuàng)建了一個名為lilei
的變量,它是一個stu
類型的變量。我們通過賦值來初始化這個變量的字段。
struct stu lilei={101,"lilei",'m'};
lilei.birthday.year=1986;
lilei.birthday.month=1;
lilei.birthday.day=8;
????????在這里,我們通過.birthday.year
,?.birthday.month
, 和?.birthday.day
來訪問和設(shè)置子結(jié)構(gòu)體中的日期字段。
最后,我們使用printf
函數(shù)來打印出變量
printf("%d %s %c\n",lilei.num,lilei.name,lilei.sex);
printf("%d %d %d\n",lilei.birthday.year,lilei.birthday.month,lilei.birthday.day);
這里,我們通過多級結(jié)構(gòu)體成員的引用來訪問和打印出各個字段的值??梢钥吹骄褪峭ㄟ^點來訪問的 嘎嘎簡單哈。
3.結(jié)構(gòu)體數(shù)組
結(jié)構(gòu)體數(shù)組是一種數(shù)據(jù)結(jié)構(gòu),它允許我們存儲多個相同類型的結(jié)構(gòu)體變量。這是非常有用的,因為它可以幫助我們組織和管理大量的相關(guān)數(shù)據(jù)。
讓我們來看看一個例子,以便更好地理解結(jié)構(gòu)體數(shù)組:
首先,我們有一個名為stu
的結(jié)構(gòu)體,它包含了三個字段:一個整數(shù)num
、一個字符數(shù)組name
和一個字符sex
。
struct stu{int num;char name[20];char sex;
};
接下來,我們定義了一個名為edu
的結(jié)構(gòu)體數(shù)組,它包含了三個元素:edu[0]
、edu[1]
和edu[2]
。
struct stu edu[3];
這個數(shù)組?edu
?可以被視為三個?stu
?類型的結(jié)構(gòu)體變量的集合。我們可以通過數(shù)組的下標來訪問每個元素,并對它們進行操作。
例如,我們可以將值?101
?給?edu[0]
?數(shù)組中的第一個結(jié)構(gòu)體變量的?num
?字段賦值:
edu[0].num = 101;
這里,.num
?是指?edu[0]
?結(jié)構(gòu)體變量中的?num
?字段。
同樣,我們可以使用?strcpy
?函數(shù)將字符串 “l(fā)ucy” 給?edu[1]
?數(shù)組中的第一個結(jié)構(gòu)體變量的?name
?字段賦值:
strcpy(edu[1].name, "lucy");
這里,.name
?是指?edu[1]
?結(jié)構(gòu)體變量中的?name
?字段。
4.結(jié)構(gòu)體指針
結(jié)構(gòu)體指針是一種在C語言中用于存儲和操作結(jié)構(gòu)體變量的特殊類型的指針。它允許我們通過指針來訪問和修改結(jié)構(gòu)體變量的字段,而無需直接使用變量的名稱。
讓我們來看看一個例子,以便更好地理解結(jié)構(gòu)體指針:
首先,我們有一個名為stu
的結(jié)構(gòu)體,它包含了兩個字段:一個整數(shù)num
和一個字符數(shù)組name
。
struct stu{int num;char name[20];
};
接下來,我們定義了一個名為p
的結(jié)構(gòu)體指針變量,它可以存儲?stu
?類型的結(jié)構(gòu)體變量的地址。
struct stu * p;
這個指針變量?p
?可以被視為一個存儲結(jié)構(gòu)體變量地址的“指針”,它占用了相同數(shù)量的內(nèi)存空間,用于保存這個地址。
現(xiàn)在,我們創(chuàng)建了一個名為boy
的結(jié)構(gòu)體變量,并使用?&
?指針運算符將其地址賦值給指針變量?p
。
struct stu boy;
p = &boy;
這里,&boy
?是?boy
?結(jié)構(gòu)體變量的地址,我們將其賦值給指針變量?p
。
接下來,我們可以通過以下方式訪問和修改?boy
?結(jié)構(gòu)體變量的字段:
-
直接訪問:
boy.num = 101; // 直接訪問并修改 boy 的 num 字段
-
通過指針訪問:
(*p).num = 101; // 使用指針來訪問并修改 boy 的 num 字段
-
使用指針運算符:
p->num = 101; // 使用指針運算符來訪問并修改 boy 的 num 字段
在這三種方法中,最后兩種都是通過指針來訪問和修改結(jié)構(gòu)體變量的字段。前提是指針必須先指向一個結(jié)構(gòu)體變量。如果指針沒有正確地指向一個結(jié)構(gòu)體變量,那么嘗試訪問或修改其字段可能會導(dǎo)致程序出錯。
結(jié)構(gòu)體指針經(jīng)常用到的地方:
(1):保存結(jié)構(gòu)體變量的地址
typedef struct stu{
int num;
char name[20];
float score;
}STU;
int main()
{
STU *p,lucy;
p=&lucy;
p->num=101;
strcpy(p->name,"baby");
//p->name="baby";//錯誤,因為 p->name 相當(dāng)于 lucy.name 是個字符數(shù)組的名字,是個常量
}
(2):傳結(jié)構(gòu)體變量的地址
#include<stdio.h>
#include<string.h>
typedef struct stu{
int num;
char name[20];
float score;
}STU;
void fun(STU *p)
{
p->num=101;
(*p).score=87.6;
strcpy(p->name,"lucy");
}
int main()
{
STU girl;
fun(&girl);
printf("%d %s %f\n",girl.num,girl.name,girl.score);
return 0;
}
(3):? ?傳結(jié)構(gòu)體數(shù)組的地址
#include<stdio.h>
#include<string.h>
typedef struct stu{
int num;
char name[20];
float score;
}STU;
void fun(STU *p)
{
p[1].num=101;
(*(p+1)).score=88.6;
}
int main()
{
STU edu[3];
fun(edu);
printf("%d %f\n",edu[1].num,edu[1].score);
return 0;
}
注意: 結(jié)構(gòu)體變量的地址編號和結(jié)構(gòu)體第一個成員的地址編號相同,但指針的類型不同
#include <stdio.h>
struct stu{
int num;
char name[20];
int score;
};
int main(int argc, char *argv[])
{
struct stu bob;
printf("%p\n",&bob);
printf("%p\n",&(bob.num));
return 0;
}
注意:結(jié)構(gòu)體數(shù)組的地址就是結(jié)構(gòu)體數(shù)組中第 0 個元素的地址.
#include <stdio.h>
struct stu{
int num;
char name[20];
int score;
};
int main(int argc, char *argv[])
{
struct stu edu[3];
printf("%p\n",edu);//struct stu *
printf("%p\n",&(edu[0]));//struct stu *
printf("%p\n",&(edu[0].num));//int *
return 0;
}
原本不想把這個代碼放上來的 但是我覺得雖然廢話多 但是如果光看話的話感覺總是有點離譜。
5、結(jié)構(gòu)體內(nèi)存分配
內(nèi)存分配與對齊規(guī)則
分配單位
- 定義:結(jié)構(gòu)體中最大成員變量的長度。
- 例如,如果結(jié)構(gòu)體中最大成員是
int
(占4字節(jié)),則分配單位為4字節(jié);如果最大成員是double
(占8字節(jié)),則分配單位為8字節(jié)。
- 例如,如果結(jié)構(gòu)體中最大成員是
成員變量偏移
- 定義:成員變量的起始地址必須是其自身長度的整數(shù)倍。
- 例如,一個
int
類型變量(4字節(jié))必須放在一個地址是4的倍數(shù)的位置上。 - 一個
short
類型變量(2字節(jié))必須放在一個地址是2的倍數(shù)的位置上。
- 例如,一個
結(jié)構(gòu)體總大小
- 定義:結(jié)構(gòu)體總大小必須是分配單位的整數(shù)倍。
- 如果最終計算出的結(jié)構(gòu)體大小不是分配單位的整數(shù)倍,需要填充(padding)到分配單位的整數(shù)倍。
內(nèi)存分配與對齊示例
假設(shè)我們有以下結(jié)構(gòu)體:
struct Example {char a; // 1字節(jié),偏移0short b; // 2字節(jié),偏移2(1 + 1對齊到2)int c; // 4字節(jié),偏移4double d; // 8字節(jié),偏移8
};
1. 確定分配單位
char
:1字節(jié)short
:2字節(jié)int
:4字節(jié)double
:8字節(jié)
最大成員變量是double
,占8字節(jié),因此分配單位是8字節(jié)。
2. 計算每個成員變量的偏移量
按照結(jié)構(gòu)體中成員變量的順序,并根據(jù)它們自身長度的整數(shù)倍來計算偏移:
- char a:
- 起始地址:0(分配結(jié)構(gòu)體的起始地址)
- 長度:1字節(jié)
- 偏移量:0(0是1的倍數(shù))
- short b:
- 上一個成員
a
結(jié)束地址:1 - 為滿足2字節(jié)對齊,b的起始地址:2
- 長度:2字節(jié)
- 偏移量:2(2是2的倍數(shù))
- 上一個成員
- int c:
- 上一個成員
b
結(jié)束地址:4 - 為滿足4字節(jié)對齊,c的起始地址:4
- 長度:4字節(jié)
- 偏移量:4(4是4的倍數(shù))
- 上一個成員
- double d:
- 上一個成員
c
結(jié)束地址:8 - 為滿足8字節(jié)對齊,d的起始地址:8
- 長度:8字節(jié)
- 偏移量:8(8是8的倍數(shù))
- 上一個成員
3. 計算結(jié)構(gòu)體總大小
- 最后一個成員
d
結(jié)束地址:16(8 + 8) - 結(jié)構(gòu)體總大小必須是分配單位(8字節(jié))的整數(shù)倍。
最終大小為16字節(jié)(已經(jīng)是8的整數(shù)倍,無需額外填充)。
成員 | 類型 | 偏移量 |
---|---|---|
a | char | 0 |
b | short | 2 |
c | int | 4 |
d | double | 8 |
結(jié)構(gòu)體總大小為16字節(jié),滿足對齊規(guī)則。
就是這樣存的。