※仅代表个人学习记录(记录自己认为重要的和薄弱的)
😄学习C++ Primer的第1天
Day 1
第二章:变量和基本类型
1. 基本类型及其字节大小
选择经验:
- 一般用
int
做算术运算,short太小而long与int表达的字节大小一样。若范围太大用long long
- 一般不要用bool和char做运算,因为有些机器char是有符号,有些机器char是无符号
- double双精度计算代价几乎与float单精度相差无几,所以一般用double(float64)
2. 关于名词对象和值
对象:指一块能存储数据并具有某种类型的内存空间
值:Read-only的数据
3. 初始值(挺有意思)
int a = 10;
众所周知这是初始化,但是用了赋值符号,所以一直争论不断。
初始化:创建变量时赋予其一个初始值。
赋值:把对象当前值擦除然后赋予新值替代。
4. 声明与定义
为了支持分离式编译,C++把声明和定义分开。
声明declaration 使得名字为程序所知。
定义 则是创建与名字关联的实体;定义申请存储空间,也可能会为变量赋予一个初始值。
定义只有一个,声明可以是很多个;定义在一个file中,而其他用到此定义的file必须对其声明,但不能定义。
extern int i; //声明而不定义
int i; //声明且定义
5. void* 指针
它可以存放任何对象的地址,这一点和其他任何指针一样。但是对于地址中到底是个什么类型的对象我们并不清楚。
6. const限定符
①必须初始化const变量
②默认状态下,const只在文件内生效。
const int buffer = 520;
,则编译器会找到所有buffer然后用520替换之。如果在多个文件里做到这点,则多个文件都要能找到buffer的初始值520,要做到这点则必须在每个文件都有定义。为了不与只有一个定义的principle,所以const变量只在文件里有效。
但有的时候const对象不是常量变量,但是又得再多个文件共享,这时候用extern
// file.cpp
extern const int buffer = fcn();
// file.h
extern const int buffer;
③关于引用
还是那个原则:常量可以引用非常量,非常量不可以引用常量,咋滴
int i = 520;
const int &ref = i;
cout<<"i : "<< i <<"\tref : "<<ref<<endl;
i =233;
cout<<"i : "<< i <<"\tref : "<<ref<<endl;
④顶层const和底层const
const int* const sb = 233
指针的const以声明类型int为分水岭,靠右为顶层const,靠左为底层const。顶层const指指针本身是个常量,底层const指指针所指对象是一个常量
⑤constexpr
验证是否是常量表达式
7. 类型别名
typedef double, wages;
typedef wages base , *p;
wages是double类型的别名,base是double类型别名,p是double*类型别名。
using SI = Sales_Item;
SI 是类Sales_Item的别名。
8. 关于auto
int i = 0;
const int ci = i, &cr = ci;
auto b = ci; //b是int,顶层const特性被忽略
auto c = cr; //同
auto d = &i; //整形指针
auto e = &ci; //指向整数常量的整形指针(底层const)
const auto f = ci; //包含顶层const
9. decltype
类型指示符
int x = 520;
decltype(x) float_or_not = 2.33333;
cout<<"type : "<<typeid(float_or_not).name()<<"\tvalue:"
<<float_or_not<<endl;
其他用法
int i = 0 , &r = i, *p = &i;
decltype(r+0) a ; // a是个int为初始化
decltype(*p) b = a; //b是个int&
decltype((i)) d = a; //d是个int&
decltype(i) e ; //e是个int
第三章:字符串、向量、数组
标准库类型string
include<iostream>
using std::string
-
Initialization
-
string对象操作
还有诸如 ==, <, >, <=, >=, -
处理string对象的字符
include<cctype>
isalnum(c); //字母or数字
isalpha(c); //字母
iscntrl(c); //控制字符
isdigit(c); //数字
isgraph(c);//不是空格可打印
islower(c);
isprint(c)
ispunct(c);
isspace(c);
isupper(c);
tolower(c);
toupper(c);
处理每个字符:基于范围的for循环
for(declaration : expression)
string s1("Jeff....is...handsome");
decltype(s1.size()) p = 0;
for(auto str:s1)
{
if(!ispunct(str))
{
str = toupper(str);
cout<<str;
}
else{
p++;
}
}
cout<<"\nThere are "<<p<<" punctuation";
标准库类型vector
vector这种容纳着其他对象的类型被称作容器,vector是类模板
include<vector>
using std::vector
-
定义和初始化vector对象
注意括号和花括号 -
添加元素
push_back
- vector支持的操作
v.empty();
v.size();
v.capacity(); //容量
v.push_back(t);
v[n];
v1 =v2;
v1 = {a,b,c,d};
v1 == v2;
v1 != v2;
< , > ,.....
ps. 不可以使用下标添加元素,因为vector容器不包含任何元素。只能对已有值得位置进行操作。
迭代器介绍
迭代器可以提供对对象的间接访问,就迭代器而言,其对象是容器的元素或string对象的字符。迭代器也可以从一个元素移动到另一个元素。迭代器有有效和无效之分。
和指针不一样的是,迭代器不是使用取地址符。
迭代器都拥有begin
和end
,其中end
指向最后一个元素的后一位。
迭代器运算符:
*iter ; //返回迭代器所指对象
iter->item; //解引用iter并获取该对象为item的成员,相当于(*iter).item
++iter;
-- iter;
iter1 == iter2;
iter1 != iter2;
迭代器类型:
vector<int>::iterator it
string::iterator it
vector<int>::const_iterator it
可读不可写
数组
(如果不确定个数,用vector)
需要注意的:
- 字符数组和字符串字面值的区别(有无
'\0'
) - 不可以直接将数组直接初始化或拷贝为另外的数组
- 不存在引用的数组
- 来看复杂一点的:(正常情况类型修饰符从右往左依次绑定)(好理解一点的话从内往外)
int* arr[n] ; //包含n个int* 类型
int (*arr) [n]; //arr指向一个含有n个int的数组
int (&arr) [n]; //arr引用一个含有n个int的数组
- ‘size_t’是机器相关的无符号类型
- ‘auto ptr(arr)’ 👉ptr是一个T型指针指向arr第一个元素
- 使用标准库函数begin和end
#include<iterator>
int arr[] {1,2,3,4,56,6,7,8};
int* ptr1 = begin(arr);
int* ptr2 = end(arr); //指向尾元素下一位
- C风格字符串
#include<cstring>
strlen(p); //不包括空字符
strcmp(p1,p2) ; //p1==p2 _ 0 ; p1>p2 _1 ; p1<p2 _-1
strcat(p1,p2) ;
strcpy(p1,p2);
string标准库:
1.阔以直接比较(数组名是地址,所以数组名不可以直接拿来比较)
与旧代码的接口
1.混用string和C风格字符串
string s("JEFF IS COOL")
const char* str = s.c_str()
.c_str()
返回值是一个C风格字符串
2.使用数组初始化vector对象
int arr[] {1,2,3,4,5,6,7};
vector<int> vec(begin(arr),end(arr)); //包含arr副本