<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      C語言 -- sizeof總結

      sizeof的語法

      1:sizeof是C語言的關鍵字,用來計算變量、常量或數據類型在當前系統中占用內存的字節數。?
      2:sizeof不是函數,產生這樣的疑問是因為sizeof的書寫確實有點像函數。 在程序中,sizeof有兩種寫法:
      1)用于數據類型:sizeof(數據類型)

      2)用于變量名:sizeof(變量名);sizeof變置名 //不建議這樣使用

      代碼示例:

      #include<stdio.h>
      int main() {
      	int i;
      	char str[20];
      	printf("sizeof(i) is %d\n", sizeof(i));
      	printf("sizeof i is %d\n", sizeof i);
      	printf("sizeof int is %d\n", sizeof(int));
      	//printf("sizeof int is %d\n", sizeof int);錯誤寫法
      
      	printf("sizeof(str) is %d\n", sizeof(str));
      	printf("sizeof str is %d\n", sizeof str);
      	printf("sizeof str is %d\n", sizeof (char[20]));
      	//printf("sizeof str is %d\n", sizeof char[20]);錯誤寫法
      
      	printf("sizeof(365) is %d\n", sizeof(365));
      	printf("sizeof(i love you) is %d\n", sizeof("i love you"));
      }
      

      結果:

      注:最后一個字符串之所以是11,是因為在C語言中字符串后邊會默認添加一個結束符,也就是'\0'

      sizeof與strlen

      sizeof是運算符,用來計算變量、常量或數據類型在當前系統中占用內存的字節數

      strlen是函數,用于計算字符串的實際長度

      代碼示例:

      char ch[20];
      strcpy(ch, "i love you");
      printf("sizeof(ch) is %d\n", sizeof(ch));//地址長度20,不變
      printf("strlen(ch) is %d\n", strlen(ch));//字符串的實際長度,也就是i love you的長度,為10
      

      結構體內存對齊

      首先看一個例子:

      struct S
      {
      	char a;
      	int b;
      	char c;
      };

      我們先來計算一下這個結構體的大小,如果不存在內存對齊這個問題,按理說這個結構體應該占(1+4+1)6個字節;然而事實上它占了12個字節,為什么?我們需要解決下面幾個問題。

      1.為什么存在內存對齊

      • 平臺原因(移植問題):一些資料上是這樣說的,“不是所有的硬件平臺都能訪問任意地址上的任意數據;某些硬件平臺只能在某些特定地址處取某些特定的數據,否則就會拋出硬件異常”。也就是說在計算機在內存讀取數據時,只能在規定的地址處讀數據,而不是內存中任意地址都是可以讀取的。
      • 性能問題:正是由于只能在特定的地址處讀取數據,所以在訪問一些數據時,對于訪問未對齊的內存,處理器需要進行兩次訪問;而對于對齊的內存,只需要訪問一次就可以。

       

      看上面的圖,因為規定只能在特定地址處讀數據,所以我們假設只能在4的倍數的地址處讀數據,那么可以訪問的地址分別為0、4、8、12、16等,這時我們給出剛才的結構體,在處理器訪問第一個結構體元素(char) a 時,它會從0號下標的地址處訪問a,而下個結構體元素 b 為int型,它占了4個字節,很顯然,要訪問它時需要先從0號下標的地址開始訪問,之后還得取它后面3個字節的內容作為一部分,之后再從4號下標的地址處訪問1個字節(因為第一個字節被第一個元素占用了),共同的內容組成了元素 b ,很明顯,訪問 b 時要進行兩次訪問,并且很麻煩。這時如果存放數據時內存對齊了,則只需訪問一次就可以讀取到 b 的內容。第二幅圖就是內存對齊的情況,在訪問每個數據時,都可以一次性訪問完畢。

      2.內存對齊后,怎么計算結構體的大小

      1. 第一個成員在與結構體變量偏移量為0的地址處。
      2. 其他成員變量要對齊到某個數字(對齊數)的整數倍的地址處。對齊數=編譯器默認的一個對齊數與該成員大小的較小值,在VS環境下默認值為8,在Linux環境下默認值為4。
      3. 結構體的總大小為最大對齊數(每個成員變量都有一個對齊數)的整數倍。
      4. 如果嵌套了結構體的情況,被嵌套的結構體對齊到其自身對齊數的整數倍處(結構體的對齊數就是其內部成員中最大的對齊數),此時結構體的整體大小就是所有最大對齊數(含被嵌套結構體的對齊數)的整數倍。

      此時再看上邊的圖:

      利用這四個規則就可以計算結構體的大小。這時參照上面的圖中第二種情況來計算,對于上面的結構體,先定義了char類型的 a ,規則1說第一個元素在偏移量為0的地址處,即它對齊到0號地址處的位置,其占一個字節;第二個元素要對齊到自己對齊數的整數倍處,因為第二個元素的大小為int型,占4個字節,而VS默認對齊數是8,取最小的數,所以 b 的對齊數為4,規則2說要對其自身對齊數(4)的整數倍,而此時 a 占了一個字節,下個地址依次為2、 3 、4等,當走到4號地址處時,此時4能被4整除,所以第二個元素對齊在4號下標的地址處,占用4個字;接下來,第三個元素為char類型的 c ,c的大小為1,和8比較取小的數,所以 c 的對齊數為1,而此時 b 存放完之后的下個地址為9號地址,根據規則2,9是1的整數倍,所以 c 直接存放在9號開頭的地址處。接下來,計算它們的大小,分別為1(char)+3(偏移量)+4(int)+1(char)=9,而正確的結果為12,原因在于規則3,規則3規定結構體的總大小為最大對齊數的整數倍,上面的3個元素中,它們的對齊數分別為0、4、1。所以最大對齊數為4,而結構體大小要整除最大對齊數,剛才計算出結構體的大小為9,很明顯不能整除,所以結構體的大小為1(char)+3(偏移量)+4(int)+1(char)+3(偏移量)=12。

      再來看第二個例子:

      struct S1
      {
      	char c1;
      	char c2;
      	int i;
      };
      struct S2
      {
      	char c1;
      	struct S1 s3;
      	double d;
      };

      首先計算出結構體S1的大小為1(char)+1(char)+2(偏移量)+4(int)=8,S1的對齊數就是其結構體成員中最大的對齊數,即4,在結構體S2中,對齊數分別是0、4、8;首先 c1 對齊在0號地址的位置,其占用1個字節,根據規則4,嵌套的結構體S1要對齊到自身對齊數4的整數倍處,所以此時結構體對其在4號地址處,其大小是8個字節,之后,d 的對齊數為8,所以它要對齊到16號地址處,所以此時計算出S2的大小是1(char)+3(偏移量)+8(struct S1)+4(偏移量)+8(double)=24,結構體S2中個成員的對齊數分別為0、4、8,因為24是8的倍數,符合規則4。所以S2的總大小就是24個字節。

      #pragma pack(n) 表示設置為n字節對齊。

      sizeof易錯點

      先看一段代碼:

      #include<stdio.h>
      #include<string.h>
      struct student {
      	char name[20];
      	int age;
      	int ID;
      	char add[300];
      };
      int main() {
      	char str[21];
      	struct student stu;
      
      	memset(str, 0, sizeof(str));
      	memset(&stu, 0, sizeof(stu));
      }

      上邊代碼主要就是對一個字符數組和一個結構體進行初始化,但是有時候我們可能需要將初始化那兩行代碼給封裝起來,如下:

      struct student {
      	char name[20];
      	int age;
      	int ID;
      	char add[300];
      };
      //初始化數據
      void InitData(char *str,struct student *stu) {
      	memset(str, 0, sizeof(str));
      	memset(&stu, 0, sizeof(stu));
      }
      int main() {
      	char str[21];
      	struct student stu;
      	InitData(str, &stu);
      }
      

      但是這樣是有問題的

      我們可以走一個測試,在main函數里輸出字符串和結構體的長度和在初始化函數里輸出字符串和結構體的長度,如下:

      struct student {
      	char name[20];
      	int age;
      	int ID;
      	char add[300];
      };
      //初始化數據
      void InitData(char *str,struct student *stu) {
      	//memset(str, 0, sizeof(str));
      	//memset(&stu, 0, sizeof(stu));
      
      	printf("sizeof(str) is %d\n", sizeof(str));
      	printf("sizeof(stu) is %d\n", sizeof(stu));
      }
      int main() {
      	char str[21];
      	struct student stu;
      
      	printf("sizeof(str) is %d\n", sizeof(str));
      	printf("sizeof(stu) is %d\n", sizeof(stu));
      
      	printf("\n");
      	InitData(str, &stu);
      }
      

      輸出:

      可以看到,在main函數里輸出的分別是21和328,也就是字符串str和結構體student的長度,但是在初始化函數里輸出的都是8,這是為什么呢?

      我們可以回到sizeof的定義,它是用來計算變量、常量或數據類型在當前系統中占用內存的字節數,在main函數里計算的就是字符串類型的結構類型的字節數,而在初始化函數里計算的都是指針類型所占的字節數,在64位操作系統中,指針都是占8位,所以輸出的都是8,如果出現這樣的錯誤后果會非常嚴重,可能會造成內存泄漏的問題。

      那么我們怎么在初始化函數中初始化我們的成員呢?

      首先,在處理字符串這種情況,我們可以在main函數中將字符串的長度傳進去,如果只傳一個字符串的地址,那么子函數不知道該字符串的長度,所以就無法完成初始化

      那么對于結構體如何處理的呢?這里可以養成一個良好習慣,就是對結構體進行初始化時候,直接用數據類型,不要用變量名。

      代碼示例如下:

      #include<stdio.h>
      #include<stdlib.h>
      #include<string.h>
      struct student {
      	char name[20];
      	int age;
      	int ID;
      	char add[300];
      };
      void InitData(char *pstr, int length, struct student *stu);
      int main() {
      	char str[21];
      	struct student stu;
      
      	printf("sizeof(str) is %d\n", sizeof(str));
      	printf("sizeof(stu) is %d\n", sizeof(stu));
      
      	printf("\n");
      	InitData(str, sizeof(str), &stu);
      
      }
      //初始化數據
      void InitData(char *pstr, int length, struct student *stu) {
      	memset(pstr, 0, length);
      	memset(stu, 0, sizeof(struct student));
      }
      

      這樣就可以調用初始化函數,將主函數的字符串和結構體進行初始化。

      posted @ 2020-12-06 12:37  初晨~  閱讀(2503)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 高清自拍亚洲精品二区| 亚洲精品麻豆一区二区| 成人欧美日韩一区二区三区| 丁香花成人电影| 欧美不卡无线在线一二三区观| 欧美大香线蕉线伊人久久| 久久国内精品自在自线91| 亚洲精品视频一二三四区| caoporn免费视频公开| 国产欧美精品一区aⅴ影院| 国产乱精品一区二区三区| 亚洲精品国产中文字幕| 99久re热视频这里只有精品6| 少妇熟女天堂网av| 不卡乱辈伦在线看中文字幕| 狠狠躁夜夜躁无码中文字幕| 91久久国产成人免费观看| 久久国产成人高清精品亚洲| 国产免费久久精品44| 欧美高清freexxxx性| 国产一区二区三区导航| 激情亚洲一区国产精品| 午夜精品一区二区三区成人| 亚洲精品一区三区三区在| 亚洲欧美日韩愉拍自拍| 中文字幕av一区| 无码精品人妻一区二区三区中| 黄瓜视频在线观看| 亚洲最大激情中文字幕| 国产精品午夜福利精品| 在线无码av一区二区三区| 91精品亚洲一区二区三区| av午夜福利一片免费看久久| 亚洲日本欧美日韩中文字幕| 精品国产一区二区亚洲人| 国产精品亚洲二区在线播放| 国产免费爽爽视频| 国产国拍精品av在线观看| 又黄又硬又湿又刺激视频免费| 乌拉特后旗| 国产在线啪|