C語言復合數據類型


       C語言數據類型非常豐富,其中結構體的使用非常廣泛,也有一點復雜,這一講我們主要學習結構體的使用方法,同時也會學習到聯合、枚舉以及typedef的使用,因為結構體最為復雜,使用最廣,所以我們主要學習結構體。

struct結構體的定義和初始化

//例:
struct student{
char name[100];
int age;
};
int main(){
struct student st;
//定義了一個student類型的結構體,名字叫做st,存放在棧里邊
st.age =20;
strcpy(st.name,”liudehua”);
struct student st1 ={“zhzdu”,40};
//定義結構體變量,同時初始化結構體變量
struct student st1 ={.age =40,.name=”zxjiifuhg”};
//定義結構體變量,同時初始化結構體變量,使用這種方式可以改變初始化順序
struct student st1 ={“zhzdu”};
//定義結構體變量,同時初始化結構體變量,不初始化的結構體變量則默認為0
};

結構體的對齊說明

     結構體在內存中總是對齊的,一個結構體成員變量總是以最大的那個元素作為對齊單位。

struct A{//8字節,a1后面空着3個字節,a2占4個字節
char a1; 
int a2;
}
struct A1{//8字節,a1后面空着一個字節,然后a3占兩個字節,a2占4個字節
char a1;
short a3;
int a2;
}
struct A2{
char a[10];
int b; 
}

       如果結構體出現數組,則以數組中的具體每個成員大小為對齊標准,如果變量結構體中的所有成員都是一種類型,那么結構體在內存中就基本和一個數組類似。結構體變量的地址就是它首元素的地址。

結構體元素的位字段

      為了節省內存空間,結構體變量允許使用為聲明,例子如下:

struct A2{//一共占1字節
unsigned char a:2;//a只有兩個bit
unsigned char b:4;  //b只有4個bit
}

結構體數組

struct A2{
char name[20];
unsigned char age; 
unsigned char sex;
}
void main(){
struct A2 st[3];//定義一個結構體數組,有3個成員,每個成員都是struct結構體變量
}

       CPU處理int相比其它基本數據類型效率是最高的,但是int比char要多占內存.

冒泡排序結構體數組

       首先要學會使用冒泡排序,然后根據結構體某個成員大小之間作比較,再根據冒泡排序交換結構體中的各個成員來排序,具體的實現方法可自行實現。

結構體嵌套

       結構體內部可以有其它結構體,其本質和結構體沒有太多區別。

struct A{
char a1;
short a2;
};

struct B{
struct A a;//這里是一個結構體的嵌套
char a3;//上面結構體變量作為一個整體存在,a3 不可能補到結構體A a2的后面去,它一定是一個單獨的對齊單位。
int b;
};
struct D{};//D結構體不含有任何結構體變量,這個語法在C語言是不合法的,在C++里是合法的

        結構體的賦值其實就是內存的拷貝

struct A{
   char a1;
   short a2;
};
struct A st1={s ,s};
struct A st2=st1;
//通過指針訪問結構體成員
struct A  * p=&st1;
//(*p).a1 =12;這種寫法與下面寫法作用相同,但下面寫法更直觀
p->a1 = 12;

通過指針訪問結構體數組

           這個和通過指針去訪問數組是類似的,這兒就不詳細介紹了

void main(){
struct A2 st[3]={0};
struct A2 *p=st;
p[1].name = “zcxc”
}

結構體中的數組成員和指針成員

struct man{
char * name;
int age;
};

       結構體拷貝的時候存在淺拷貝與深拷貝;淺拷貝之間只是成員之間的粗暴賦值,解決不了結構體中存在指針時,兩個指針成員之間只是簡單的地址賦值,當一個結構體變量指針成員釋放空間時,另一個結構體變量指針成員訪問的空間也就消失了,兩結構體變量之間相互影響很大。深拷貝則是存在指針變量時,首先為指針變量各自分配空間,然后再進行拷貝,每個結構體指針變量指向的的空間時相互獨立的。

