最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

C語言存儲類別、鏈接和內(nèi)存管理

2023-01-30 18:24 作者:虛云幻仙  | 我要投稿

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

#include <string.h>

#include "diceroll.h" // 包含的頭文件如果是C標準庫的,需要使用<>告訴編譯器去標準庫中查找,如果是用戶定義的,需要使用""告訴編譯器去IDE指定的用戶存放頭文件的區(qū)域查找


int mode; // 將變量定義在函數(shù)外面,變量具有文件作用域,變量mode對當(dāng)前翻譯單元(當(dāng)前文件和include包含的所有文件的總和稱為翻譯單元)內(nèi),當(dāng)前聲明語句之后的所有函數(shù)可見

double distance; // 變量distance可以描述為文件作用域,靜態(tài)存儲期(在編譯時分配內(nèi)存,并在程序運行過程中一直保留這塊內(nèi)存),外部鏈接(在當(dāng)前程序的其他翻譯單元中可以引用該變量,翻譯單元即由.c源文件和文件中包含的頭文件等的總和,程序如果由多個源文件組成會形成多個翻譯單元),靜態(tài)變量如果沒有顯式初始化則會將所有位初始化為0(在某些硬件系統(tǒng)中浮點數(shù)的0不是所有位都為0)

static double fuel; // 對文件作用域的變量使用static修飾,將變量定義為內(nèi)部鏈接,內(nèi)部鏈接只對當(dāng)前翻譯單元可見,其他翻譯單元不能引用

extern int sets; // 使用extern,引用式聲明,告訴編譯器去其他地方(包括當(dāng)前文件的上下文)尋找sets,這里sets的定義式聲明在別的翻譯單元中,當(dāng)前翻譯單元想要使用同一個變量則必須要extern引用

void critic(void); // 函數(shù)原型默認extern引用,函數(shù)也具有文件作用域

void critic2(int* ptr); //函數(shù)原型作用域用于函數(shù)原型中的形參/變量名,作用域范圍從定義處到原型聲明結(jié)束,所以除了變長數(shù)組之外,形參名可以省略,簡寫為void critic2(int*); 函數(shù)定義時必須有形參名,且函數(shù)定義的形參名可以和函數(shù)原型中的不同

void set_mode(int p_mode);

void get_info(void);

void show_info(void);

int invoke_count(void);

void random_array(void);

void array_sort(int* arr, int len);

void test_random(void);

static void dice_game(void); // 將函數(shù)聲明為內(nèi)部鏈接,文件/翻譯單元私有

int* dynamic_make_array(int size, int init);

void dynamic_show_array(int* arr, int size);

void words(void);

void others(void);

int main(void)

{

???? words();

???? return 0; //C規(guī)定main()函數(shù)的return 0和exit(EXIT_SUCCESS)作用相同,0代表成功運行

}

void critic(void)

{

???? auto int units = 0; // 一般在花括號{}內(nèi)聲明的變量和函數(shù)形參內(nèi)的變量都默認auto,自動存儲期,指程序在執(zhí)行到當(dāng)前函數(shù)才會分配內(nèi)存給變量(存儲在棧中),并且在函數(shù)結(jié)束時釋放內(nèi)存,當(dāng)前變量的標識符為units,程序通過該標識符訪問內(nèi)存塊,在C語言中這個內(nèi)存塊稱為對象(不同于面向?qū)ο笳Z言的對象),變量units可以被描述為自動存儲期、塊作用域(花括號{}內(nèi)的區(qū)域被稱為塊)、無鏈接(塊作用域以外不可見,除了傳參/返回之外無法引用)

???? //雖然units的內(nèi)存在程序執(zhí)行到當(dāng)前函數(shù)時就已分配,但只對當(dāng)前塊內(nèi)在units的聲明語句下面的區(qū)域可見,自動存儲器的變量在聲明時如果不手動進行初始化則該內(nèi)存塊仍然保留著之前該區(qū)域的垃圾值

???? printf("How many pounds to a firkin of butter?\n");

???? scanf("%d", &units);

???? while (units!=56)

???? {

???? ????critic2(&units);

???? }

???? printf("You must have looked it up!\n");

}

void critic2(int* ptr) { // 函數(shù)頭的普通變量也是自動存儲期、塊作用域、無鏈接

???? printf("No luck, my friend. Try again.\n");

???? scanf("%d", ptr);

} // 離開critic2函數(shù)會釋放變量ptr的內(nèi)存,即&ptr地址的內(nèi)存塊,這不影響主調(diào)函數(shù)的&units

