- fopen()
“r” 打开一个用于读取的文件。该文件必须存在。
“w” 创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。
“a” 追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。
“r+” 打开一个用于更新的文件,可读取也可写入。该文件必须存在。
“w+” 创建一个用于读写的空文件。
“a+” 打开一个用于读取和追加的文件。
r:read w:write a:add
带+都可以写入
- const
const 出现在星号左边,表示的是p所指的变量内容不可变,指针指向可以改变,也就是顶层const
const 出现在星号右边,表示的是p是一个常量指针,不能指向其他的变量,但是指向的变量的内容可以改变,底层const
const在*左右两边都出现,表示指针指向不能改变,所指的变量内容也不能改变
类的方法后面加了const后,该方法的实现中不能修改类的成员
- 虚函数,动态联编,静态联编
对于父类函数( virtual 、非 virtual ),如果有同型函数:
----非virtual函数由指针类型决定调用哪个 「即 f(Base &b) , 指针类型为父类Base」
----virtual函数由指针指向的对象决定调用哪个(运行时决定)「即 Derive obj; , 指针指向对象为子类对象Derive」
静态联编:通过对象名调用虚函数,在编译阶段就能确定调用的是哪一个类的虚函数
动态联编:通过基类指针调用,在编译阶段无法通过语句本身来确定调用哪一个类的虚函数,只有在运行时指向一个对象后,才能确定调用时哪个类的虚函数
- 数组指针与指针数组
数组指针可以说成是”数组的指针”,首先这个变量是一个指针,其次,这个指针指向一个数组的首地址
char (*p)[4];
char b[4];
p指向一个char [4]的数组,不能将b赋值给p,因为b是数组首元素首地址,p存放的却是数组首地址,b是char 类型,b+1,b的值会实实在在的加1,而p是char[4]类型的,p+1,p则会加4
可以这样:p = &b,p相当与二维数组的行指针
数组指针对应着二维数组
函数定义
void fun(int (*P)[4]);//子函数中的形参,指针数组
a[3][4] = {0};//主函数中定义的二维数组
fun(a);//主函数调用子函数的实参,是二维数组的首元素首地址
指针数组
内存映像图 | 内容 | 权限 |
---|---|---|
栈区 | 函数中的普通变量 | 可读可写 |
堆区 | 动态申请的内存 | 可读可写 |
静态变量区 | static修饰的变量 | 可读可写 |
数据区/常量区 | 用于初始化变量的常量 | 只读 |
代码区 | 代码指令 | 只读 |
char *a[4] = {"hello", "world", "C", "C++"};//相当于char *(a[4]),大小是16个字节
a是一个在栈区有四个元素的数组,而每一个数组又是一个指针,所以说它的四个元素各占四个字节,所以变量a的大小是16个字节。“hello”, “world”, “C”, "C++"在只读数据区。
指针数组对应的是二级指针
void fun(char **pp);//子函数中的形参
fun(char *p[]);//主函数中的实参
-
字符数组初始化的两种方法
1.用字符为数组赋初值,char s[80] = {‘A’, ‘B’ ,‘C’}
2.用字符串常量赋初值,char s[80] =“ABC”
其他均是错误的,如char s[80]; s = {‘A’, ‘B’,‘C’},char s[80]; s = “ABC”;,此时s已经是指针了
注意:指针指向字符串时,字符串是常量,存储在常量区,而指针存储在栈区,不能对其操作修改。
char* s1 = “Hello world”;s1[2] = ‘E’; 这个操作是错的 -
malloc在内存分配失败时返回的是空指针,即NULL,而不是未初始化指针。
-
不能再析构函数中调用delete this,否则会形成无限递归,造成堆栈溢出
-
二维数组初始化
定义二维数组并赋初值时,可以省略第一维的大小,但不能省略第二维的大小,int a[2][ ]={{1,0,1},{5,2,3}}错误
初值列表中有一行是空的,这在C语言中是不允许的,int a[][3]={{1,0,1},{},{5,2,3}}错误
当省略第一维时,必须初始化
int a[][5] = {};//对
int a[][5];//错 -
利用循环计算
x|(x+1)统计x二进制数中,0的个数
x&(x-1)统计x二进制数中,1的个数
while(value)
{
cnt++;
//消除所有1,变成0
value = value & (value - 1);
}
其他:
1.int x=3,y=6,z; z=x^y<<2;
先执行<<,再执行 ^
x|z&y;
先执行z&y
2.用户态切换到内核态的 3 种方式
a. 系统调用
b. 异常
c. 外围设备的中断,如read系统调用
3.对于程序需要频繁读写的少量状态数据,应该用什么存储对象
注册表是windows操作系统中的一个核心数据库,其中存放着各种参数,直接控制着windows的启动、硬件驱动程序的装载以及一些windows应用程序的运行,从而在整个系统中起着核心作用。这些作用包括了软、硬件的相关配置和状态信息
4.* 是scanf函数中的一种修饰符,表示忽略该输入项,使用方法为:放在%与格式d(或者s,c等)之间。
如选项: scanf(“%x%*d%o”,&x,&y);
scanf不能指明浮点数的精度。如果出现scanf(“%6.2f”,&x);就是错误的
注意scanf函数完全就是字符串匹配。
5.基类型相同的两个指针变量之间可以进行大小比较、赋值及减法运算,但加法运算没有意义