1.
Const char *str1 = “ssss”;(指针指向常量区要加const,数组不需要)
Const char *str2 =“ssss“; (“ssss”是常量不可修改)
str1 == str2
因为两个指针指向同一个地址
char str1[] = "ssss"
char str2[] = "ssss"
str1 != str2
因为两个数组分别存放在不同的栈中
指针不可以直接指向常量字符串,数组可以
const char *p 表示 p是指向常量字符串的指针。
char* const p 表示p是指向字符串的常量指针。
2.
struct 数据类型对齐:
空成员struct 占一个字节
#pragma pack(n) 设置数值对齐 n只能为1 2 4 8 16
struct 整数对齐
若干char类型诺加起来不超过整数倍,则占用一个整数倍
结构体整体大小必须为实际对齐单位的整数倍
数据声明顺序也会对结构体大小有影响
Class 对齐:(C++)
空类占用一个字节
虚函数占用一个指针空间
子类大小等于父类大小+子类成员大小
静态成员不占用类大小,在堆区
函数成员不占用大小
3.
-= *= /= +=
右结合性,先算右边
ps:n *= 5 + 6;
先算 5+ 6 再算 *
4.
int n[3] = { 1,4,8 };
int* p = n;(等价于 p = &n ; *p=n)
int** pp = &p
int*** ppp = &pp
(依次添加‘*’ 和‘&’)
cout
cout
cout
cout
可复制代码仔细研究
int a[4];
(int *)(&a +1);a以整个数组大小移动一组
(int *)(a +1);a以首字符移动一位
5
(C++)
析构函数调用delete this;会造成递归调用,导致栈溢出,且this为*const常量指针不可以修改指向
6.
预处理命令一行只能出现一条 , 可以出现在任何位置 , 宏替换不占用任何运行时间
7.
背口决,考试可能需要,工作不太要求
■“单”表示单目运算符:逻辑非(!),按位取反(~),自增(++),自减(--),取地址(&),取值(*);
■“算”表示算术运算符:乘、除和求余(*,/,%)级别高于加减(+,-);
■“移”表示按位左移();
■“关”表示关系运算符:大小关系(>,>=,
■“与”表示按位与(&);
■“异”表示按位异或(^);
■“或”表示按位或(|);
■“逻”表示逻辑运算符:逻辑与(&&)级别高于逻辑或(||);
■“条”表示条件运算符(? :);
■“赋”表示赋值运算符(=,+=,-=,*=,/=,%=,>>=,
◆另,逗号运算符(,)级别最低,口诀中没有表述,需另加记忆..
8.
linux系统中的编译器gcc负责c语言 , g++负责c++。(了解即可)
gcc和g++的主要区别
1. 对于 *.c和*.cpp文件,gcc分别当做c和cpp文件编译(c和cpp的语法强度是不一样的)
2. 对于 *.c和*.cpp文件,g++则统一当做cpp文件编译
3. 使用g++编译文件时,g++会自动链接标准库STL,而gcc不会自动链接STL
4. gcc在编译C文件时,可使用的预定义宏是比较少的
5. gcc在编译cpp文件时/g++在编译c文件和cpp文件时(这时候gcc和g++调用的都是cpp文件的编译器),会加入一些额外的宏,这些宏如下:
#define __GXX_WEAK__ 1
#define __cplusplus 1
#define __DEPRECATED 1
#define __GNUG__ 4
#define __EXCEPTIONS 1
#define __private_extern__ extern
C语言编译
四个步骤
一、预处理阶段
展开头文件,宏替换,条件编译,去掉注释
二、编译阶段
检查语法错误,生成汇编代码
三、汇编阶段
把汇编代码转换成二进制机器码
四、链接阶段
将所有机器码链接在一起,生成可执行程序
9.
重载条件(c++类的知识)
1. 参数不同,(数据类型 ,参数个数)
2. Const
10.
C语言对源程序没有缩进要求
A+B = C;C – A != B 则C溢出(判断A+B是否溢出)
Void * 可以和任何指针相互转化
Sizeof()是操作符 , 返回size_t
else 与相同作用域且不带else 的最近的if匹配
浮点数会按照默认精度四舍五入,整数型只会截断
%% 输出% //输出/
时间局部性是一旦一条指令执行了,则在不久的将来它可能再被执行。空间局部性是一旦一个存储单元被访问,那么它附近的存储单元也很快被访问
形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元
64位机器的指针占8个字节。32位为4个字节
int型和double型混合运算,整型会自动转成double型再进行运算
11.
Class 中(C++)
Class指针不调用构造函数,和析构函数
构造函数的执行先执行父类,再执行子类。析构顺序相反
如果析构函数不是虚构则只调用,释放对象时只调用当前虚析构函数,反之,从父到子依次调用析构(若当前对象有子类,也依次调用),不受当前对象影响,
初始化为NULL的类指针可以安全的调用不涉及类成员变量的类成员函数而不出错
Class 和struct 有小端存储(内存地址从小到大)和大端存储(内存地址从大到小)根据成员声明顺序
12.
m%(-n) 等于m%n
(-m)%n 等于-(m%n)
%运算两边必须是整数
0001|0001被低位截断(高位丢弃) 为0001
指针类型都一样大,指针数组根据指针数量累加
负数计算时要用补码(取反加一)
符号扩展时,最高位为0则全补0,若为1则全补1
_try{}块中,无论运行什么代码在程序退出之前都会运行_finally{}块中的代码(c语言测试函数)
‘\0’是八位的00000000 , 是字符串的结束标志 , 在内存中实际表现为0
return 会根据返回类型的值进行强制转换
?:三目运算符,是右结合性
字符串在计算大小时要加‘\0’一个字节的大小
当代码执行到该变量被赋值的代码时才被创建(用内存存储数据)
如果同一个变量,分别作为全局变量和局部变量,根据局部优先原则,是可以定义为不同类型的。
13.文本函数
ssize_t write( int fd, const void * buf,size_t nbytes)
write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量. 在网络程序中,当我们向套接字文件描述符写时有俩种可能.
ssize_t read( int fd, void * buf,size_t nbyte)
read函数是负责从fd中读取内容. 成功时,read返回实际所读的字节数,如果返回的值是0,表示已经读到文件的结束了.
小于0表示出现了错误.
write(const char* str,int n) str是字符指针或字符数组,用来存放一个字符串。
int x=1;int y=~x;x的值为-2
负值除符号位取反加一(补码)
14
一、返回值
C中:如果函数未指定返回值类型,则默认为int
c++中:如果一个函数没有返回值,返回值类型必须指定为void
二、参数列表
C中:如果函数没有指定参数列表,则默认可以接受任意多个参数
C++中:有严格的类型检测,没有参数列表的函数默认为void,不接受任意参数
三、缺省参数(即给参数一个默认值)
C:不支持
C++:支持(如果没有指定实参则使用缺省值,有则使用指定实参)
1.默认实参必须在参数列表的结尾
2.默认参数只能出现在函数声明或者定义二选一中
3.缺省值必须是常量或全局变量
4.缺省参数必须是值传递或者常参传递
四、函数重载
C:不支持
C++:支持在同一作用域中存在几个功能类似的同名函数,但参数列表(参数个数、类型、顺序)不同
15
强制转化float 和int 等数值要考虑截断问题
(float)(int)num
(int)(float)num
num原为int
结果相同
若num为flaot
则结果不同
16
字符串常量是const char *或(const char [])
字符是char
不能空引用,但可以空指针
静态局部变量,默认初始化为0
17
Static_cast 编译时检查(C++子父类转换问题)
用于基本数据类型之间的转换
上行转换(派生类---基类)是安全的,与dynamic_cast效果相同;
下行转换(基类---派生类)由于没有动态类型检查,所以是不安全的;
把空指针转换成目标类型的空指针
把任何类型的表达式转为void类型
static_cast不能转换掉expression的const、volatile、或者__unaligned属性
dynamic_cast关键字(运行时类型检查)
上行转换(派生类--->基类)是安全的,与static_cast效果相同;
下行转换(基类--->派生类)具有类型检查的功能,转型是安全的,
dynamic_cast只能用于有虚函数的类
先检查能否转型成功,能成功则转型,不能成功则返回0
18
void test(void *data)
unsignedint value = (*((unsigned int*) data));
data为void类型不能直接转换值,先指针转换,再取值
19
struct成员类型不可以是它自己。可以是引用和指针
//用new创建一个二维数组
Int *arr = new int[m * n];
Delete []arr;
一:
int (*p)[line] = new int[row][line];
删除二维数组:
delete []p;
二:
int **p
p = new int*[row];
for(int i = 0;i < row; i++)
p[i] = new int[line];
删除二维数组
for(int i=0;i delete [] p[i];
delete [] p;
char *p = new char[row];
for(int i=0;i {
p[i] = new char[line];//为每个指针都分配line个char元素空间
}
二:
char *p[row];
for(int i=0;i {
p[i]=new char[line];//为每个指针分配line个char元素空间
}
删除指针数组:
for(int i=0;i delete [] p[i];
重点,复制代码,仔细研究。
20
Int *p[3] , a[3];//p是指针数组
P[0] = &a[0]; //把p[3]看成一个整体理解
21.
(C++)
shared_ptr采用了引用计数器,允许多个指针指向同一个对象引用计数归0时,shared_ptr会释放管理的内存空间weak_ptr
weak_ptr不能单独作为智能指针使用,只能辅助shared_ptr解决循环依赖的问题。
定义对象的时候使用shared_ptr,引用对象的时候使用weak_ptr。
unique_ptr
unique_ptr是独占型的强智能指针。独占型就是不允许多个智能指针指向同一块内存空间,也不支持拷贝,复制。
Auto_ptr 已经停用 不要再使用,容易出bug22.#include 编译器直接从系统类库目录里查找头文件,如果类库目录下查找失败,编译器会终止查找。
#include "" 编译器默认从当前文件所在目录下查找头文件,如果查找失败,再从项目工程中设置的头文件引用目录查找Union
1.要≥最大的那一个变量的大小
2.要是最大的那种类型的整数倍
23在类的成员函数中可调用delete this,但是有个前提:被调用的方法不涉及这个对象的数据成员和虚函数。在类对象的内存空间中,只有数据成员和虚函数表指针,并不包含代码内容,类的成员函数单独放在代码段中,在delete this之后进行的其他任何函数调用,只要不涉及到this指针的内容,都能够正常运行delete this释放了类对象的内存空间,但是内存空间却并不是马上被回收到系统中,可能是缓冲或者其他什么原因,导致这段内存空间暂时并没有被系统收回delete this会去调用本对象的析构函数,而析构函数中又调用delete this,形成无限递归,造成堆栈溢出,系统崩溃24.C语言源程序:f.c,目标程序:f.obj,可执行程序:f.exeC++不是类型安全的
第一个打印的是指针指向x数组的值,也就是x[0],然后指针变量自加1;
第二个打印的是x数组的首地址(pp=&x),但每次分配都不相同,所以随机。
++b后b由原先b[0][]指向b[1][] ,所以b[1][1] 指向a[2][1];数组名作为函数参数传递时,数组名退化成指针,传递过去的其实是数组的首地址25变量a++返回的是一个临时变量,不可以给其赋值
函数中二维指针不能被二维数组直接调用
void f(int **b);或(int *b[]);
void g(int b[][]);
int *b[4] = {…};
int a[3][4] = {…};
f(b);
g(a);
void getMemory(char** p) {
*p = (char*)malloc(100); // 1
}
int main(int argc, char const* argv[]) {
char* str = NULL;
getMemory(&str);
strcpy(str,"hello wrold"); // 2
printf("%s\n", str); // 3
free(str); // 4
}
参数本身就是指针了,传str实际就是按值传递(因为str就是指针)。如果想传递str的指针,应该将参数定为指针的指针
函数的定义不可以嵌套,调用可以
内存溢出,申请不到足够的内存;
内存泄露,无法释放已申请的内存;
两者关系:内存泄露 剩余内存不足 后续申请不到足够内存 内存溢出。
函数参数传递指针的时候,内存其实是对原指针做了复制(指针其实还是值传递)
int,short,long都是signed的;
char可能是signed的,也可能是unsigned的;
明明传入的形参是指针,但是在函数改变指针的指向后但是数据却不会发生改变,这个很有可能是我们忽略了在函数中我们是否使用了局部参数的地址
函数调用
void f(int);
f(x);是函数调用语句
f;是函数地址
else始终与同一括号内最近的if结合
C语言实际只有一维数组,多维数组是仿真出的
任何一个数组下标都等同于一个对应的指针运算
*((*(p+1))+1)
p[1][1]
*((p[1])+1)
(*(p+1))[1]
不能单独写int c[];
要有初始化int c[] = “sssss”;
指针不会请求内存空间,且任何指针字节都为4字节
strcpy,strcat等字符函数,第一个字符都应该是有内存空间的指针或数组
通过malloc函数可以为指针分配内存空间,此时可以使用字符函数,但是要注意malloc可能会无法请求内存返回空指针,且malloc()分配的字符大小应该多一共字节存储‘\0’
#define NULL 0
NULL和0相同
不可以使用空指针的内容,但是可以调用空指针
简化程序设计
取值范围的大小为上界与下界之差
如果取值范围为空,上界等于下界
上界永远不可能小于下界
无符号运算不可能溢出
有符号和无符号运算时,有符号转换为无符号运算
有符号和有符号运算可能会发生溢出
static可以修饰变量,和函数
如果一个函数在被定义和声明之前调用,(main函数后),那么他的返回类型为整型
printf()和scanf()接收不同类型的参数用不同方式处理,会出现相关错误。
外部变量n,声明两次为int n ; long n;不会检测出错误,运行时会出现多种情况
1. 被检测出
2. 赋值给其中一个值对另一个也有效
3. 两个n都被声明为long(或int)
4. 共享了存储空间,程序将不能正常工作
在不同文件,
char *file;
extern char *file;
或
char file[];
extern char file[];
getchar()返回的是int类型,如果给char类型的数据,会数据截断,
对于文件的读写模式,一个输入函数不能紧跟输出函数,反之亦然,必须在其中插入fseek()函数才能同时输入输出
char 转化为无符号(unsigned)会先转化成int,再转化为unsigned,可能会出现错误,而(unsigned char)直接无符号转化
如果对象长度为n位,那么只能移位n以内,0和0以上
领取专属 10元无门槛券
私享最新 技术干货