void set_mode(int p_mode) {

???? // 如果形參也命名為mode會蓋住前面定義的靜態(tài)變量mode,使靜態(tài)變量mode對當(dāng)前函數(shù)不可見

???? extern int mode; // 引用式聲明,靜態(tài)變量mode對當(dāng)前翻譯單元所有函數(shù)可見,所以不需要這一句聲明也可以調(diào)用變量,引用式聲明不可以初始化,只有定義式聲明可以初始化

???? switch (p_mode)

???? {

???????? case 1:

???????????? mode = 1;

???????????? break;

???????? case 0:

???????????? mode = 0;

???????????? break;

???????? default:

???????????? printf("Invalid mode specified. Mode %s used.\n", mode ? "1(US)" : "0(metric)");

???? }

}

void get_info(void) {

???? printf("Enter distance traveled in %s:", mode ? "miles" : "kilometers");

???? scanf("%lf", &distance);

???? printf("Enter fuel consumed in %s:", mode ? "gallons" : "liters");

???? scanf("%lf", &fuel);

}

void show_info(void) {

???? if(mode)

???????? printf("Fuel consumption is %.2f miles per gallon.\n",distance / fuel);

???? else

???????? printf("Fuel consumption is %.2f liters per 100 km.\n", fuel / distance * 100);


}

int invoke_count(void) { // 記錄函數(shù)被調(diào)用的次數(shù)

???? static int invoke_c; // 聲明靜態(tài)存儲期的塊作用域無鏈接變量,靜態(tài)變量invoke_c會在編譯階段分配內(nèi)存,在程序運行時一直存在,所以實際函數(shù)調(diào)用時會跳過這個語句,靜態(tài)變量在程序一開始執(zhí)行就存在,沒有顯式初始化則初始化為0

???? invoke_c++; //靜態(tài)變量在程序運行時一直存在,所以該值會不斷遞增。塊作用域使其只對當(dāng)前函數(shù)可見,函數(shù)私有,無鏈接使其不能被extern引用

???? return invoke_c;

}

void random_array(void) {

???? int arr[100];

???? srand(time(0)); //time()函數(shù)在time.h頭文件中,傳入指向time_t類型的指針,返回當(dāng)前時間戳并將該值也存到傳入的指針指向的對象上,傳入NULL或0省略指針賦值,srand()接收unsigned int類型作為隨機數(shù)的種子,傳入time_t類型可能發(fā)生截斷

???? for (int i = 0; i < 100; i++) //for循環(huán)的()為函數(shù)的語句塊的子塊,在子塊中聲明的變量的作用域也為子塊,所以for循環(huán)結(jié)束之后會釋放i的內(nèi)存

???? { // for循環(huán)的循環(huán)體{}為for循環(huán)的()的子塊,如果在{}內(nèi)再聲明一個int i,會蓋住()中i,當(dāng)單次循環(huán)結(jié)束離開{}進入()判定時依然是以()中聲明的i來判定

???? ????arr[i] = rand() % 10 + 1; //rand()生成隨機數(shù),范圍0-RAND_MAX,%10是0-9,+1是1-10

???? }

???? array_sort(arr, 100);

???? for (int i = 0; i < 100; i++)

???? {

???? ????printf(" %d,", arr[i]);

???? }

???? putchar('\n');

}

void array_sort(int* arr, int len) { // 使用歸并排序

???? if (len<2)

???? return;

???? int mid = len / 2;

???? array_sort(arr, mid);

???? array_sort(arr+mid, len-mid);

???? int* ptr = (int*)malloc(len * sizeof(int)); // malloc(size_t size)函數(shù)動態(tài)分配內(nèi)存,即在程序運行中,在執(zhí)行到malloc()函數(shù)時根據(jù)傳參的大小分配內(nèi)存塊,返回內(nèi)存塊的地址,類型為void*即指向void的指針,該類型相當(dāng)于一個通用指針,通過(int*)強轉(zhuǎn),動態(tài)分配的內(nèi)存需要通過free()函數(shù)來釋放,不會自動釋放

???? // 通過len*sizeof(int)生成存放len個int元素的空間

???? // malloc()如果分配內(nèi)存失敗,會返回NULL

???? if (ptr==NULL)

???? {

???????? printf("動態(tài)分配失敗");

???????? exit(EXIT_FAILURE);

???? }

???? int r, l,i;

???? for ( i=l = 0,r=mid; l < mid&&r<len;)

???? ????ptr[i++] = arr[l] > arr[r] ? arr[l++] : arr[r++];

???? while (l<mid)

???? ????ptr[i++] = arr[l++];

???? while (r<len)

???? ????ptr[i++] = arr[r++];

???? for ( i = 0; i < len; i++)

???? ????arr[i] = ptr[i];

???? free(ptr); //free()只能釋放動態(tài)分配的內(nèi)存,自動存儲期和靜態(tài)存儲期都不行

}

