C Primer Plus--C存儲類、鏈接和內存管理之動態分配內存及類型限定詞

存儲類說明符

C中存儲類說明符共有5個,爲auto register static extern typeddef,最後一個關鍵字typedef與內存存儲無關。
規定:不可以在一個聲明中使用一個以上存儲類說明符
存儲類說明符用來確定變量的存儲類型。

存儲類和函數

函數的存儲類有兩種:

  • 外部
  • 靜態

在一個文件中定義的函數默認是外部的,也就是說其他文件可以調用它,只有使用static關鍵字修飾的函數纔是函數定義所在文件所私有的函數,通常用來解決不同文件函數之間的命名衝突。

double a();//默認聲明,函數a是外部的
extern int b();//此處顯式聲明b函數是在其他文件中定義的,可以省略。主要是爲了讓程序更清晰,除非函數聲明使用了關鍵字`static`,否則默認其爲`extern`的
static int c();//c函數只能在本文件中調用

動態分配內存

mallocfree函數原型存在於stdlib.h中。

malloc函數

在C中,一些數據的內存是由系統自動分配的,也允許程序主動要求分配。

int foo = 0;//系統自動分配內存空間用來存儲一個int
char string[] = "I love you.";//系統自動爲數組string分配正好裝下字符串的內存空間
int bar[10];//要求分配10個用來存儲int的內存空間

還可以手動分配內存。
extern void * malloc(unsigned int num_bytes)
函數malloc函數接受一個參數,該餐宿用於指定需要分配的內存字節數。malloc找到可用內存中一個區塊,並返回該區塊內存第一個字節的地址。它的void *返回值是一個通用指針,可以轉換爲其他指針類型。C中不要求強制轉換,但C++中要求強制轉換。如果malloc找不到符合要求的可用內存,它會返回空指針。例子:

double *p;
p = (double *)malloc(30 * sizeof(double));

例子中,分配了一塊內存用於存儲30個double類型數據,並將首字節地址賦值給了指針p

free函數

void free(void *p)
對應每個malloc函數調用,應該有對應的free調用來進行內存釋放。它的參數是之前malloc函數分配內存塊第一個字節的地址。也就是說分配的內存可用時間是從malloc執行結束開始到free釋放內存爲止。
例子:

#include <stdio.h>
#include <stdlib.h>

/*
 * test.c 編譯後產生可執行文件test.exe或test.out
 */


int main() {

    double *p;
    int max;
    int number;
    int i = 0;

    puts("What's the number of \"double\" entries?");
    while (scanf("%d",&max) != 1){
//        setbuf(stdin,NULL);
        scanf("%*s");
        puts("Please input a integer:");
    }

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

    p = (double *) malloc(max * sizeof(double));
    if (p == NULL){
        puts("Memory allocation has failed. Try to Restart this program.");
        exit(EXIT_FAILURE);
    }

    puts("Enter the values(q to quit): ");
    while (i < max && scanf("%lf",&p[i]) == 1)
        ++i;
    printf("Here are the number of entries: %d\n",number = i);
    for (int j = 0; j < number; ++j) {
        printf("%7.2f ",p[j]);
        if (j % 7 == 6)
            putchar('\n');
    }
    if (i % 7 !=0)
        putchar('\n');
    printf("i = %d\n",i);
    puts("Done.");
    free(p);
    return 0;
}

calloc函數

malloc類似,不同的是calloc可以指定要分配單元數目以及每個單元所需要的字節數。calloc會默認將內存塊中的各個位置0。
calloc分配的內存同樣需要用free函數來釋放。

動態分配內存的缺點

動態分配內存給了程序一定的自由,但是若是忘記釋放內存,那麼就會造成資源的浪費(內存泄漏)。而且相對於自動變量棧式管理,動態分配內存不是緊湊的連續分配,而是在內存中找合適的區塊,會造成內存碎片,拖慢速度。

C類型限定關鍵字

const定義全局常量

const定義常量之前已經做了筆記,看這裏。這裏我們來看它與全局常量的關係。
constant定義全局常量有兩種方式:
第一種方法:

//file1.c
const double PI = 3.14;

//file2.c
extern const double PI;

第二種:

//constant.h中定義常量,需要`static`關鍵字來修飾
static const double PI = 3.14;

//file1.c只需include 頭文件即可
#include "constant.h"

//file2.c
#include "cobnstant.h"

第二種方法中,file1.cfile2.c文件都包含了constant.h頭文件,那麼這兩個文件都會定義聲明一個本文件私有的靜態內部鏈接變量PI,其實是對constant.hPI值的拷貝。爲什麼必須要使用static關鍵字呢?因爲如果不使用的話同一個靜態外部鏈接變量就要在兩個文件中定義聲明兩次,而我們知道外部變量只允許定義聲明一次,其餘的都應該是引用聲明,定義兩次會造成標識符衝突,還不如直接加個static修飾,爲每個文件分別拷貝一個PI值給他們用。

volatile關鍵字

volatile告訴編譯器某個變量除了能被程序本身修改之外,還可以被超出程序之外的其他部分改變。假定,有一個變量的值記錄的是時間,那麼不管程序有沒有在運行,運行的如何,這個變量的值肯定是要隨着時間變化而變化的,那麼這個變量就應該加volatile修飾來提醒編譯器。再來個例子:

int x = 10;
int val1 = x;
int val2 = x;

編譯器注意到x變量被使用了兩次而沒有進行別的操作,那麼他可以將x的值臨時存儲在寄存器中,那麼當val2val1進行賦值操作時就會變快。但是,如果x的值可能被除了程序之外的部分改變,那麼就應該這樣:volatile int x = 10;來告訴編譯器這個變量可能會如此,那麼編譯器就不會做出將x值存於寄存器這樣的優化。一個變量既可以是constant,也可以是volatile的,因爲不能被程序改變的量爲常量,但可能被硬件改變,那麼就是volatile的。這與Java中的volatile關鍵字可不一樣。

restrict關鍵字

restrict關鍵字只能用來修飾指針,表示某個數據對象的唯一訪問方式就是該指針,方便編譯器優化。用法:
int * restrict foo = (int *) malloc(10 * sizeof(int))。這裏表明foo這個指針是數組的唯一訪問方式。

int array[4] = {};
int *p = array;

這裏就不能給prestrict限定詞,因爲array這個數組可以通過arrayp兩種方式進行訪問。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章