當前位置:首頁 » 編程語言 » c語言內存操作內置函數
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

c語言內存操作內置函數

發布時間: 2022-12-28 03:19:54

c語言中內置函數為什麼要用頭文件

所謂的「內置函數」應該是像printf、strcpy這類的系統庫函數吧?在編譯的過程中,編譯器會根據包含的頭文件查找相應的庫進行連接編譯,如果沒有包含頭文件的話,系統裡面有很多庫文件,編譯器就無法找到對應的文件進行編譯。也有的編譯器會在用戶忘記包含頭文件的情況下進行自動查找,但是這一個過程會相當慢,假如是一個大的項目的話,進行編譯就可以明顯的看出來了,編譯非常慢

Ⅱ C語言中分配內存的函數是怎麼寫的

Windows下的 malloc 原理就是調用 windows API 的各種內存管理函數申請內存並記錄內存狀態以便將來釋放。

DOS下的 malloc 原理就是調用申請內存的中斷申請內存並記錄內存狀態以便將來釋放。

UNIX 和 Linux 都有內存管理的系統調用,malloc 相當於給這些系統調用穿了一件

malloc()工作機制

malloc函數的實質體現在,它有一個將可用的內存塊連接為一個長長的列表的所謂空閑鏈表。調用malloc函數時,它沿連接表尋找一個大到足以滿足用戶請求所需要的內存塊。然後,將該內存塊一分為二(一塊的大小與用戶請求的大小相等,另一塊的大小就是剩下的位元組)。接下來,將分配給用戶的那塊內存傳給用戶,並將剩下的那塊(如果有的話)返回到連接表上。調用free函數時,它將用戶釋放的內存塊連接到空閑鏈上。到最後,空閑鏈會被切成很多的小內存片段,如果這時用戶申請一個大的內存片段,那麼空閑鏈上可能沒有可以滿足用戶要求的片段了。於是,malloc函數請求延時,並開始在空閑鏈上翻箱倒櫃地檢查各內存片段,對它們進行整理,將相鄰的小空閑塊合並成較大的內存塊。

malloc()在操作系統中的實現

在 C 程序中,多次使用malloc () 和 free()。不過,您可能沒有用一些時間去思考它們在您的操作系統中是如何實現的。本節將向您展示 malloc 和 free 的一個最簡化實現的代碼,來幫助說明管理內存時都涉及到了哪些事情。
在大部分操作系統中,內存分配由以下兩個簡單的函數來處理:
void *malloc (long numbytes):該函數負責分配 numbytes 大小的內存,並返回指向第一個位元組的指針。
void free(void *firstbyte):如果給定一個由先前的 malloc 返回的指針,那麼該函數會將分配的空間歸還給進程的「空閑空間」。

malloc_init 將是初始化內存分配程序的函數。它要完成以下三件事:將分配程序標識為已經初始化,找到系統中最後一個有效內存地址,然後建立起指向我們管理的內存的指針。這三個變數都是全局變數:

//清單 1. 我們的簡單分配程序的全局變數

int has_initialized = 0;
void *managed_memory_start;
void *last_valid_address;

如前所述,被映射的內存的邊界(最後一個有效地址)常被稱為系統中斷點或者 當前中斷點。在很多 UNIX? 系統中,為了指出當前系統中斷點,必須使用 sbrk(0) 函數。 sbrk 根據參數中給出的位元組數移動當前系統中斷點,然後返回新的系統中斷點。使用參數 0 只是返回當前中斷點。這里是我們的 malloc 初始化代碼,它將找到當前中斷點並初始化我們的變數:

清單 2. 分配程序初始化函數

#include
void malloc_init()
{

last_valid_address = sbrk(0);

managed_memory_start = last_valid_address;

has_initialized = 1;
}

現在,為了完全地管理內存,我們需要能夠追蹤要分配和回收哪些內存。在對內存塊進行了 free 調用之後,我們需要做的是諸如將它們標記為未被使用的等事情,並且,在調用 malloc 時,我們要能夠定位未被使用的內存塊。因此, malloc 返回的每塊內存的起始處首先要有這個結構:

