Ⅰ 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