void test_random(void) {

???? int count[11]={0}; // 只顯式初始化一個值,剩下的元素都初始化為0

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

???? {

???????? srand(time(0)+i*i);

???????? for (int j = 0; j < 1000; j++)

???????? {

???????? ????count[rand() % 10 + 1]++; //count[1]對應(yīng)隨機數(shù)1,count[10]對應(yīng)隨機數(shù)10,每次出現(xiàn)哪個隨機數(shù)就把哪個計數(shù)器遞增

???????? }

???????? printf("loop %d:\t", i);

???????? for (int j = 1; j < 11; j++)

???????? {

???????????? printf("count[%d]=%d\t", j, count[j]);

???????????? count[j] = 0;

???????? }

???????? putchar('\n');

???? }

}

int roll_n_dice(int dice, int sides) { // 拋多個骰子,dice接收骰子的個數(shù),sides指定骰子有幾面

???? int n, sum;

???? sum = n = 0;

???? putchar('(');

???? for (int i = 0; i < dice; i++)

???? {

???????? n = rand() % sides + 1;

???????? printf("%d ", n);

???????? sum += n;

???? }

???? printf(") = %d\n", sum);

???? return sum;

}

void dice_game(void) {

???? int dice, sides;

???? fputs("Enter the number of sets(1-64); enter q to stop:", stdout);

???? while (scanf("%d",&sets)==1&&sets>0&&sets<65)

???? {

???????? srand(time(0));

???????? printf("How many sides(2-64) and how many dice(1-64)?");

???????? if (scanf("%d%d",&dice,&sides)!=2||dice<0||dice>64||sides<2||sides>64)

???????? {

???????? ????puts("invalid input. sides(2-64) dice(1-64).");

???????? }

???????? else

???????? {

???????????? printf("Here are %d sets of %d %d-sided throws.\n", sets, dice, sides);

???????????? for (int i = 0; i < sets; i++)

???????????? {

???????????? ????roll_n_dice(sides, dice);

???????????? }

???????? }

???????? fputs("How many sets(1-64)? Enter q to stop:", stdout);

???? }

}

int* dynamic_make_array(int size, int init) {

???? int* ptr = (int*)calloc(size, sizeof(int)); // calloc()函數(shù)也用于動態(tài)分配內(nèi)存,第一個參數(shù)指定元素的數(shù)量,第二個參數(shù)指定元素的大小,函數(shù)會將所有位初始化為0,返回void*需要強轉(zhuǎn)

???? if(ptr) //動態(tài)分配內(nèi)存如果失敗會返回NULL

???????? for (int i = 0; i < size; i++)

???????????? ptr[i] = init;

???? return ptr;

}

void dynamic_show_array(const int* arr, int size) {

???? // 指針arr是其指向?qū)ο蟮脑诋?dāng)前函數(shù)內(nèi)的初始方式,如果同時也是唯一的方式(即函數(shù)內(nèi)沒有用其他指針也指向該對象),可以使用restrict關(guān)鍵字修飾arr,restrict關(guān)鍵字用于編譯器優(yōu)化,告訴編譯器當(dāng)前聲明的指針是訪問數(shù)據(jù)對象唯一且初始的方式,restrict關(guān)鍵字只能用于指針

???? for (int i = 0; i < size; i++)

???? {

???????? printf("%d ", arr[i]);

???????? if (i % 8 == 7)

???????? putchar('\n');

???? }

}