//清單 3. 內存控制塊結構定義
struct mem_control_block {
int is_available;
int size;
};

現在,您可能會認為當程序調用 malloc 時這會引發問題 —— 它們如何知道這個結構?答案是它們不必知道;在返回指針之前,我們會將其移動到這個結構之後,把它隱藏起來。這使得返回的指針指向沒有用於任何其他用途的內存。那樣,從調用程序的角度來看,它們所得到的全部是空閑的、開放的內存。然後,當通過 free() 將該指針傳遞回來時,我們只需要倒退幾個內存位元組就可以再次找到這個結構。

在討論分配內存之前,我們將先討論釋放,因為它更簡單。為了釋放內存,我們必須要做的惟一一件事情就是,獲得我們給出的指針,回退 sizeof(struct mem_control_block) 個位元組,並將其標記為可用的。這里是對應的代碼:

清單 4. 解除分配函數
void free(void *firstbyte) {
struct mem_control_block *mcb;

mcb = firstbyte - sizeof(struct mem_control_block);

mcb->is_available = 1;

return;
}

如您所見,在這個分配程序中,內存的釋放使用了一個非常簡單的機制,在固定時間內完成內存釋放。分配內存稍微困難一些。我們主要使用連接的指針遍歷內存來尋找開放的內存塊。這里是代碼:

//清單 6. 主分配程序
void *malloc(long numbytes) {

void *current_location;

struct mem_control_block *current_location_mcb;

void *memory_location;

if(! has_initialized) {
malloc_init();
}

numbytes = numbytes + sizeof(struct mem_control_block);

memory_location = 0;

current_location = managed_memory_start;

while(current_location != last_valid_address)
{

current_location_mcb =
(struct mem_control_block *)current_location;
if(current_location_mcb->is_available)
{
if(current_location_mcb->size >= numbytes)
{

current_location_mcb->is_available = 0;

memory_location = current_location;

break;
}
}

current_location = current_location +
current_location_mcb->size;
}

if(! memory_location)
{

sbrk(numbytes);

memory_location = last_valid_address;

last_valid_address = last_valid_address + numbytes;

current_location_mcb = memory_location;
current_location_mcb->is_available = 0;
current_location_mcb->size = numbytes;
}

memory_location = memory_location + sizeof(struct mem_control_block);

return memory_location;
}

這就是我們的內存管理器。現在,我們只需要構建它,並在程序中使用它即可.多次調用malloc()後空閑內存被切成很多的小內存片段,這就使得用戶在申請內存使用時,由於找不到足夠大的內存空間,malloc()需要進行內存整理,使得函數的性能越來越低。聰明的程序員通過總是分配大小為2的冪的內存塊,而最大限度地降低潛在的malloc性能喪失。也就是說,所分配的內存塊大小為4位元組、8位元組、16位元組、 18446744073709551616位元組,等等。這樣做最大限度地減少了進入空閑鏈的怪異片段(各種尺寸的小片段都有)的數量。盡管看起來這好像浪費了空間,但也容易看出浪費的空間永遠不會超過50%。

Ⅲ C語言內部函數 printf() 具體是怎麼寫的

printf()函數是C語言中的格式化輸出函數,包含在<stdio.h>庫函數里,格式化輸出是指按照一定的格式輸出,具體寫法為
printf("<格式化字元串>",<參數列表>);
例如:
printf("Hello,world!\n");
輸出為:
Hello,world!
如果要輸出數據,則應使用格式控制字元,常用的有%d、%c、%f等等,例如:
int a=1;
printf("The number is %d.\n",a);
輸出為
The number is 1.

Ⅳ 在C語言中,如何給函數分配內存

不知lz有沒聽說過虛存一說,當源碼被編譯成二進制文件後,其中的變數,函數的虛擬地址,也就是內存空間中的地址就已確定,在運行時,操作系統為其分配物理內存並添加虛擬地址到物理地址的映射。
再說的多一點,一個進程(運行的程序)可分為若干段:代碼段、數據段、堆棧段等,其中函數所操作的空間(也就是局部變數的空間)就位於堆棧段,所謂函數分配內存大小,實際就是堆棧段指針的變化而已。

