main函数原型
界说:main函数有多种界说格式,main函数也是函数,函数相关的结论对main函数也有用(也可
以界说main函数的函数指针)。
main函数的完备写法:
- int main(int argc,char *argv[]){}
- int main(int argc,char **argv){}
复制代码 扩展写法:
- main(){} 等价 int main(){}
- int main(void){}
- void main(){}
- void main(void){}
- int main(int a){}
- int main(int a,int a,int c){}
- ...
复制代码 阐明:
- argc,argv是形参,它们俩可以修改
- main函数的扩展写法有些编译器不支持,编译报告诫
- argc和argv的通例写法:
argc:存储了参数的个数
argv:存储了全部参数的字符串形式
- #include <stdio.h>
- int main(int argc,char *argv[])
- {
- printf("argc=%d\n",argc);
- }
- int i = 1;
- for(;i < argc; i++)
- {
- printf("%s,%s\n",argv[i],*(argv+i));// 下标法和指针法
- }
- return 0;
复制代码
4. main函数是体系通过函数指针的回调形调用的
发起:1. 假如一个函数必要返回数组,发起将这个函数界说成
指针函数(返回值为指针的函数)
2. 假如一个被调函数必要接收主调函数传递一个非char类型的数组,发起被调函数的参数用
数组指针
- #include <stdio.h>
- /**
- * 定义一个函数,从从成绩中求某一个学生的成绩
- * @param n 索引,表示某个学生
- * @param arr 数组指针,表示总成绩
- */
- float* get_score(float (*arr)[4],int n)
- {
- return arr[n];// *(arr+n)
- }
- int main(int argc,char *argv[])
- {
- // 创建一个二维数组
- float scores[3][4] = {{66,67,78,88},{99,89,78,86},{56,78,67,57}};
- float *p = get_score(scores,1);
- printf("%5.2f\n",*(p+2));
- return 0;
- }
复制代码
- 假如一个被调函数的参数是一个字符数组{“aaa”,“bbb”…},发起将参数类型界说为字符
指针数组char *arr[]或者字符二级指针char **arr
- #include <stdio.h>
- // 需求:用一个指针数组, 存储一组字符串,要求写一个函数,取出数组中的字符串
- char* get_str(char **p,int n)
- {
- return *(p+n);
- }
-
- int main(int argc,char *argv[])
- {
- // 指针数组
- char *arr[3] = {"hello","wangwu","zhangsan"};
- char *str = get_str(arr,1);
- printf("%s\n",str);
- return 0;
- }
复制代码
- 假如必要将一个函数作为另一个函数的形参,发起将该函数的形参用函数指针表示
- int add(int a,int b){ return a+b; }
- int jisuan(int a,int b,int (*ADD)(int,int))
- {
- printf("开始计算:\n");
- // 执行函数add
- ADD(a,b);
- }
- int main()
- {
- int a = 5,b = 3;
- jisuan(a,b,add);
-
复制代码 内存管理
C历程内存布局
任何一个步伐,正常运行都必要内存资源,用来存放诸如变量、常量、函数代码等等。这些差别的
内容,所存储的内存地区是差别的,且差别的地区有差别的特性。因此我们必要研究C语言历程的
内存布局,逐个相识差别内存地区的特性。
每个C语言历程都拥有一片布局相同的虚拟内存,所谓的虚拟内存,就是从现实物理内存映射出来
的地址规范范围,最重要的特性是全部的虚拟内存布局都是相同的,极大地方便内核管理差别的进
程。比方三个完全不相干的历程p1、p2、p3,它们很显然会占据差别区段的物理内存,但颠末系
统的变换和映射,它们的虚拟内存的布局是完全一样的。
PM:Physical Memory,物理内存。
VM:Virtual Memory,虚拟内存。
将其中一个C语言含如历程的虚拟内存放大来看,会发现其内部包下地区:
栈(stack)
堆(heap)
数据段
代码段
虚拟内存中,内核区段对于应用步伐而言是禁闭的,它们用于存放操纵体系的关键性代码,别的由
于 Linux 体系的历史性原因,在虚拟内存的最底端 0x0 ~ 0x08048000 之间也有一段禁闭的区段,
该区段也是不可访问的。
虚拟内存中各个区段的具体内容:
栈内存
什么东西存储在栈内存中?
情况变量
下令行参数
局部变量(包罗形参)
栈内存有什么特点?
空间有限,尤其在嵌入式情况下。因此不可以用来存储尺寸太大的变量。
每当一个函数被调用,栈就会向下增长一段,用以存储该函数的局部变量。
每当一个函数退出,栈就会向上缩减一段,将该函数的局部变量所占内存归还给体系。
留意:
栈内存的分配和开释,都是由体系规定的,我们无法干预。
示例代码:
- void func(int a, int *p) // 在函数 func 的栈内存中分配
- {
- double f1, f2;
- ...
- }
- // 在函数 func 的栈内存中分配
- // 退出函数 func 时,系统的栈向上缩减,释放内存
- int main(void)
- {
- int m = 100; // 在函数 main 的栈内存中分配
- func(m, &m); // 调用func时,系统的栈内存向下增长
- }
复制代码 静态数据
C语言中,静态数据有两种:
全局变量:界说在函数外部的变量。
静态局部变量:界说在函数内部,且被static修饰的变量。
示例:
- int a; // 全局变量,退出整个程序之前不会释放
- void f(void)
- {
- static int b; // 静态局部变量,退出整个程序之前不会释放
- printf("%d\n", b);
- b++;
- }
- int main(void)
- {
- f();
- f(); // 重复调用函数 f(),会使静态局部变量 b 的值不断增大
- }
复制代码 为什么必要静态数据?
- 全局变量在默认的情况下,对全部文件可见,为某些必要在各个差别文件和函数间访问的数据
提供操纵上的方便。
- 当我们希望一个函数退出后依然能保留局部变量的值,以便于下次调用时还能用时,静态局部
变量可帮助实现这样的功能。
留意1:
若界说时未初始化,则体系会将全部的静态数据自动初始化为0
静态数据初始化语句,只会实行一遍。
静态数据从步伐开始运行时便已存在,直到步伐退出时才开释。
留意2:
static修饰局部变量:使之由栈内存暂时数据,酿成了静态数据。
static修饰全局变量:使之由各文件可见的静态数据,酿成了本文件可见的静态数据。
static修饰函数:使之由各文件可见的函数,酿成了本文件可见的静态函数。
数据段与代码段
数据段细分成如下几个地区:
.bss 段:存放未初始化的静态数据,它们将被体系自动初始化为0
.data段:存放已初始化的静态数据
.rodata段:存放常量数据
代码段细分成如下几个地区:
.text段:存放用户代码
.init段:存放体系初始化代码
- int a;
- // 未初始化的全局变量,放置在.bss 中
- int b = 100; // 已初始化的全局变量,放置在.data 中
- int main(void)
- {
- static int c;
- // 未初始化的静态局部变量,放置在.bss 中
- static int d = 200; // 已初始化的静态局部变量,放置在.data 中
- }
- // 以上代码中的常量100、200防止在.rodata 中
复制代码 堆内存
堆内存(heap)又被称为动态内存、自由内存,简称堆。堆是唯一可被开辟者自界说的区段,开辟
者可以根据必要申请内存的巨细、决定利用的时间长短等。但又由于这是一块体系“飞地”,全部的
细节均由开辟者本身把握,体系不对此做任何干预,给予开辟者绝对的“自由”,但也正因云云,对
开辟者的内存管理提出了很高的要求。对堆内存的合理利用,几乎是软件开辟中的一个永恒的话
题。
堆内存根本特性:
相比栈内存,堆的总巨细仅受限于物理内存,在物理内存允许的范围内,体系对堆内存的申
请不做限定。
相比栈内存,堆内存从下往上增长。
堆内存是匿名的,只能由指针来访问。
自界说分配的堆内存,除非开辟者自动开释,否则永不开释,直到步伐退出。
相关API:
申请堆内存:malloc() / calloc()
清零堆内存:bzero()
开释堆内存:free()
示例:
- int *p = malloc(sizeof(int)); // 申请1块大小为 sizeof(int) 的堆内存
- bzero(p, sizeof(int));
- // 将刚申请的堆内存清零
- *p = 100; // 将整型数据 100 放入堆内存中
- free(p); // 释放堆内存
- // 申请3块连续的大小为 sizeof(double) 的堆内存
- double *k = calloc(3, sizeof(double));
- k[0] = 0.618;
- k[1] = 2.718;
- k[2] = 3.142;
- free(k); // 释放堆内存
复制代码 留意:
malloc()申请的堆内存,默认情况下是随机值,一样平常必要用 bzero() 来清零。
calloc()申请的堆内存,默认情况下是已经清零了的,不必要再清零。
free()只能开释堆内存,并且只能开释整块堆内存,不能开释别的区段的内存或者开释一部
分堆内存。
开释内存的寄义:
开释内存意味着将内存的利用权归还给体系。
开释内存并不会改变指针的指向。
开释内存并不会对内存做任何修改,更不会将内存清零。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |