五点了啊哈,才看到12页。
猫头鹰被花生辣醒了。
提示,各取所需,美美与共,不要硬肝。
斜体下划线是回答,其他的是背景、解释、分析甚至吐槽。
目录
p12 变量定义前的修饰符(续++)
五点整,开盘王者,啧,金牌法师。咳,来讲面向对象中特别会用到的修饰符。
1)类型对象实例/变量 声明和定义修饰符标识
声明时修饰符必须显示标识,定义时如果有默认的修饰符可不显示标识,但是显示标识可提高程序可读性,如无默认修饰则必须通过修饰符获取相应的扩展。
修饰符(前置修饰)变量 | const | extern | static | volatile |
非自定义类类型中的变量声明和定义 | 不可修改变量的值;定义时默认为文件级变量,可通过显示extern扩展 | 指定为声明;扩展变量为多文件级变量;定义时非const变量默认带有该标识 | 静态存储变量;不可更改的文件级变量 | 机器因素可更改变量,编译器不作优化处理 |
2) 自定义类数据成员定义和初始化
修饰符(前置修饰)声明和初始化 | const | static | volatile | mutable (可在const函数中更改该数据成员) |
声明时标识 | 所有数据的特殊作用扩展都需要在声明时显示标识 | |||
初始化时标识 | 必须在构造函数初始化列表中完成初始化 | 需要在类定义体外进行初始化,但不可进行显示标识 | 可在构造函数初始化列表中初始化,或在构造函数体中进行非初始化赋值 |
p25 逻辑运算符
我发现我搞错了。
逻辑运算符是可以多个串联的,例如
if(0||0||0||0||1)
if(x == 0 && x == 3 && y == 2)
都是合法的。
并且由于短路逻辑,以上两个运算符,在遇到一个使结果成立/不成立的算式时就会停止运算。以第二个举例,假设int x = 0,那么x == 0符合,x == 3不符合,则它就不再考虑y的问题,直接返回false即可。
运算符优先级和iomanip库输出格式我是真的记不住。
有点苦恼,直到我想起上机考试可以带书。
p38 switch,default的特别写法有点儿玄学,以前搞明白过,我记得很不合自然思路,然后现在也忘了。
p52 二维数组初始化
a.多维数组在内存中也是连续的;
b.初始化时二维数组可以只定义第二维大小,第一维可以省略;
c.数组初始化花括号内包含的第n个花括号指第一维中第n个(俗称就算是第n行)中初始化的内容;
d.初始化不足的置0。
p58 指针定义运算符优先级
这个本来没想写的,但有个无聊的人写了挺长一段来讲这个,于是就借过来看看,就当是概念关联的练习了,指路参考博客连接第二个。
int p; // 普通的int变量
int *p; // 首先从p开始, p先与*结合,表明p是一个指针。然后再与int结合, 表明p指向的是int类型。所以p是一个指向int类型的指针。
int p[3];//p先与[]结合,表明p是一个数组。然后与int结合,表明数组的元素是int类型的。因此p是一个整型的数组。
int *p[3];/*[]的优先级比*高,所以p先与[]结合,表明p是一个数组,再与*结合,表明数组里的元素是指针。再与int结合,表明指针指向的是int。所以p是一个数组,数组元素是整型指针(int*)。*/
int (*p)[3];//*这里的括号,让p与*先结合。表明p是一个指针。然后再与[]结合,表明指针指向的类型是数组。再与int结合,表明数组的元素是int类型的。 所以p是一个指向整型数组的指针。*/
int **p; //p为典型的二级指针。
int p(int);/*p首先与()结合,表明p是一个函数。进入()分析,说明该函数有一个int类型的参数。再与外面的int结合,表明函数的返回值是一个int。 所以p是一个参数类型为int,返回值为int的函数。*/
int (*p)(int);/*从p处开始,先与指针结合,表明p是一个指针。然后再与()结合,表明该指针指向的是一个函数。然后再与()里的int结合,表明函数有一个int类型的参数。再与最外层的int结合,表明函数的返回值是int。 这里的p是一个典型的函数指针。*/
int *(*p(int))[3];/*这个看上去很复杂。从p开始,先与()结合,表明p是一个函数,然后进入(),与int结合,表明函数的参数为int。再与外面的*结合,表明函数的返回值类型是指针。然后再到最外面一层,先与[]结合,表明返回指针指向的是一个数组。再与最外面的*结合,表明数组的元素是指针,再与最后的int结合,表明数组的元素指针指向的是int类型。所以p是一个函数, 参数为int, 返回值为指向int* []的指针。*/
哈,考最后这个多好玩,devcpp上你一时半会儿也没法编程来验证,狗头了。
p62 字符串与指针
这里说实话我只是随便搜搜,结果给我惊了个呆呆。
对于以下这个例子:
char str[] = "YewLi_yiwanshangmeishui";
char *p = str;
char *str = "YewLi_xuyaoyourenguanguan";
这两者看起来非常相似,但本质上是不同的。
最根本的区别是在内存中的存储区域不一样,字符数组存储在全局数据区或栈区,第二种形式的字符串存储在常量区。全局数据区和栈区的字符串(也包括其他数据)有读取和写入的权限,而常量区的字符串(也包括其他数据)只有读取权限,没有写入权限。
内存权限的不同导致的一个明显结果就是,字符数组在定义后可以读取和修改每个字符,而对于第二种形式的字符串,一旦被定义后就只能读取不能修改,任何对它的赋值都是错误的。
例如:
#include <stdio.h>
int main(){
char *str = "Hello World!";
str = "I love C!"; //正确,可以更改指针变量本身的指向
str[3] = 'P'; //错误,不能修改字符串中的字符
return 0;
}
这段代码能够正常编译和链接,但在运行时会出现段错误(Segment Fault)或者写入位置错误。
这就解释了学道上的那个小点,不加const会有警告的原因,警告的好哇。
p74 函数参数传递和函数重载
初始化赋值右往左,传参赋值左往右,害,最近老给人讲这个,搞得我都会了。
函数重载作用于名字相同,参数类型或个数不同的函数之间,其他一切都无关。不细讲别的了,但总之按照上面那个初始化和复制要求后,重载的函数不能导致某个调用会出现无法根据参数情况判断调用哪个函数的情况即可。
参考博客和网站:https://blog.youkuaiyun.com/mrwenzhi/article/details/76649115