1.内存
RAM
- 数据段
- 栈区(stack)——自动分配,释放,类似栈 (局部变量)
- 堆区(heap)——程序员分配,释放,类似链表
- 全局区(静态区static)——存放全局变量和静态变量,系统释放
- 文字常量区(const修饰)——存放常量和字符串存储,自动释放
-代码段
- 程序代码区——存放函数体二进制代码
ROM
全局变量
特性 | 全局变量 |
---|---|
两个全局变量可否重名 | 可以,局部会屏蔽全局变量 |
如何引用一个定义过的全局变量 | 头文件引用(变量有错误会在编译期间报错); extern关键字(变量有错误会在了解期间报错) |
可不可以被定义在多个.c文件的头文件中 | 可以,在不同.c文件中static修饰,但是只能一个赋值 |
静态全局变量和非静态全局变量(有无static修饰) | 静态全局变量作用域是整个源程序,非静态全局变量作用域是单个源文件 |
static
特性 | static | 普通 |
---|---|---|
函数(作用域不同) | 内存只有一份 | 每个被调用维持一份拷贝 |
全局变量 | 只初始化一次,防止其他文件单元中被引用 | 可多次初始化 |
局部变量 | 只被初始化一次,下一次依据上一次结果值 |
//main.cpp
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main()
{
int b;//栈
char s[] = "abc";//栈
char *p2; //栈
char *p3 = "123456"; //123456\0在常量区上,p3在栈上
static int c =0;//全局(静态)初始化区
p1 = (char*)malloc(10); //堆区
strcpy(p1,"123456");//123456\0在常量区,编译器可能将p3和这个优化为一处
}
堆和栈
区别 | 堆 | 栈 |
---|---|---|
申请方式 | 自动分配 | 程序员申请 |
全申请后系统响应 | 只要栈剩余空间大于所申请空间,就提供,否则提示栈溢出 | 类似链表 |
申请大小的限制 | 堆是向高地址扩展的数据结构,是不连续区域,所以比较灵活,空间较大 | 栈是向低位扩展的数据结构,获得的空间较少,连续的内存 |
申请效率的比较 | 速度快 | 速度慢,会有内存碎片,但是灵活 |
申堆和栈的存储内容 | 固定方式 | 不固定存储 |
存储效率的比较 | 运行时赋值,存取快 | 编译时确定 |
const(只读,常量区)
优点:1.清晰方便
2.保护那些不希望被修改的参数
const int a;//a是一个常整型数
int const a;//同上
const int *a;//指向常整型数的指针(const int )
int *const a;//指向整型数的常指针( *const)
int const a const;//指向常整型数的常指针(const 和 a const)
2.static作用
- 在函数体内,一个被声明为静态的变量在被调用过程维持其值不变
- 在模块内,一个被声明为静态的变量可以被模块内所有函数访问,但不能被模块外其他函数访问,是一个全局变量
- 在模块内,一个被声明为静态的函数只能被模块内其他函数调用(本地化)
3.引用和指针的区别
引用 | 指针 |
---|---|
要初始化 | 可以不必初始化 |
引用初始化后不能被改变 | 可以指向其他对象 |
不存在指向空值的引用 | 可以指向空值 |
可读性强,但不方便 | 可读性差,但方便 |
4.小知识
#include<file.h>和#include "file.h"
//区别:前者直接从标准路径(standard library)寻找头文件;后者从当前工作目录搜寻
#(预编译,实现代码文本替换工作,可以放在程序任意位置)
1.宏定义 2.文件包含 3.条件编译
.h头文件中的ifndef/define/endif的作用
//防止头文件被重复引用
实时系统的特性
//在特定时间内完成特定的任务,具有实时性和可靠性
什么是平衡二叉树
//左右子树都是平衡二叉树,左右子树深度差值的绝对值不超过1
堆栈溢出的原因
//1.没有及时回收垃圾资源;2.层次太深的递归调用
冒泡排序算法的时间复杂度
//O(n^2)
什么函数不能是虚函数
//constructor(静态成员函数)、构造函数和内联函数(C++)
队列和栈的区别
//先进先出和先进后出
不能做switch()的参数
//实型(如:float)
while(1)
//和for(;1;)相同,和for(;;)相同,和loop:--- goto loop;相同
三种数据模型
//层次,网状,关系模型
关键字 volatile
//定义为volatile的变量是说这个变量可能意想不到的变化,这样, 编译器就不会去假设这个变量的值
//三个volatile(1.并行设备的硬件寄存器 2.中断子查询会访问到的非自动变量 3.多线程应用中被几个任务共享的变量)
//一个参数既可以是const也可以是volatile,假如这是一个寄存器,因为它可能意想不到变化,所以提箱程序员不应去改变它
//一个指针可以使volatile,假如这是个中断子程序,子程序指向一个指针
结构和联合的异同
//相同点:都是由多个不同数据类型成员构成
不同点:联合共用一块地址,对不同成员赋值,其他成员也会重写,原来成员值不存在了;结构不同成员存放地址不同,赋值不影响
const 和#define相比
//const(定义常量,修饰函数参数,修饰函数返回值,可以提高健壮性)
//区别:const有数据类型,define没有;const有类型检查,define只有字符替换,没有类型检查;const可以调试,define不能
数组和指针的区别
//内存:数组在静态存储区或栈上创建;指针可以使任意内存块
//修改内容:
char a[] = "hello";
a[0] = 'x';
char *p = "world";
p[0] = 'x';//错误
//sizeof:sizeof(a)-->测出数组a长度;sizeof(p)-->测出一个指针变量长度
BOOL,int,float,指针类型的变量a与0的比较语句
BOOL: if(!a)or if(a)
int : if(a == 0)
float:const EXPRESSION EXP = 0.000001
if(a < EXP && a > -EXP)
pointer:if(a != NULL)or if(a == NULL)
判断程序是c还是c++编译的
#ifdef_cplusplus
cout << "c++";
#else
cout << "c";
#endif
宏和函数
带参宏编译时处理,不占用运行时间,函数在程序运行时,调用和返回占用时间;
带参宏没有数据类型,函数有
带参宏不分配内存,函数分配内存
带参宏使程序长度变长,函数不变
带参宏不占用
两个栈实现一个队列
//设A,B两个栈,一开始为空
1.新元素push入栈A
2.栈A所有元素pop出push到B
3.B的栈顶元素pop出
位操作
//给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a的bit3,要保持其他位不变
#define BIT3(0x1 << 3)
static int a;
void set_bit3(void)
{
a |= BIT3;
}
void clear_bit3(void)
{
a &= ~BIT3;
}
访问某特定的内存位置
假如要求设置一个绝对地址0x67a9的整形变量的值为0xaa66
int *ptr;
ptr =(int *)0x67a9;
*pte = 0xaa66;
中断子程序(不return,不传递参数,不用printf)
Typedef
#define dPS struct s*
typedef struct *s *tPS;
dPS p1; dPS P2;//分开声明
tPS p3,p4;//可以一起声明
一个整型数 // int a;
一个纸箱整型数的指针 // int *a;
一个指向指针的指针,它纸箱的指针是指向一个整型数 // (int *)*a;
一个有10个整型数的数组 // int a[10];
一个有10个指针的数组,该指针是指向一个整型数的 // int *a[10];
一个指向有10个整型数数组的指针 // int (*a)[10];
一个指向函数的指针,该函数有一个整型参数并返回一个整型数 // int (*a)int;
一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整形数 // int (*a[10])int;