void words(void) {

???? fputs("How many words do you wish to enter?", stdout);

???? int n;

???? if (scanf("%d", &n) == 1 && n > 0)

???? {

???????? char** words = (char**)malloc(n * sizeof(char*)); // 創(chuàng)建指向字符串的指針數(shù)組,可以想象成:char是字符,char*是字符串/字符數(shù)組,char**是字符串?dāng)?shù)組/指向字符串的指針數(shù)組,所以每個元素為指針大小,有n個元素

???????? if (words == NULL)

???????? ????goto end; // goto語句的標簽是函數(shù)作用域,即使一個標簽首次出現(xiàn)在函數(shù)的內(nèi)層塊中,它的作用域也延伸至整個函數(shù)

???????? printf("Enter %d words now:\n", n);

???????? char temp[20];

???????? for (int i = 0; i < n; i++)

???????? {

???????????? scanf("%19s", temp); // 最多讀19個字符,末尾留一位\0

???????????? words[i] = (char*)malloc((strlen(temp) + 1) * sizeof(char)); // 先存放到臨時數(shù)組

???????????? strcpy(words[i], temp);????//字符串賦值

???????? }

???????? puts("Here are your words:");

???????? for (int i = 0; i < n; i++)

???????? {

???????????? printf("%s ", words[i]);

???????????? free(words[i]); // 每個動態(tài)分配的內(nèi)存分別釋放

???????? }

???????? free(words); // 千萬記得釋放

???? }

????end:;????//goto的end標簽,對應(yīng)的語句為;空

}

void others(void) {

register int i; // register關(guān)鍵字,請求將聲明的變量儲存在CPU的寄存器中,與普通變量相比,寄存器變量訪問、處理的速度更快,無法獲得寄存器變量的地址,所以無法使用&取址,編譯器視情況決定是否將該變量儲存到寄存器中,即便儲存在了內(nèi)存中也不能使用&

const volatile char* ptr; //volatile易變的,volatile限定符告知計算機,代理(而不是變量所在的程序)可以改變該變量的值,通常被用于硬件地址以及在其他程序或同時運行的線程中共享數(shù)據(jù),編譯器會根據(jù)volatile改變優(yōu)化,const和volatile順序無所謂

//_Thread_local //以關(guān)鍵字 _Thread_local聲明具有線程存儲期的對象,每個線程都獲得該變量的私有備份,線程存儲期從被聲明時到線程結(jié)束一直存在

//_Atomic int hogs; // _Atomic原子類型變量,并發(fā)程序通過各種宏函數(shù)訪問原子類型,當(dāng)一個線程對一個原子類型的對象執(zhí)行原子操作時,其他線程不能訪問該對象

//static int j; int k; malloc(sizeof(int)); //靜態(tài)變量、自動變量、動態(tài)變量分別存儲在內(nèi)存中的三個不同的區(qū)域

int?arr1[10];

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

memcpy(arr1, arr2, sizeof(arr2)); //內(nèi)存字節(jié)拷貝,參數(shù)1、2和返回值(返回參數(shù)1)都是void*類型,參數(shù)3指定字節(jié)數(shù),參數(shù)1和參數(shù)2不應(yīng)重疊

memmove(arr1, arr2, sizeof(arr2)); //和memcpy區(qū)別是參數(shù)1、2可以重疊,使用緩沖區(qū)進行拷貝,src拷貝到緩沖區(qū)再拷貝到dest

/*存儲期分為靜態(tài)、自動、動態(tài)。靜態(tài)存儲期在程序開始執(zhí)行時分配內(nèi)存。自動存儲期在程序進入變量定義所在的塊時分配變量內(nèi)存,離開塊釋放內(nèi)存。動態(tài)存儲期在調(diào)用malloc()calloc()分配內(nèi)存,調(diào)用free()釋放

作用域分為文件作用域、塊作用域、函數(shù)作用域。

鏈接分為外部鏈接、內(nèi)部鏈接、無鏈接。*/

}

//void func(int a1[const], int a2[restrict], double ar[static 20]) //C99規(guī)定,int* const a1等價int a1[const],int* restrict a2等價int a2[restrict],double ar[static 20]告訴編譯器該數(shù)組至少有20個元素


C語言存儲類別、鏈接和內(nèi)存管理的評論 (共 條)

分享到微博請遵守國家法律
克拉玛依市| 启东市| 广河县| 辽源市| 南澳县| 海原县| 东阳市| 石河子市| 江达县| 杭州市| 进贤县| 嵩明县| 浦北县| 大渡口区| 通州市| 东丰县| 吴江市| 梨树县| 蓬莱市| 娱乐| 拜泉县| 工布江达县| 特克斯县| 衢州市| 仪陇县| 永新县| 德清县| 汉川市| 应城市| 天长市| 阿拉善左旗| 龙口市| 肇州县| 奈曼旗| 苏尼特左旗| 马公市| 海原县| 潜江市| 仙桃市| 侯马市| 大同县|