Ⅳ 在C語言中,如何給函數分配內存

函數的相對地址在編譯鏈接的時候就已經分配好了,但是絕對地址是未知的。就是說,函數的地址相對於程序基址的偏移是確定的,但是程序在運行的時候,會被載入到哪一個區域運行是不確定的,需要由操作系統根據內存的使用的情況等進行調度,所以函數在內存中的絕對地址也就自然不確定了,希望可以幫到你。

Ⅵ 例舉兩個c語言中申請內存空間的函數

上面那個,你貌似不懂耶

看好了

malloc

原型:extern void *malloc(unsigned int num_bytes);

用法:#include <alloc.h>

功能:分配長度為num_bytes位元組的內存塊

說明:如果分配成功則返回指向被分配內存的指針,否則返回空指針NULL。
當內存不再使用時,應使用free()函數將內存塊釋放。

舉例:

// malloc.c

#include <syslib.h>
#include <alloc.h>

main()
{
char *p;

clrscr(); // clear screen

p=(char *)malloc(100);
if(p)
printf("Memory Allocated at: %x",p);
else
printf("Not Enough Memory!\n");

free(p);

getchar();
return 0;
}

free

原型:extern void free(void *p);

用法:#include <alloc.h>

功能:釋放指針p所指向的的內存空間。

說明:p所指向的內存空間必須是用calloc,malloc,realloc所分配的內存。
如果p為NULL或指向不存在的內存塊則不做任何操作。

舉例:

// free.c

#include <syslib.h>
#include <alloc.h>

main()
{
char *p;

clrscr(); // clear screen
textmode(0x00);

p=(char *)malloc(100);
if(p)
printf("Memory Allocated at: %x",p);
else
printf("Not Enough Memory!\n");

getchar();
free(p); // release memory to reuse it

p=(char *)calloc(100,1);
if(p)
printf("Memory Reallocated at: %x",p);
else
printf("Not Enough Memory!\n");

free(p); // release memory at program end

getchar();
return 0;
}

為什麼很多人不喜歡c,c++,因為管理內存的一部分任何必須由程序員自己管理,不然很容易內存泄露,現在有很多檢查內存泄露的軟體比較常用的有(boundchecker)有興趣的可以下個試一下自己的程序,你會發現自己好可怕。malloc free使用一般有幾個原則(自己總結的,不一定正確,但很實用)
1 ,malloc free必須配套使用,並且盡可能逆序。
2 ,誰malloc的誰free
3,能夠不動態分配的盡量不動態分配,動態分配是很費時間的,而且存在一定的風險。

很多人喜歡這樣寫程序:
type * f()
{
type *t = (type*)malloc ( sizeof(type));
.
.

return t ;
}
這個肯定會出問題,一般象這種情況,一般聲明f(type* t),誰調用它誰為t分配空間,誰來釋放它的空間。不過很有意思的是,在有寫系統函數的會這樣.如(char* asctime() ,它返回一個表示時間的字元指針,但是並不要求你釋放,你也沒有辦法釋放,但是我可以肯定它這個串肯定不是在堆區分配的)

free的順序也很重要,很多時候free的時候會出現空指針的引用,不足為齊。有人提議free(t);t = NULL ;這種用法,有一定的道理,當你free一塊空間後,操作系統不會立即回收,所以在你再次用t的時候可能還是可以用的,t就成了個野指針,而將其t = NULL後,對t的引用會出問題。

Ⅶ C語言常用詞彙及函數有那些

常用詞彙:

1、short:修飾int,短整型數據,可省略被修飾的int。

2、long:修飾int,長整型數據,可省略被修飾的int。

3、long long:修飾int,超長整型數據,可省略被修飾的int。

4、signed:修飾整型數據,有符號數據類型。

5、unsigned:修飾整型數據,無符號數據類型。

