乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      熬夜整理的C語言/C++萬字總結(jié)(四)

       C語言與CPP編程 2021-12-15

      1、結(jié)構(gòu)體

      1.1 結(jié)構(gòu)體基礎(chǔ)知識

      1.1.1 結(jié)構(gòu)體類型的定義

      struct?Person{
      ?char?name[64];
      ?int?age;
      };
      
      typedef?struct?_PERSON{
      ?char?name[64];
      ?int?age;
      }Person;
      

      注意:定義結(jié)構(gòu)體類型時不要直接給成員賦值,結(jié)構(gòu)體只是一個類型,編譯器還沒有為其分配空間,只有根據(jù)其類型定義變量時,才分配空間,有空間后才能賦值。

      10W+字C語言硬核總結(jié)(一),值得閱讀收藏!

      10W+字C語言硬核總結(jié)(二),值得閱讀收藏!

      10W+字C語言硬核總結(jié)(三),值得閱讀收藏!

      熬夜整理的C/C++萬字總結(jié)(五),文件操作

      程序員必備硬核資源,點擊下載!

      程序員書籍資源,值得收藏!

      1.1.2 結(jié)構(gòu)體變量的定義

      struct?Person{
      ?char?name[64];
      ?int?age;
      }p1;?//定義類型同時定義變量
      
      struct{
      ?char?name[64];
      ?int?age;
      }p2;?//定義類型同時定義變量
      
      struct?Person?p3;?//通過類型直接定義
      

      1.1.3 結(jié)構(gòu)體變量的初始化

      struct?Person{
      ?char?name[64];
      ?int?age;
      }p1?=?{"john",10};?//定義類型同時初始化變量
      
      struct{
      ?char?name[64];
      ?int?age;
      }p2?=?{"Obama",30};?//定義類型同時初始化變量
      
      struct?Person?p3?=?{"Edward",33};?//通過類型直接定義
      

      1.1.4 結(jié)構(gòu)體成員的使用

      struct?Person{
      ?char?name[64];
      ?int?age;
      };
      void?test(){
      ?//在棧上分配空間
      ?struct?Person?p1;
      ?strcpy(p1.name,?"John");
      ?p1.age?=?30;
      ?//如果是普通變量,通過點運算符操作結(jié)構(gòu)體成員
      ?printf("Name:%s?Age:%d\n",?p1.name,?p1.age);
      
      ?//在堆上分配空間
      ?struct?Person*?p2?=?(struct?Person*)malloc(sizeof(struct?Person));
      ?strcpy(p2->name,?"Obama");
      ?p2->age?=?33;
      ?//如果是指針變量,通過->操作結(jié)構(gòu)體成員
      ?printf("Name:%s?Age:%d\n",?p2->name,?p2->age);
      }
      

      1.1.5 結(jié)構(gòu)體賦值

      1.1.5.1 賦值基本概念

      相同的兩個結(jié)構(gòu)體變量可以相互賦值,把一個結(jié)構(gòu)體變量的值拷貝給另一個結(jié)構(gòu)體,這兩個變量還是兩個獨立的變量。

      struct?Person{
      ?char?name[64];
      ?int?age;
      };
      
      void?test(){
      ?//在棧上分配空間
      ?struct?Person?p1?=?{?"John"?,?30};
      ?struct?Person?p2?=?{?"Obama",?33?};
      ?printf("Name:%s?Age:%d\n",?p1.name,?p1.age);
      ?printf("Name:%s?Age:%d\n",?p2.name,?p2.age);
      ?//將p2的值賦值給p1
      ?p1?=?p2;
      ?printf("Name:%s?Age:%d\n",?p1.name,?p1.age);
      ?printf("Name:%s?Age:%d\n",?p2.name,?p2.age);
      }
      

      1.1.5.1 深拷貝和淺拷貝

      //一個老師有N個學生
      typedef?struct?_TEACHER{
      ?char*?name;
      }Teacher;
      
      
      void?test(){
      ?
      ?Teacher?t1;
      ?t1.name?=?malloc(64);
      ?strcpy(t1.name?,?"John");
      
      ?Teacher?t2;
      ?t2?=?t1;
      
      ?//對手動開辟的內(nèi)存,需要手動拷貝
      ?t2.name?=?malloc(64);
      ?strcpy(t2.name,?t1.name);
      
      ?if?(t1.name?!=?NULL){
      ??free(t1.name);
      ??t1.name?=?NULL;
      ?}
      ?if?(t2.name?!=?NULL){
      ??free(t2.name);
      ??t1.name?=?NULL;
      ?}
      }
      

      1.1.6 結(jié)構(gòu)體數(shù)組

      struct?Person{
      ?char?name[64];
      ?int?age;
      };
      
      void?test(){
      ?//在棧上分配空間
      ?struct?Person?p1[3]?=?{
      ??{?"John",?30?},
      ??{?"Obama",?33?},
      ??{?"Edward",?25}
      ?};
      
      ?struct?Person?p2[3]?=?{?"John",?30,?"Obama",?33,?"Edward",?25?};
      ?for?(int?i?=?0;?i?<?3;i?++){
      ??printf("Name:%s?Age:%d\n",p1[i].name,p1[i].age);
      ?}
      ?printf("-----------------\n");
      ?for?(int?i?=?0;?i?<?3;?i++){
      ??printf("Name:%s?Age:%d\n",?p2[i].name,?p2[i].age);
      ?}
      ?printf("-----------------\n");
      ?//在堆上分配結(jié)構(gòu)體數(shù)組
      ?struct?Person*?p3?=?(struct?Person*)malloc(sizeof(struct?Person)?*?3);
      ?for?(int?i?=?0;?i?<?3;i++){
      ??sprintf(p3[i].name,?"Name_%d",?i?+?1);
      ??p3[i].age?=?20?+?i;
      ?}
      ?for?(int?i?=?0;?i?<?3;?i++){
      ??printf("Name:%s?Age:%d\n",?p3[i].name,?p3[i].age);
      ?}
      }
      

      1.2 結(jié)構(gòu)體嵌套指針

      1.2.1 結(jié)構(gòu)體嵌套一級指針

      struct?Person{
      ?char*?name;
      ?int?age;
      };
      
      void?allocate_memory(struct?Person**?person){
      ?if?(person?==?NULL){
      ??return;
      ?}
      ?struct?Person*?temp?=?(struct?Person*)malloc(sizeof(struct?Person));
      ?if?(temp?==?NULL){
      ??return;
      ?}
      ?//給name指針分配內(nèi)存
      ?temp->name?=?(char*)malloc(sizeof(char)*?64);
      ?strcpy(temp->name,?"John");
      ?temp->age?=?100;
      
      ?*person?=?temp;
      }
      
      void?print_person(struct?Person*?person){
      ?printf("Name:%s?Age:%d\n",person->name,person->age);
      }
      
      void?free_memory(struct?Person**?person){
      ?if?(person?==?NULL){
      ??return;
      ?}
      ?struct?Person*?temp?=?*person;
      ?if?(temp->name?!=?NULL){
      ??free(temp->name);
      ??temp->name?=?NULL;
      ?}
      
      ?free(temp);
      }
      
      void?test(){
      ?
      ?struct?Person*?p?=?NULL;
      ?allocate_memory(&p);
      ?print_person(p);
      ?free_memory(&p);
      }
      

      1.2.2 結(jié)構(gòu)體嵌套二級指針

      //一個老師有N個學生
      typedef?struct?_TEACHER{
      ?char?name[64];
      ?char**?students;
      }Teacher;
      
      void?create_teacher(Teacher**?teacher,int?n,int?m){
      
      ?if?(teacher?==?NULL){
      ??return;
      ?}
      
      ?//創(chuàng)建老師數(shù)組
      ?Teacher*?teachers?=?(Teacher*)malloc(sizeof(Teacher)*?n);
      ?if?(teachers?==?NULL){
      ??return;
      ?}
      
      ?//給每一個老師分配學生
      ?int?num?=?0;
      ?for?(int?i?=?0;?i?<?n;?i?++){
      ??sprintf(teachers[i].name,?"老師_%d",?i?+?1);
      ??teachers[i].students?=?(char**)malloc(sizeof(char*)?*?m);
      ??for?(int?j?=?0;?j?<?m;j++){
      ???teachers[i].students[j]?=?malloc(64);
      ???sprintf(teachers[i].students[j],?"學生_%d",?num?+?1);
      ???num++;
      ??}
      ?}
      
      ?*teacher?=?teachers;?
      }
      
      void?print_teacher(Teacher*?teacher,int?n,int?m){
      ?for?(int?i?=?0;?i?<?n;?i?++){
      ??printf("%s:\n",?teacher[i].name);
      ??for?(int?j?=?0;?j?<?m;j++){
      ???printf("??%s",teacher[i].students[j]);
      ??}
      ??printf("\n");
      ?}
      }
      
      void?free_memory(Teacher**?teacher,int?n,int?m){
      ?if?(teacher?==?NULL){
      ??return;
      ?}
      
      ?Teacher*?temp?=?*teacher;
      
      ?for?(int?i?=?0;?i?<?n;?i?++){
      ??
      ??for?(int?j?=?0;?j?<?m;j?++){
      ???free(temp[i].students[j]);
      ???temp[i].students[j]?=?NULL;
      ??}
      
      ??free(temp[i].students);
      ??temp[i].students?=?NULL;
      ?}
      
      ?free(temp);
      
      }
      
      void?test(){
      ?
      ?Teacher*?p?=?NULL;
      ?create_teacher(&p,2,3);
      ?print_teacher(p,?2,?3);
      ?free_memory(&p,2,3);
      }
      

      1.3 結(jié)構(gòu)體成員偏移量

      //一旦結(jié)構(gòu)體定義下來,則結(jié)構(gòu)體中的成員內(nèi)存布局就定下了
      #include?<stddef.h>
      struct?Teacher
      {
      ?char?a;
      ?int?b;
      };
      
      void?test01(){
      
      ?struct?Teacher??t1;
      ?struct?Teacher*p?=?&t1;
      
      
      ?int?offsize1?=?(int)&(p->b)?-?(int)p;??//成員b?相對于結(jié)構(gòu)體?Teacher的偏移量
      ?int?offsize2?=?offsetof(struct?Teacher,?b);
      
      ?printf("offsize1:%d?\n",?offsize1);?//打印b屬性對于首地址的偏移量
      ?printf("offsize2:%d?\n",?offsize2);
      }
      

      1.4 結(jié)構(gòu)體字節(jié)對齊

      程序員必備硬核資源,點擊下載!

      在用 sizeof 運算符求算某結(jié)構(gòu)體所占空間時,并不是簡單地將結(jié)構(gòu)體中所有元素各自占的空間相加,這里涉及到內(nèi)存字節(jié)對齊的問題。

      從理論上講,對于任何變量的訪問都可以從任何地址開始訪問,但是事實上不是如此,實際上訪問特定類型的變量只能在特定的地址訪問,這就需要各個變量在空間上按一定的規(guī)則排列, 而不是簡單地順序排列,這就是內(nèi)存對齊。

      1.4.1.1 內(nèi)存對齊原因

      我們知道內(nèi)存的最小單元是一個字節(jié),當 cpu 從內(nèi)存中讀取數(shù)據(jù)的時候,是一個一個字節(jié)讀取,所以內(nèi)存對我們應該是入下圖這樣:

      但是實際上 cpu 將內(nèi)存當成多個塊,每次從內(nèi)存中讀取一個塊,這個塊的大小可能是2、4、8、16等,

      那么下面,我們來分析下非內(nèi)存對齊和內(nèi)存對齊的優(yōu)缺點在哪?

      內(nèi)存對齊是操作系統(tǒng)為了提高訪問內(nèi)存的策略。操作系統(tǒng)在訪問內(nèi)存的時候,每次讀取一定長度(這個長度是操作系統(tǒng)默認的對齊數(shù),或者默認對齊數(shù)的整數(shù)倍)。如果沒有對齊,為了訪問一個變量可能產(chǎn)生二次訪問。

      至此大家應該能夠簡單明白,為什么要簡單內(nèi)存對齊?

      • 提高存取數(shù)據(jù)的速度。比如有的平臺每次都是從偶地址處讀取數(shù)據(jù),對于一個int型的變量,若從偶地址單元處存放,則只需一個讀取周期即可讀取該變量;但是若從奇地址單元處存放,則需要2個讀取周期讀取該變量。

      • 某些平臺只能在特定的地址處訪問特定類型的數(shù)據(jù),否則拋出硬件異常給操作系統(tǒng)。

      1.4.1.1 如何內(nèi)存對齊

      • 對于標準數(shù)據(jù)類型,它的地址只要是它的長度的整數(shù)倍。

      • 對于非標準數(shù)據(jù)類型,比如結(jié)構(gòu)體,要遵循一下對齊原則:

      1. 數(shù)組成員對齊規(guī)則。第一個數(shù)組成員應該放在offset為0的地方,以后每個數(shù)組成員應該放在offset為min(當前成員的大小,#pargama pack(n))整數(shù)倍的地方開始(比如int在32位機器為4字節(jié),#pargama pack(2),那么從2的倍數(shù)地方開始存儲)。

      2. 結(jié)構(gòu)體總的大小,也就是sizeof的結(jié)果,必須是min(結(jié)構(gòu)體內(nèi)部最大成員,#pargama pack(n))的整數(shù)倍,不足要補齊。

      3. 結(jié)構(gòu)體做為成員的對齊規(guī)則。如果一個結(jié)構(gòu)體B里嵌套另一個結(jié)構(gòu)體A,還是以最大成員類型的大小對齊,但是結(jié)構(gòu)體A的起點為A內(nèi)部最大成員的整數(shù)倍的地方。(struct B里存有struct A,A里有char,int,double等成員,那A應該從8的整數(shù)倍開始存儲。),結(jié)構(gòu)體A中的成員的對齊規(guī)則仍滿足原則1、原則2。

      手動設(shè)置對齊模數(shù):

      • #pragma pack(show)

      顯示當前packing alignment的字節(jié)數(shù),以warning message的形式被顯示。

      • #pragma pack(push)

      將當前指定的packing alignment數(shù)組進行壓棧操作,這里的棧是the internal compiler stack,同事設(shè)置當前的packing alignment為n;如果n沒有指定,則將當前的packing alignment數(shù)組壓棧。

      • #pragma pack(pop)

      從internal compiler stack中刪除最頂端的reaord; 如果沒有指定n,則當前棧頂record即為新的packing alignement數(shù)值;如果指定了n,則n成為新的packing alignment值

      • #pragma pack(n)

      指定packing的數(shù)值,以字節(jié)為單位,缺省數(shù)值是8,合法的數(shù)值分別是1,2,4,8,16。

      程序員必備硬核資源,點擊下載!???????

      1.4.2 內(nèi)存對齊案例

      #pragma?pack(4)
      
      typedef?struct?_STUDENT{
      ?int?a;
      ?char?b;
      ?double?c;
      ?float?d;
      }Student;
      
      typedef?struct?_STUDENT2{
      ?char?a;
      ?Student?b;?
      ?double?c;
      }Student2;
      
      void?test01(){
      
      ?//Student
      ?//a從偏移量0位置開始存儲
      ?//b從4位置開始存儲
      ?//c從8位置開始存儲
      ?//d從12位置開存儲
      ?//所以Student內(nèi)部對齊之后的大小為20?,整體對齊,整體為最大類型的整數(shù)倍?也就是8的整數(shù)倍?為24
      
      ?printf("sizeof?Student:%d\n",sizeof(Student));
      
      ?//Student2?
      ?//a從偏移量為0位置開始?
      ?//b從偏移量為Student內(nèi)部最大成員整數(shù)倍開始,也就是8開始
      ?//c從8的整數(shù)倍地方開始,也就是32開始
      ?//所以結(jié)構(gòu)體Sutdnet2內(nèi)部對齊之后的大小為:40?,?由于結(jié)構(gòu)體中最大成員為8,必須為8的整數(shù)倍?所以大小為40
      ?printf("sizeof?Student2:%d\n",?sizeof(Student2));
      }
      

        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多