堆中創建結構體變量

struct man{
char  name[20];
int age;
};
struct student{
char * name;
int age;
}
int main(){
struct man st;//name在棧里邊
struct man *st1 = malloc(sizeof(struct man));//name在堆里邊
struct man *p = malloc(sizeof(struct student));//name在堆里邊
p->name = malloc(20);
strcpy(p->name,”lfsdi”);//申請一個堆空間,st1->name在堆里,但是一個野指針
st1->age = 20;
free(p->name);
free(p);//如果結構體變量里含有指針,注意free的先后順序,如果先free p,則p堆已經釋放了,就找不到p->name的首地址
}

函數的參數為結構體變量

struct man{
  char  name[20];
  int age;
};
printf_student(struct student st){//st是形參,函數調用的時候,在棧里面有一個淺拷貝的過程,如果里邊某個成員為數組較大,會出現一個數組拷貝的過程,會消耗大量時間,不利於優化程序
  printf(“%s,%d\n”,st.name,st.age);
}
printf_student(const struct student *st) {//st =&st //只是一個簡單的結構體地址賦值,效率遠遠高於上面的,形參很少直接用一個結構體變量,一般放結構體指針
  printf(“%s,%d\n”,st->name,st->age);
}

聯合體

       聯合union是一個能在同一個存儲空間存儲不同類型的數據,聯合體所占的內存長度等於其最長成員的長度,所以代碼效率很高。聯合體雖然有多個成員,但同一時間只能存放其中一種。

union A{
int a1;
short a2;
char a3;
char *p;
};//只占4個字節
int main(){
union A a;
a1 =1;
a3 =10;
a1 =0; //之后a.a3的值為0
a.p = malloc(10);//假設這塊堆的內存編號為0x12345C
a.a1 = 0;//p的值也成了0
free(a.p);
return 0;
}

枚舉類型

     可以使用枚舉聲明代表整數常量的符號名稱,關鍵字enum創建一個新的枚舉類型,實際上enum常量是int類型的,可以增加代碼的可讀性。

struct A2{
char name[20];
unsigned char age; 
unsigned char sex;
}

enum color{red,blue,yellow,green,black};
enum sex {man,woman};
void main(){
struct A2 st;
enum sex s;
s =man;
strcpy(st.name,”znfysry”);
st.sex = man;//man就是一個整形的常量,不能做左值,常量也不能取地址
st.age = 0;
}

       每一個枚舉都有默認值0,1, 2,3,4,5,6……… 可以自己設置每個成員的值,enum color{red = 100,blue =12,red = 58,yellow,black,white};100,12,58,59,60,61.....,100 在系統內是由CPU產生的一個立即數,不能取地址, “hello”在內存的常量區里,可以取地址,int a =100;//CPU生成一個立即數,在棧中分配一個4個字節的空間,然后把這個空間的值設置為100,enum在編譯完成后只是一個不存在於內存中的立即數,不能取地址。

typdef數據類型

      typdef數據類型是一種高級數據類型,它能使某種類型創建自己的名字。僅限於數據類型,不能是表達式或具體的值。

struct student{
    char name[20];
    unsigned char age; 
    unsigned char sex;
}
typedef struct student M;//M就類似於int,就是一種數據類型
typedef unsigned char BYTE;//多了一種數據類型叫byte.可以提高代碼的維護性
int main(){
M m;
BYTE a;
return 0;
}

        typdef數據類型不是一種必須使用的數據類型,但是使用typedef主要目的是為了讓程序的可讀性更高,方便代碼的維護,在代碼十分龐大的時候這種數據類型就顯得十分必要。

#ifndef UNICODE  //方便維護代碼
typedef wchar_t TCHAR
#else
typedef char TCHAR
#endif
void main(){
TCHAR a1;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM