內存管理+內存佈局

內存管理程序員

8.1 做用域數組

C語言變量的做用域分爲:函數

l  代碼塊做用域(代碼塊是{}之間的一段代碼)佈局

l  函數做用域測試

l  文件做用域spa

8.1.1 局部變量操作系統

局部變量也叫auto自動變量(auto可寫可不寫),通常狀況下代碼塊{}內部定義的變量都是自動變量,它有以下特色:指針

l  在一個函數內定義,只在函數範圍內有效code

l  在複合語句中定義,只在複合語句中有效對象

l  隨着函數調用的結束或複合語句的結束局部變量的聲明聲明週期也結束

l  若是沒有賦初值,內容爲隨機

 1 #include <stdio.h>
 2 
 3  
 4 
 5 void test()
 6 
 7 {
 8 
 9        //auto寫不寫是同樣的
10 
11        //auto只能出如今{}內部
12 
13        auto int b = 10;
14 
15 }
16 
17  
18 
19 int main(void)
20 
21 {
22 
23        //b = 100; //err, 在main做用域中沒有b
24 
25  
26 
27        if (1)
28 
29        {
30 
31               //在複合語句中定義,只在複合語句中有效
32 
33               int a = 10;
34 
35               printf("a = %d\n", a);
36 
37        }
38 
39  
40 
41        //a = 10; //err離開if()的複合語句,a已經不存在
42 
43       
44 
45        return 0;
46 
47 }
48 
49  

 

8.1.2 靜態(static)局部變量

l  static局部變量的做用域也是在定義的函數內有效

l  static局部變量的生命週期和程序運行週期同樣,同時staitc局部變量的值只初始化一次,但能夠賦值屢次

l  static局部變量若未賦以初值,則由系統自動賦值:數值型變量自動賦初值0,字符型變量賦空字符

 

 1 #include <stdio.h>
 2 
 3  
 4 
 5 void fun1()
 6 
 7 {
 8 
 9        int i = 0;
10 
11        i++;
12 
13        printf("i = %d\n", i);
14 
15 }
16 
17  
18 
19 void fun2()
20 
21 {
22 
23        //靜態局部變量,沒有賦值,系統賦值爲0,並且只會初始化一次
24 
25        static int a;
26 
27        a++;
28 
29        printf("a = %d\n", a);
30 
31 }
32 
33  
34 
35 int main(void)
36 
37 {
38 
39        fun1();
40 
41        fun1();
42 
43        fun2();
44 
45        fun2();
46 
47       
48 
49        return 0;
50 
51 }

 

 

8.1.3 全局變量

l  在函數外定義,可被本文件及其它文件中的函數所共用,若其它文件中的函數調用此變量,須用extern聲明

l  全局變量的生命週期和程序運行週期同樣

l  不一樣文件的全局變量不可重名

 

8.1.4 靜態(static)全局變量

l  在函數外定義,做用範圍被限制在所定義的文件中

l  不一樣文件靜態全局變量能夠重名,但做用域不衝突

l  static全局變量的生命週期和程序運行週期同樣,同時staitc全局變量的值只初始化一次

 

8.1.5 extern全局變量聲明

extern int a;聲明一個變量,這個變量在別的文件中已經定義了,這裏只是聲明,而不是定義。

 

8.1.6 全局函數和靜態函數

在C語言中函數默認都是全局的,使用關鍵字static能夠將函數聲明爲靜態,函數定義爲static就意味着這個函數只能在定義這個函數的文件中使用,在其餘文件中不能調用,即便在其餘文件中聲明這個函數都沒用。

 

對於不一樣文件中的staitc函數名字能夠相同。

 

注意:

l  容許在不一樣的函數中使用相同的變量名,它們表明不一樣的對象,分配不一樣的單元,互不干擾。

l  同一源文件中,容許全局變量和局部變量同名,在局部變量的做用域內,全局變量不起做用。

l  全部的函數默認都是全局的,意味着全部的函數都不能重名,但若是是staitc函數,那麼做用域是文件級的,因此不一樣的文件static函數名是能夠相同的。

 

8.1.7 總結

類型

做用域

生命週期

auto變量

一對{}內

當前函數

static局部變量

一對{}內

整個程序運行期

extern變量

整個程序

整個程序運行期

static全局變量

當前文件

整個程序運行期

extern函數

整個程序

整個程序運行期

static函數

當前文件

整個程序運行期

register變量

一對{}內

當前函數

 

8.2 內存佈局

8.2.1 內存分區

C代碼通過預處理、編譯、彙編、連接4步後生成一個可執行程序。

在 Linux 下,程序是一個普通的可執行文件,如下列出一個二進制可執行文件的基本狀況:

 

 

經過上圖能夠得知,在沒有運行程序前,也就是說程序沒有加載到內存前,可執行程序內部已經分好3段信息,分別爲代碼區(text)、數據區(data)和未初始化數據區(bss)3 個部分(有些人直接把data和bss合起來叫作靜態區或全局區)。

 

l  代碼區

存放 CPU 執行的機器指令。一般代碼區是可共享的(即另外的執行程序能夠調用它),使其可共享的目的是對於頻繁被執行的程序,只須要在內存中有一份代碼便可。代碼區一般是隻讀的,使其只讀的緣由是防止程序意外地修改了它的指令。另外,代碼區還規劃了局部變量的相關信息。

 

l  全局初始化數據區/靜態數據區(data段)

該區包含了在程序中明確被初始化的全局變量、已經初始化的靜態變量(包括全局靜態變量和局部靜態變量)和常量數據(如字符串常量)。

 

l  未初始化數據區(又叫 bss 區)

存入的是全局未初始化變量和未初始化靜態變量。未初始化數據區的數據在程序開始執行以前被內核初始化爲 0 或者空(NULL)。

 

程序在加載到內存前,代碼區和全局區(data和bss)的大小就是固定的,程序運行期間不能改變。而後,運行可執行程序,系統把程序加載到內存,除了根據可執行程序的信息分出代碼區(text)、數據區(data)和未初始化數據區(bss)以外,還額外增長了棧區、堆區。

 

 

 

l  代碼區(text segment)

加載的是可執行文件代碼段,全部的可執行代碼都加載到代碼區,這塊內存是不能夠在運行期間修改的。

 

l  未初始化數據區(BSS)

加載的是可執行文件BSS段,位置能夠分開亦能夠緊靠數據段,存儲於數據段的數據(全局未初始化,靜態未初始化數據)的生存週期爲整個程序運行過程。

 

l  全局初始化數據區/靜態數據區(data segment)

加載的是可執行文件數據段,存儲於數據段(全局初始化,靜態初始化數據,文字常量(只讀))的數據的生存週期爲整個程序運行過程。

 

l  棧區(stack)

棧是一種先進後出的內存結構,由編譯器自動分配釋放,存放函數的參數值、返回值、局部變量等。在程序運行過程當中實時加載和釋放,所以,局部變量的生存週期爲申請到釋放該段棧空間。

 

l  堆區(heap)

堆是一個大容器,它的容量要遠遠大於棧,但沒有棧那樣先進後出的順序。用於動態內存分配。堆在內存中位於BSS區和棧區之間。通常由程序員分配和釋放,若程序員不釋放,程序結束時由操做系統回收。

 

8.2.2 存儲類型總結

類型

做用域

生命週期

存儲位置

auto變量

一對{}內

當前函數

棧區

static局部變量

一對{}內

整個程序運行期

初始化在data段,未初始化在BSS段

extern變量

整個程序

整個程序運行期

初始化在data段,未初始化在BSS段

static全局變量

當前文件

整個程序運行期

初始化在data段,未初始化在BSS段

extern函數

整個程序

整個程序運行期

代碼區

static函數

當前文件

整個程序運行期

代碼區

register變量

一對{}內

當前函數

運行時存儲在CPU寄存器

字符串常量

當前文件

整個程序運行期

data段

 

 1 #include <stdio.h>
 2 
 3 #include <stdlib.h>
 4 
 5  
 6 
 7 int e;
 8 
 9 static int f;
10 
11 int g = 10;
12 
13 static int h = 10;
14 
15 int main()
16 
17 {
18 
19        int a;
20 
21        int b = 10;
22 
23        static int c;
24 
25        static int d = 10;
26 
27        char *i = "test";
28 
29        char *k = NULL;
30 
31  
32 
33        printf("&a\t %p\t //局部未初始化變量\n", &a);
34 
35        printf("&b\t %p\t //局部初始化變量\n", &b);
36 
37  
38 
39        printf("&c\t %p\t //靜態局部未初始化變量\n", &c);
40 
41        printf("&d\t %p\t //靜態局部初始化變量\n", &d);
42 
43  
44 
45        printf("&e\t %p\t //全局未初始化變量\n", &e);
46 
47        printf("&f\t %p\t //全局靜態未初始化變量\n", &f);
48 
49  
50 
51        printf("&g\t %p\t //全局初始化變量\n", &g);
52 
53        printf("&h\t %p\t //全局靜態初始化變量\n", &h);
54 
55  
56 
57        printf("i\t %p\t //只讀數據(文字常量區)\n", i);
58 
59  
60 
61        k = (char *)malloc(10);
62 
63        printf("k\t %p\t //動態分配的內存\n", k);
64 
65  
66 
67        return 0;
68 
69 }
70 
71  

 

8.2.3 存儲類型總結內存操做函數

1) memset()

#include <string.h>

void *memset(void *s, intc, size_tn);

功能:將s的內存區域的前n個字節以參數c填入

參數:

       s:須要操做內存s的首地址

       c:填充的字符,c雖然參數爲int,但必須是unsigned char , 範圍爲0~255

       n:指定須要設置的大小

返回值:s的首地址

 

 1        int a[10];
 2 
 3  
 4 
 5        memset(a, 0, sizeof(a));
 6 
 7        memset(a, 97, sizeof(a));
 8 
 9        int i = 0;
10 
11        for (i = 0; i < 10; i++)
12 
13        {
14 
15               printf("%c\n", a[i]);
16 
17        }

 

 

2) memcpy()

#include <string.h>

void *memcpy(void *dest, constvoid *src, size_tn);

功能:拷貝src所指的內存內容的前n個字節到dest所值的內存地址上。

參數:

       dest:目的內存首地址

       src:源內存首地址,注意:dest和src所指的內存空間不可重疊

       n:須要拷貝的字節數

返回值:dest的首地址

 

       int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

       int b[10];

      

       memcpy(b, a, sizeof(a));

       int i = 0;

       for (i = 0; i < 10; i++)

       {

              printf("%d, ", b[i]);

       }

       printf("\n");

 

       //memcpy(&a[3], a, 5 * sizeof(int)); //err, 內存重疊

 

3) memmove()

memmove()功能用法和memcpy()同樣,區別在於:dest和src所指的內存空間重疊時,memmove()仍然能處理,不過執行效率比memcpy()低些。

 

4) memcmp()

#include <string.h>

intmemcmp(constvoid *s1, constvoid *s2, size_tn);

功能:比較s1和s2所指向內存區域的前n個字節

參數:

       s1:內存首地址1

       s2:內存首地址2

       n:需比較的前n個字節

返回值:

       相等:=0

       大於:>0

       小於:<0

 

       int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

       int b[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

 

       int flag = memcmp(a, b, sizeof(a));

       printf("flag = %d\n", flag);

 

8.2.4 堆區內存分配和釋放

1)malloc()

#include <stdlib.h>

void *malloc(size_tsize);

功能:在內存的動態存儲區(堆區)中分配一塊長度爲size字節的連續區域,用來存放類型說明符指定的類型。分配的內存空間內容不肯定,通常使用memset初始化。

參數:

       size:須要分配內存大小(單位:字節)

返回值:

成功:分配空間的起始地址

失敗:NULL

 

 1 #include <stdlib.h>
 2 
 3 #include <stdio.h>
 4 
 5 #include <string.h>
 6 
 7  
 8 
 9 int main()
10 
11 {
12 
13        int count, *array, n;
14 
15        printf("請輸入要申請數組的個數:\n");
16 
17        scanf("%d", &n);
18 
19  
20 
21        array = (int *)malloc(n * sizeof (int));
22 
23        if (array == NULL)
24 
25        {
26 
27               printf("申請空間失敗!\n");
28 
29               return -1;
30 
31        }
32 
33        //將申請到空間清0
34 
35        memset(array, 0, sizeof(int)*n);
36 
37  
38 
39        for (count = 0; count < n; count++) /*給數組賦值*/
40 
41               array[count] = count;
42 
43  
44 
45        for (count = 0; count < n; count++) /*打印數組元素*/
46 
47               printf("%2d", array[count]);
48 
49  
50 
51        free(array);
52 
53  
54 
55        return 0;
56 
57 }
58 
59  

 

2)free()

#include <stdlib.h>

voidfree(void *ptr);

功能:釋放ptr所指向的一塊內存空間,ptr是一個任意類型的指針變量,指向被釋放區域的首地址。對同一內存空間屢次釋放會出錯。

參數:

ptr:須要釋放空間的首地址,被釋放區應是由malloc函數所分配的區域。

返回值:無

 

8.3 內存分區代碼分析(在Linux下測試)

1) 返回棧區地址

 1 #include <stdio.h>
 2 
 3 int a = 10;
 4 
 5 int *fun()
 6 
 7 {
 8 
 9       
10 
11        return &a;//函數調用完畢,a釋放
12 
13 }
14 
15  
16 
17 int main(int argc, char *argv[])
18 
19 {
20 
21        int *p = NULL;
22 
23        p = fun();
24 
25        *p = 100; //操做野指針指向的內存,err
26 
27  
28 
29        return 0;
30 
31 }
32 
33  
34 
35 2) 返回data區地址
36 
37 #include <stdio.h>
38 
39  
40 
41 int *fun()
42 
43 {
44 
45        static int a = 10;
46 
47        return &a; //函數調用完畢,a不釋放
48 
49 }
50 
51  
52 
53 int main(int argc, char *argv[])
54 
55 {
56 
57        int *p = NULL;
58 
59        p = fun();
60 
61        *p = 100; //ok
62 
63        printf("*p = %d\n", *p);
64 
65  
66 
67        return 0;
68 
69 }

 

 

3) 值傳遞1

 1 #include <stdio.h>
 2 
 3 #include <stdlib.h>
 4 
 5  
 6 
 7 void fun(int *tmp)
 8 
 9 {
10 
11        tmp = (int *)malloc(sizeof(int));
12 
13        *tmp = 100;
14 
15 }
16 
17  
18 
19 int main(int argc, char *argv[])
20 
21 {
22 
23        int *p = NULL;
24 
25        fun(p); //值傳遞,形參修改不會影響實參
26 
27        printf("*p = %d\n", *p);//err,操做空指針指向的內存
28 
29  
30 
31        return 0;
32 
33 }
34 
35  
36 
37 4) 值傳遞2
38 
39 #include <stdio.h>
40 
41 #include <stdlib.h>
42 
43  
44 
45 void fun(int *tmp)
46 
47 {
48 
49        *tmp = 100;
50 
51 }
52 
53  
54 
55 int main(int argc, char *argv[])
56 
57 {
58 
59        int *p = NULL;
60 
61        p = (int *)malloc(sizeof(int));
62 
63  
64 
65        fun(p); //值傳遞
66 
67        printf("*p = %d\n", *p); //ok,*p爲100
68 
69  
70 
71        return 0;
72 
73 }

 

 