6、restrict:用於限定和約束指針,並表明指針是訪問一個數據對象的唯一且初始的方式。

7、return:用在函數體中,返回特定值(如果是void類型,則不返回函數值)。

8、continue:結束當前循環,開始下一輪循環。

9、break:跳出當前循環或switch結構。

10、goto:無條件跳轉語句。

11、if:條件語句,後面不需要放分號。

12、else:條件語句否定分支(與if連用)。

13、switch:開關語句(多重分支語句)。

14、case:開關語句中的分支標記,與switch連用。

15、default:開關語句中的「其他」分支,可選。

常用函數:

1、int isalpha(int ch) 若ch是字母('A'-'Z','a'-'z'),返回非0值,否則返回0。

2、int isalnum(int ch) 若ch是字母('A'-'Z','a'-'z')或數字('0'-'9'),返回非0值,否則返回0。

3、int abs(int i) 返回整型參數i的絕對值。

4、double cabs(struct complex znum) 返回復數znum的絕對值。

5、double fabs(double x) 返回雙精度參數x的絕對值。

6、long labs(long n) 返回長整型參數n的絕對值。

Ⅷ 什麼是C語言函數,簡單明了讓你知道

函數是一組一起執行一個任務的語句。每個 C 程序都至少有一個函數,即主函數 main() ,所有簡單的程序都可以定義其他額外的函數。

您可以把代碼劃分到不同的函數中。如何劃分代碼到不同的函數中是由您來決定的,但在邏輯上,劃分通常是根據每個函數執行一個特定的任務來進行的。

C 標准庫提供了大量的程序可以調用的內置函數。例如,函數 strcat() 用來連接兩個字元串,函數 memcpy() 用來復制內存到另一個位置。

函數還有很多叫法,比如方法、子常式或程序,等等。

C 語言中的函數定義的一般形式如下:

在 C 語言中,函數由一個函數頭和一個函數主體組成。下面列出一個函數的所有組成部分:

以下是 max() 函數的源代碼。該函數有兩個參數 num1 和 num2,會返回這兩個數中較大的那個數:

創建 C 函數時,會定義函數做什麼,然後通過調用函數來完成已定義的任務。

當程序調用函數時,程序控制權會轉移給被調用的函數。被調用的函數執行已定義的任務,當函數的返回語句被執行時,或到達函數的結束括弧時,會把程序控制權交還給主程序。

調用函數時,傳遞所需參數,如果函數返回一個值,則可以存儲返回值。例如:

如上把 max() 函數和 main() 函數放一塊,編譯源代碼。當運行最後的可執行文件時,會產生下列結果:

形式參數就像函數內的其他局部變數,在進入函數時被創建,退出函數時被銷毀。

當調用函數時,有兩種向函數傳遞參數的方式:

默認情況下,C 使用 傳值調用 來傳遞參數。一般來說,這意味著函數內的代碼不能改變用於調用函數的實際參數。

Ⅸ C語言中動態內存分配函數的用法及作用(比如malloc,calloc,realloc等)

先舉個例子:某用戶需要一個將任意多個整數按大小排序的程序。(在計算機文件夾中,當文件很多時經常用到排序)
1。若不用動態分配內存,那就定義一個超大的數組吧!問題是,如果用戶不需要那麼大,不就浪費了?如果定義的數組還不夠大,不就不能滿足需求了?
2。如果用動態分配,就解決上述問題了。當你需要多大內存時,就給你多大——如果有的話——這就是動態分配的意義。

現在看上述問題的代碼,我調試過的:
----------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h> /* calloc、exit需要聲明頭文件 */
void main()
{
int n,*p,i,j,m;
printf("本程序可對任意個整數排序;\n");
printf("請輸入整數的總個數: ");
scanf("%d",&n);
p=(int *)calloc(n,sizeof(int)); /* calloc函數的使用 */
if(p==0) {
printf("分配失敗!\n");
exit(1); /* 當分配失敗時,exit可以終止程序 */
}
printf("請輸入這些整數:\n");
for(i=0;i<n;i++)
scanf("%d",p+i); /* 利用指針移位的方法賦值 */
for(i=1;i<n;i++) /* 冒泡排序法 */
{
for(j=0;j<n-i;j++)
if(*(p+j)>*(p+j+1))
{
m=*(p+j);
*(p+j)=*(p+j+1);
*(p+j+1)=m;
}
}
printf("將這些整數從小到大排列輸出為:");
for(i=0;i<n;i++)
{
if(i%5==0) printf("\n"); /* 每隔5個數換行 */
printf(" %11d;",*(p+i));
/* 為了整齊,每個數佔11個字元,當數字很多時這很重要 */
}
printf("\n");
free(p); /* 釋放空間 */
}

----------------------------------------------------------------------
調用calloc函數時,calloc(n,sizeof(int))表示請求n個連續的、每個長度為整型的空間,若成功返回這些空間的首地址。(int *)表示將這個地址放在指針中。到此為止,就可以用指針來對分配到的空間操作了。注意,最後一定要用free函數釋放申請到的空間,否則這部分空間會一直占著。

malloc、calloc、realloc的用法(以上述問題為例)及區別:
1。malloc(n*sizeof(int)) /* 請求n個連續的、每個長度為整型的空間,若成功返回這些空間的首地址,失敗返回0 */
2。calloc(n,sizeof(int)) /* 請求n個連續的、每個長度為整型的空間,若成功返回這些空間的首地址並將每個空間賦值為0,失敗返回0 */
3。realloc(p,sizeof(int)*n) /* 給一個已經分配了地址的指針重新分配空間,參數p為原有的空間地址,sizeof(int)*n是重新申請的地址長度,用於分配不足的時候。個人覺得沒用——不夠就找到原分配處改大一點不就行了?! */

我能說得只有這些了,有些東西看起來麻煩,當你小試一下就會發現,不過如此嘛!學C要多練、多思,不怕麻煩。不知道您學了遞歸沒有?有個經典的「漢諾塔」問題,那傢伙——得整死人啊!到現在我還一知半解的……
希望我的回答對您有幫助!

Ⅹ 有關C語言的內部函數和外部函數的定義說明

有兩種理解.(1)庫函數是C語言的內部函數或自帶函數,外部函數即程序員自定函數.
(2)凡加寫了extern 的函數是外部函數.

第一種理解好懂:

C語言的內部函數指的是C語言自帶的函數,無論是動態鏈接的或靜態鏈接的. 這些函數通過C語言的頭文件定義了.
例如, sin(),cos()等數學函數,在math.h中定義了,輸入輸出函數 printf(),fgetc()在stdio.h中定義了,時間函數表time(),ctime()等在time.h中定義了.還有許多其他內部函數.編程時,只要用#include <庫名.h>寫在編程頭部,程序中就可調用.

自定義函數,就是用戶自己寫的函數.

第二種凡加寫了extern 的函數是外部函數:

自定義函數可以與程序的main()寫在同一個文件中,也可以寫在另一個文件中,這時你可能還另寫自己的頭文件或者寫extern....,告訴編譯器,main中用到的某某函數是"外部函數".
例如,main()在a.c中,自定義函數my_func()在a2.c中

a.c內容:
#include <stdio.h>
extern float my_func(float a);
main()
{
printf("result=%f\n",my_func(2.0));
}

a2.c 內容:
float my_func(float a)
{
return a;
}

編譯:
cl -c a.c [得到a.obj]
cl -c a2.c [得到a2.obj]
cl a.obj a2.obj [鏈接成a.exe]
運行:
a.exe

result=2.000000

extern float my_func() 是外部說明,告訴編譯,main()里的my_func是外部函數,要通過鏈接(.obj)得到.

如果把my_func寫在a.c里:
#include <stdio.h>
float my_func(float a){
retun a;
}
main()
{
printf("result=%f\n",my_func(2.0));
}

my_func() 就不是外部函數.
編譯:
cl a.c [得a.exe]
運行:
a.exe

result=2.000000