扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
除去布尔型和扩展的字符型外,其他整型可以划分为带符号的和无符号的两种。带符号类型可以表示正数、负数或0,无符号类型则仅能表示大于等于0的值。
float与double※如果表达式里既有带符号类型又有无符号类型,当这个带符号类型取值为负时会出现异常,因为带符号数会自动转换成无符号数。所以切勿混用带符号与无符号类型。
unsigned u = 10, u2 = 42 ,u - u2 = 4294967264
10, 10u, 10L, 10uL, 012, 0xC:整形字面值,无符号整形字面值,长整形字面值,无符号长整形字面值,八进制整形字面值,十六进制整形字面值;
int month = 09, day = 07; 八进制整形,八进制中没有9,所以会报错。
1024f;非法,整形字面值不可加后缀f;
'A’与"A"float最小尺寸为6位有效值,double最小尺寸为10位有效值。
布尔类型转换时前者代表单独的字符A
==※==后者代表了一个字符的数组,包含两个字符:一个是字母A,另一个是空字符(‘\0’)
初始化与赋值非布尔类型值赋给布尔类型值时,初始值为0,结果为false。除此之外为true
布尔类型值赋给非布尔类型值时,初始值为false,结果为0。初始值true,结果为1
初始化初始化不是赋值
初始化:创建变量时赋予其一个初始值
赋值:把对象的当前值擦除,用一个新的值来替代
定义于函数体内的内置类型的对象如果没有初始化,则其值未定义,如果试图拷贝或者访问此类值将引发错误。(所以建议初始化每一个内置类型的变量)
而类的对象如果没有显式地初始化,则其值由类决定。(例如string类如果没有指定初值则生成一个空串)
int i = { 3.14 }; 非法,不能执行强制转换,因为存在丢失信息的风险
int i = 3.14;合法,已强制转换。
声明规定了变量的类型和名字,定义不仅这样,还会申请存储空间,也有可能直接赋初始值。
extern int i; //声明i,但无定义(如果赋初始值就是定义了)
int j; // 声明并定义j
变量能被多次声明,但只能被定义一次
含义是在编译阶段检查类型
用户自定义的类名一般以大写字母开头 Sales_item
复合类型 引用与指针一旦定义了引用,就无法令其再绑定到另外的对象
引用是其他对象的别名。指针本身就是对象(所以它本身也有自己的地址),存放其他对象的地址
※因为引用不是对象,没有实际地址,所以不能定义指向引用的指针
int *p1 = nullptr; int *p1 = NULL; //等价于int *p1 = 0
int *p1 = 0; //直接将p1初始化为字面常量0来生成空指针
推荐使用nullptr
pi = &ival;//pi的值被改变,此时pi里是ival的地址,pi指向了ival
*pi = 0; //ival的值被改变,指针pi并没有改变
任何非0指针对应的bool都是true;if(pi)
建议 int *p这种写法
int ival = 1024;
int *pi = &ival;
int **ppi = π
遇到复杂的指针和引用时,建议从右向左阅读
指向指针的引用int i = 42;
int *p;
int *&r = p;// r是一个对指针p的引用
r = &i;// 因为r是引用了一个指针,所以给r赋值&i就是令p指向i
*r = 0; // 解引用r得到i,将i的值改为0;
为什么没有指向引用的指针?因为引用本身就不是一个对象。
2022-11-26 星期六 小雨 constconst对象一旦创建后其值就不能再改变,所以const对象必须初始化
如果想在多个文件之间共享const对象,就必须在变量的定义之前加extern关键字
int errNumb = 0;
int *const curErr = &errNumb; // curErr将一直指向errNumb(此时可以通过指针修改errNumb的值)
const double pi = 3.14;
const double *const pip = π // pip是一个指向常量对象的常量指针(都不可修改)
const int *p; //合法,指向常量的指针可以不初始化。
onst int *const p3; //不合法,常量指针未初始化;
第三章 字符串、常量和数组
命名空间操作符(::)的意思是:编译器应从操作符左侧名字所示的作用域中寻找右侧那个名字
※头文件里的内容会拷贝到所有引用它的文件中,所有应该避免在头文件中使用using声明
在用cin读取string对象时,会自动忽略开头的空白,并在下一个空白处停止
如果输入" Hello World “,那么输出将是"Hello”
要解决这个问题可以使用getline(cin, s),当遇见换行符时停止
※string中的size()函数返回的其实是一个unsigned无符号的int值。所以,对于表达式s.size()< n来说,如果n是一个负值,则这个表达式的结果几乎100%是true,因为负值n会自动转换成一个比较大的无符号值。
所以如果一个表达式里已经有了size()函数就不要再使用int了,这样可以避免混用int和unsigned可能带来的问题
C++中,字符串字面值与string是不同的类型,string s = “hello” + ","是错误的。必须保证每个加号两侧的运算对象至少有一个是string。
不管什么时候,只要对string对象使用了下标,都要确认这个下标处有值
小tips:
for (decltype(s.size()) index=0; index != s.size(); index++ ) {}
题目:
string s;
cout<< s[0]<< endl;
//合法,定义后就占用一个字节,包含’\0’。
vectorvector中只能存放同一种类型对象
vector不能存放引用,因为引用不是对象
vectorv1(10, 1); // 有10个元素,每个值都是1
vectorv1{10, 1}; // 有2个元素,分别是10,1
vectorsvec(10, "null"); //正确,创建了一个包含10个元素为“null”的vector对象。
范围for语句体内不应改变其所遍历序列的大小
只能对已确认存在的元素执行下标操作(否则常常会出现缓冲区溢出buffer overflow)
迭代器begin成员指向容器中第一个元素,而end返回容器尾元素的后一个元素(即不存在的元素)
当容器为空时,begin和end返回的是同一个迭代器,即尾后迭代器
要理解数组声明的含义,最好是从数组的名字开始,由内向外依次阅读
int ia[txt_size()]; 当txt_size()是constexpr时正确;否则错误
string sa[10];
int ia[10];
int main() {string sa2[10];
int ia2[10];
}
sa:空字符串;
ia:0;
sa2:空字符串;
ia2:不确定值。
string nums[] = {"one", "two", "three"};
string *p = &nums[0];
string *p2 = nums; //等价于 p2 = &nums[0]
// 通常情况下,使用数组类型的对象其实是使用一个指向该数组首元素的指针
使用数组类型的对象,其实就是使用一个指向该数组首元素的指针
int ia[] = {0, 1, 2, 3, 4};
auto ia2(ia); // ia2是一个整型指针,指向ia的第一个元素
但是如果使用decltype时转换不会发生、
decltype(ia) ia3 = {0, 1, 2, 3, 4}; //此时ia3是一个含有5个整数的数组
要特别注意:尾后指针不能执行解引用和递增操作
C++程序应该尽量使用vector和迭代器,而避免使用内置数组和指针
应该尽量使用string,而避免使用C风格的基于数组的字符串
严格地说,C++中并没有多维数组,只有数组的数组。
int ia[3][4]; //大小为3的数组,每个元素是含有4个整数的数组
使用for循环多维数组时,除最内层循环外,其他循环的控制变量应该为引用类型(否则可能会出现转换为指向数组首元素指针的情况)
int ia[3][4]; //大小为3的数组,其中每个元素都是含有4个整数的数组
int (*p)[4] = ia; // p指向含有4个整数的数组
p = &ia[2]; // p指向ia的尾元素
int *ip[4]; // 整型指针的数组
int (*ip)[4]; //指向含有4个整数的数组
第四章:表达式
算术运算符当优先级相同时,按照从左向右的顺序组合
bool b = true;
bool c = -b; // c依旧是true;因为b参与运算后值被转为1,而-1不等于0,所以转为bool后为true
参与取模运算%的运算对象必须为整数类型
const char *cp = "Hello World";
if (cp && *cp)
当指针cp不为空时,才判断解引用cp的值。
我们知道,cp不为空,&&左侧为true;*cp为’H’,右侧也为真,所以if语句为真。
避免使用后置递增/递减,因为后置版本需要将原始值存储起来以便于返回这个未修改的内容
成员访问运算符解引用运算符的优先级低于点运算符
ptr->men 等价于 (*ptr).men;
2022-11-28 周一 阴
位运算强烈建议仅将位运算符用于处理无符号类型
左移运算符<< 在右侧插入值为0的二进制位
右移运算符 >>行为取决于左侧运算对象的类型
如果是无符号型,在左侧插入值为0的二进制位
如果是带符号型,在左侧插入值为0的二进制位或插入符号位的副本
位求反运算符 `:0置1,1置0
位异或运算符^:两个中只有1个1则为1,否则为0
cout<< 10< 42; //错误,试图比较cout和42!
sizeofsizeof(obj); //这种情况返回存储obj所占空间的大小
sizeof obj; //这种情况返回obj类型 所占空间的大小
int x[10]; int *p = x;
cout<< sizeof(x)/sizeof(*x)<< endl; // 40/4=10,数组所占的字节数/数组类型int所占的字节数,就是数组的个数;
cout<< sizeof(p)/sizeof(*p)<< endl; // 4/4=1,指针所占的字节数/int所占的字节数。
类型转换int val = 3.14 + 3; // 3会转换为double,然后执行浮点数加法运算,再将double转为int赋予val
3.1415L + 'a'; // 'a'提升为int,然后int转为long double
cval + fval; // cval提升为int,然后int转为float
fval = ui - ival * 1.0; // ival->double,ui->double,double->float;
强烈建议避免强制类型转换
第五章: 语句在switch中,哪怕default没用,也最好加上
鲁棒是Robust的音译,也就是健壮和强壮的意思。它也是在异常和危险情况下系统生存的能力。
局部静态对象:即使其所在的函数执行结束对它也没有影响,它直到程序终止才被销毁。
在C++中,建议使用引用类型的形参代替指针类型的形参。而且,当函数无需改变引用形参的值时,最好将形参声明为常量引用
const int &r = 42; //正确
int &r = 42; // 错误,不能用字面值初始化一个非常量引用
char *argv[];等同于 char **argv;
不要返回局部对象的引用或指针
如果main函数结尾处没有return语句,编译器将隐式地插入一条返回0的return语句
重载:名字相同,形参列表不同
void print(const int*);
void print(const int[]);
void print(const int[10]);
// 这三者等价,而[10]只是表示我们期望数组含有多少元素,实际不一定
通常应该在函数声明中指定默认实参,并将该声明放在头文件中
构造函数无论何时,只要类的对象被创建,就会执行构造函数
struct 于class的区别
vector: 可变大小数组。访问快,在尾部之外位置插入/删除元素慢
deque:双端队列。访问快,在头尾位置插入/删除元素快
list: 双向链表。只支持双向的顺序访问。任何位置插入/删除都很快
forward_list: 单向链表。只能单向顺序访问。在任何位置插入/删除都很快
array:固定大小数组。访问快,不能添加/删除元素
string:与vector基本一样,但只能保存字符。访问快,在尾部插入/删除快
通常情况下,使用vector是最好的选择
如果要求随机访问元素:vector或deque
如果要求在中间插入/删除元素:list或forward_list
如果要求在头尾插入/删除元素且不在中间位置插入/删除元素:deque
迭代器迭代器范围:左闭右开
向一个vector、string或deque插入元素会使所有指向容器的迭代器、引用和指针失效
调用swap后,元素本身并未交换,也就意味着指向容器的迭代器、引用和指针都依然有效(除string外)
每次改变容器的操作之后都应该重新定位迭代器,特别是vector、string和deque;
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流