5) 返回堆區地址

 1 #include <stdio.h>
 2 
 3 #include <stdlib.h>
 4 
 5  
 6 
 7 int *fun()
 8 
 9 {
10 
11        int *tmp = NULL;
12 
13        tmp = (int *)malloc(sizeof(int));
14 
15        *tmp = 100;
16 
17        return tmp;//返回堆區地址,函數調用完畢,不釋放
18 
19 }
20 
21  
22 
23 int main(int argc, char *argv[])
24 
25 {
26 
27        int *p = NULL;
28 
29        p = fun();
30 
31        printf("*p = %d\n", *p);//ok
32 
33  
34 
35        //堆區空間,使用完畢,手動釋放
36 
37        if (p != NULL)
38 
39        {
40 
41               free(p);
42 
43               p = NULL;
44 
45        }
46 
47  
48 
49        return 0;
50 
51 }

 內存操做函數

  1 #define _CRT_SECURE_NO_WARNINGS
  2 #include<stdio.h>
  3 #include<string.h>
  4 #include<stdlib.h>
  5 
  6 int main1501()
  7 {
  8     //int * p = (int *)malloc(sizeof(int) * 10);
  9     ////參數:目標 值 字節大小
 10     //memset(p, 0, 40);
 11     //for (int i = 0; i < 10; i++)
 12     //{
 13     //    printf("%d\n", p[i]);
 14     //}
 15     //char * p = malloc(sizeof(char) * 10);
 16     //memset(p, 0, 10);
 17     //printf("%s\n", p);
 18 
 19 
 20     int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
 21     memset(arr, 0, 40);
 22     for (int i = 0; i < 10; i++)
 23     {
 24         printf("%d\n", arr[i]);
 25     }
 26 
 27     //free(p);
 28     //system("pause");
 29     return EXIT_SUCCESS;
 30 }
 31 int main1502()
 32 {
 33     int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
 34     //int *p = malloc(sizeof(int) * 10);
 35     //memcpy(p, arr, 40);
 36     //for (int i = 0; i < 10; i++)
 37     //{
 38     //    printf("%d\n", p[i]);
 39     //}
 40 
 41     //free(p);
 42 
 43     memcpy(&arr[2], arr, 20);
 44     for (int i = 0; i < 10; i++)
 45     {
 46         printf("%d\n", arr[i]);
 47     }
 48     char arr1[] = { 'h','e','l','l','o' };
 49     char * p = malloc(100);
 50     memset(p, 0, 100);
 51     //一、函數參數不一樣
 52     //二、strcpy拷貝字符串 memcpy 能夠拷貝一塊內存
 53     //三、拷貝結束標誌不一樣 strcpy \0 memcpy  以個數爲結尾
 54     strcpy(p, arr1);
 55     memcpy(p, arr1, 5);
 56     printf("%s\n", p);
 57     free(p);
 58     return 0;
 59 }
 60 
 61 int main1503()
 62 {
 63     int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
 64     //memmove拷貝重疊內存地址不會出現問題  可是效率比較低   若是拷貝源和拷貝目標沒有重疊  兩個函數效率同樣
 65     memmove(&arr[2], arr, 20);
 66 
 67     for (int i = 0; i < 10; i++)
 68     {
 69         printf("%d\n", arr[i]);
 70     }
 71 }
 72 int main()
 73 {
 74     //int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
 75     //int arr2[5] = { 1,2,3,4 };
 76 
 77     //int val = memcmp(arr1, arr2, 20);
 78     //if (!memcmp(arr1, arr2, 8))
 79     //{
 80     //    printf("前兩個數組元素內容相同");
 81     //}
 82     //printf("%d\n", val);
 83 
 84     //int * p1 = malloc(sizeof(int) * 10);
 85     //char * p2 = malloc(sizeof(char) * 40);
 86 
 87     //memcpy(p1, "hello", 6);
 88     //memcpy(p2, "hello", 6);
 89     //if (!memcmp(p1, p2, 6))
 90     //{
 91     //    printf("內容相同\n");
 92     //}
 93     //else
 94     //{
 95     //    printf("內容不相同\n");
 96 
 97     //}
 98 
 99     int a = 0xffff;
100     char b = 0xffff;
101     //printf("%d\n", b);
102     if (!memcmp(&a, &b, 2))
103     {
104         printf("內容相同\n");
105     }
106     else
107     {
108         printf("內容不相同\n");
109 
110     }
111 
112     //free(p1);
113     //free(p2);
114     //練習   求出三名學生 三門功課成績 並排序   經過堆空間來實現  arr[3][3];
115     int ** p = (int **)malloc(sizeof(int *) * 3);
116     p[0] = (int *)malloc(sizeof(int) * 3);
117     p[1] = (int *)malloc(sizeof(int) * 3);
118     p[2] = (int *)malloc(sizeof(int) * 3);
119 
120     p[0][0] = 90;
121     p[0][1] = 80;
122     p[0][2] = 70;
123 
124     //排序
125 
126     free(p[0]);
127     free(p[1]);
128     free(p[2]);
129 
130     free(p);
131 
132 
133     return 0;
134 }

堆空間開闢數組冒泡排序

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<stdlib.h>
 5 #include <time.h>
 6 
 7 #define MAX 10
 8 
 9 int main()
10 {
11     srand((unsigned int)time(NULL));
12     int * p = (int *)malloc(sizeof(int) * MAX);
13     //int len = sizeof(p) 
14     for (int i = 0; i < MAX; i++)
15     {
16         //*(p + i) = rand() % 50;
17         p[i] = rand() % 50;
18         //*p++ = rand() % 50;
19     }
20     for (int i = 0; i < MAX; i++)
21     {
22         printf("排序前:\n");
23         printf("%d\n", p[i]);
24     }
25     for (int i = 0; i < MAX - 1; i++)
26     {
27         for (int j = 0; j < MAX - i - 1; j++)
28         {
29             if (p[j] > p[j + 1])
30             {
31                 int temp = p[j];
32                 p[j] = p[j + 1];
33                 p[j + 1] = temp;
34             }
35         }
36     }
37     printf("排序前:\n");
38 
39     for (int i = 0; i < MAX; i++)
40     {
41         printf("%d\n", p[i]);
42     }
43     free(p);
44 
45 
46     system("pause");
47     return EXIT_SUCCESS;
48 }

 

相關文章
相關標籤/搜索