1-1 C++基础:开始、变量和基本类型
1 配置C++和基础
1.1配置C++编译环境
1.1.1利用Visual studio创建C++程序
Step1:新建项目选择win32项目
Step2:在win32项目选项里,将windows应用程序改成控制台程序,再勾选空项目。
Step3:在项目栏右侧添加.h或者.cpp文件。
1.1.2利用VScode创建C++程序
step1:下载MinGW
链接:https://pan.baidu.com/s/1LnO_3_N8Uw_mB87spqSBqQ
提取码:ikbf
复制这段内容后打开百度网盘手机App,操作更方便哦
step2:将压缩包解压到指定文件夹,例如D盘
Step3:打开系统高级设置,将之前解压的MinGW的bin目录添加进用户变量的path和系统变量的path里
Step4:win+r打开对话框输入cmd,在命令行窗口输入
g++ -v
查看编辑器是否配置完成
Step5:打开VScode 在扩展里添加C++,code runner,include autocomplete插件,添加完成后重启VScode
Step6:新建项目,ctrl+F5进入调试,选择C++ (GDB/LLDB),然后选择g++ .exe即可。如果这步没有弹出选择g++ .exe操作则是VScode没有打开你新建的cpp文件的目录,右侧选择目录来打开即可。(因为要指定目录生成exe文件)
Tips:VScode每次编译C++总会生产.exe文件在.cpp文件下面,怎么把.exe文件集中到一个文件夹呢?
1、打开设置搜索code-runner:Executor Map,选择在settings.json中编辑
2、在settings.json中的C和C++内容添加要放置的文件夹目录如D:\\Workspace\\Cpp\\build\\
1.2关键知识点
“()”运算符-----调用运算符。跟随在函数名之后的一对括号“()",起到调用函数的效果。传递给函数的实参放置在括号内。
“.”运算符-----点运算符。左侧运算对象必须是一个类类型对象,右侧运算对象必须是此对象的一个成员的名字。运算结果即为该对象的这个成员。
“<<”运算法----- 输出运算符,将右侧运算对象的值写到左侧运算对象表示的输出流: cout << "hi"表示将hi写到标准输出。输出运算符可以连接: cout < <“hi” << "bye"表示将输出hibye.
“>>”运算符----- 输入运算符,从右侧运算对象的值写到左侧运算对象表示的输出流: cout << "hi"表示将hi写到标准输出。输出运算符可以连接: cout < <“hi” << "bye"表示将输出hibye.
1.3练习题
1.3.1书店程序
// --------------------------Sales_item.h-------------------------------
#ifndef SALESITEM_H
#define SALESITEM_H
#include <iostream>
#include <string>
class Sales_item {
friend std::istream& operator>>(std::istream&, Sales_item&);
friend std::ostream& operator<<(std::ostream&, const Sales_item&);
friend bool operator<(const Sales_item&, const Sales_item&);
friend bool
operator==(const Sales_item&, const Sales_item&);
public:
#if defined(IN_CLASS_INITS) && defined(DEFAULT_FCNS)
Sales_item() = default;
#else
Sales_item() : units_sold(0), revenue(0.0) { }
#endif
Sales_item(const std::string &book) :
bookNo(book), units_sold(0), revenue(0.0) { }
Sales_item(std::istream &is) { is >> *this; }
public:
Sales_item& operator+=(const Sales_item&);
std::string isbn() const { return bookNo; }
double avg_price() const;
private:
std::string bookNo;
#ifdef IN_CLASS_INITS
unsigned units_sold = 0;
double revenue = 0.0;
#else
unsigned units_sold;
double revenue;
#endif
};
inline
bool compareIsbn(const Sales_item &lhs, const Sales_item &rhs)
{
return lhs.isbn() == rhs.isbn();
}
Sales_item operator+(const Sales_item&, const Sales_item&);
inline bool
operator==(const Sales_item &lhs, const Sales_item &rhs)
{
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool
operator!=(const Sales_item &lhs, const Sales_item &rhs)
{
return !(lhs == rhs);
}
Sales_item& Sales_item::operator+=(const Sales_item& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
Sales_item
operator+(const Sales_item& lhs, const Sales_item& rhs)
{
Sales_item ret(lhs);
ret += rhs;
return ret;
}
std::istream&
operator>>(std::istream& in, Sales_item& s)
{
double price;
in >> s.bookNo >> s.units_sold >> price;
if (in)
s.revenue = s.units_sold * price;
else
s = Sales_item();
return in;
}
std::ostream&
operator<<(std::ostream& out, const Sales_item& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_item::avg_price() const
{
if (units_sold)
return revenue / units_sold;
else
return 0;
}
#endif
// --------------------chapter1.cpp----------------
#include<iostream>
#include"Sales_item.h"
int main(){
Sales_item total;
if(std::cin>>total){
Sales_item trans;
while(std::cin>>trans){
if(total.isbn()==trans.isbn())
total+=trans;
else{
std::cout<<total<<std::endl;
total=trans;
}
}
std::cout<<total<<std::endl;
}else{
std::cerr<<"no data"<<std::endl;
return -1;
}
return 0;
}
输出结果:
1.3.2 程序流程图
2 变量和基本类型
2.1字和字节
1、比特(bit):计算机以比特序列存储数据,每个比特非0即1。
2、字节(byte):大多数计算机以2的整数次幂个比特作为块来处理内存,可寻址的最小内存块称为字节
3、字(word):存储的基本单元称为字,它通常由几个字节组成。
一般计算机的字节由8比特构成,而一个字通常为4个字节或者8个字节。
2.2引用(左值引用)
1、引用即是为对象起了别名;
2、引用必须初始化,而且引用的初始值必须是一个 对象 ;
什么是对象?
通常而言对象是一块能存储数据并具有某种类型的内存空间。一些人把命名的对象和未命名的对象区分开来,他们把命名了的对象叫做变量。还有一些人把对象和值区分开来,其中对象指能被程序修改的数据,而值(value)指只读的数据。
int &a = 3 //错误
3、引用本身不是一个对象,所以不能定义引用的引用;
4、允许在一条语句中定义多个引用,其中每个引用标识符都必须以符号&开头
关键点:对引用变量的操作就是对它所引用的那个对象的操作!!所以在某些函数的形参常常为引用类型。
2.3指针
1、了解指针,需了解 *
符号和&
符号,*
可以用于定义指针,也可以用于解引用,&
表示为取地址。
2、空指针不指向任何对象。int *p=nullptr
定义空指针。
3、void*
指针可以存放任意对象的地址,可以比较大小,因无类型,仅操作内存空间,对所存对象无法访问即不能解引用,不能强制偏移,能通过强制类型装换static_cast装换成其他类型指针。 void *
指针变量主要用于将不同类型的指针变量传递给函数,在函数内部再将它强制转换为特定的指针类型。
4、指向指针的指针,指针变量p也是占据独立内存块的变量,它本身的地址也可以保存在一个 指针变量中,这个指针变量通常称为指向指针的指针,代表**
符号。
5、指向指针的引用,引用本身不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用,*&
符号,从右向左看。
int i=42;
int *p;
int *&r = p; //从右向左看,指针类型的引用
r = &i; //成立,相对于p = &i
引用和指针的比较:
引用变量只是其他变量的别名,无独立内存,同一个引用变量不能修改去引用不同的变量。指针变量存储其他变量的地址,有独立内存,在不同时刻可指向不同对象。
2.4const修饰符
1、const希望定义一些不能被改变值的变量。
2、const对象必须初始化,且不能被改变。
3、const变量默认不能被其他文件访问,非要访问,必须在指定const定义之前加extern。要想在多个文件中使用const变量共享,定义和声明都加const关键字即可。
4、const和指针,包括指向常量的指针和指针类型的常量。
5、指向常量的指针(pointer to const),不能用于改变其所指对象的值, 其定义方式有两种,以整形常量为例子,定义包括int const* p = &i
和const int* p = &i
。都表示指针指向的对象是常量,被指对象是不能被修改类型的。
5、指针类型的常量也叫常量指针(const pointer),指针本身是常量,定义方式有int *const p = &i;
,即指针是常量类型的,也就是说指针固定指向该对象,存放在指针中的地址不变,但地址所对应的那个对象值可以修改的。
6、const和引用,即对常量的引用(reference to const),指向const对象的引用,如 const int i =1; const int &r = i;
,可以读取但不能修改变量r。
临时量(temporary)对象:当编译器需要一个空间来暂存表达式的求值结果时,临时创建的一个未命名的对象。对临时量的引用是非法行为。
2.5类型别名typedef
1、类型别名(type alias)是一个名字,它是某种类型的同义词。使用类型别名有很多好处,它让复杂的类型名字变得简单明了、易于理解和使用,还有助于程序员清楚地知道使用该类型的真实目的。
2、传统定义方式,使用关键字typedef,如typedef Sales_item SI
2、C++11 新特性定义,using SI = Sales_item
3、理解指针类型的typedef的不同点:这一符合类型的对象,不能代回原式来进行理解如:
typedef char *pstring; // pstring是char*的别名
const pstring cstr = 0; // 的指针类型的常量,指向char类型
const pstring *ps; //此时ps是一个指向char类型常量的指针
// 如改写为const char *cstr = 0;不正确,为指向const char的指针
// 辅助理解(可代回后加括号)
// const pstring cstr = 0;代回后const (char *) cstr = 0;
// const char *cstr = 0;即为(const char *) cstr = 0;
再次注意:
1、指向常量的指针定义方式const int* p = &i或者int const* p = &i,
2、指针类型的常量定义为int const* p = &i,
3、如果使用typedef的话,cons修饰的表示指针类型的常量,即const pstring p是指针类型的常量,而const pstring *p是指向常量的指针。
3字符串、容器和数组
3.1 字符串string
标准库类型string表示可变长的字符序列,注意,其不同于字符串字面值。
Tips:字符串string不同于字符串字面值的例子:例如在字符串拼接(+)时候
s1+s2
使用时,保证至少一侧是string类型。string s1 = "hello" + "world"
// 错误,两侧均为字符串字面值,不能实现字符串的拼接!!!
3.1.1 字符串string的一些操作
1、初始化:
方式一:拷贝初始化(copy initialization):使用等号=将一个已有的对象拷贝到正在创建的对象。例如string str1 = str2
或者string str = "1234"
等。
方式二:直接初始化(direct initialization):通过括号给对象赋值。例如string str(s1)
或者string str("value")
等。
string str2 = "i_am_second";
string str2a = str2;
str2a[0] = 'h';
string str2b = "i_am_test";
string str2c = " ";
str2b = str2c;
cout<<"------------The using of = in string--------------"<<endl;
cout<<"str2 is: "<<str2<<endl<<"str2a is: "<<str2a<<endl;
cout<<"str2b is: "<<str2b<<endl<<"str2c is: "<<str2c<<endl<<endl;
输出结果为:------------The using of = in string--------------
str2 is: i_am_second
str2a is: h_am_second
str2b is:
str2c is:
2、求长度: 采用str.size()或者str.length()。
string str1 = "i_am_first";
// string类型的长度;(采用str.size()或者str.length())
int len = str1.size();cout<<"the size of str1 is: "<<len<<endl;
int leng = str1.length();cout<<"the length of str1 is: "<<leng<<endl<<endl;
输出结果为:the size of str1 is: 10和the length of str1 is: 10。
3、字符串拼接: 直接通过运算符+,值得注意,+号的两个对象必须至少一个是string类型的。
cout<<"------------The using of + in string--------------"<<endl;
string str3 = "i_am_";
string str3a = "third";
string str3b = str3 + str3a ;
cout<<"str3 is: "<<str3<<endl<<"str3a is: "<<str3a<<endl<<"str3b is: "<<str3b<<endl<<endl;
输出结果为:------------The using of + in string--------------
str3 is: i_am_
str3a is: third
str3b is: i_am_third
4、字符串切片: substr(位置,长度)
string str4 = "i_am_forth";
string str4a = str4.substr(5,5);
cout<<"------------slice of string type--------------"<<endl;
cout<<"str4 is: "<<str4<<endl<<"str4a is: "<<str4a<<endl<<endl;
输出结果为:------------slice of string type--------------
str4 is: i_am_forth
str4a is: forth
5、其他操作:
3.1.2 对string对象中的字符操作
/*
//----------------------------处理string中的字符--------------------------
*/
string str5 = "I_a m _5(fifth)";
// 判断字符是否为数字
bool isnum = isdigit(str5[7]);
cout<<"------------Process the characters of the string--------------"<<endl;
cout<<"5 in str5 is digit(1=true,0=false): "<<isnum<<endl;
// 判断字符是否为字母
bool isalp = isalpha(str5[1]);
cout<<"i in str5 is alpha(1=true,0=false): "<<isalp<<endl;
// 判断字符是否为大写
bool isup = isupper(str5[0]);
cout<<"i in str5 is alpha(1=true,0=false): "<<isup<<endl;
// 判断字符是否为小写
bool islo = islower(str5[2]);
cout<<"i in str5 is alpha(1=true,0=false): "<<islo<<endl;
// 判断字符是否为空格等其他符号
bool isspa = isspace(str5[3]);
cout<<"i in str5 is alpha(1=true,0=false): "<<isspa<<endl;
输出结果为:------------Process the characters of the string--------------
5 in str5 is digit(1=true,0=false): 1
i in str5 is alpha(1=true,0=false): 0
i in str5 is alpha(1=true,0=false): 1
i in str5 is alpha(1=true,0=false): 1
i in str5 is alpha(1=true,0=false): 1
3.1.3 例子
例子1:将字符串str5a的字符串中空格全部删除,如str5 = “i am str5a”;最后输出"iamstr5"
解题思路:
1、按下标i判断,
2、记录空格下标i,将其拆分成前后两字符(0–i和i+1–end)串再合并;
3、空格处下标再下次遍历重置为(i-1)
for(int i = 0; i < str5a.size(); i++)
{
if(isspace(str5a[i]))
{
string str5b = str5a.substr(0,i);
string str5c = str5a.substr(i+1);
str5a = str5b + str5c;
i--;
}
}
cout<<"Example1--to delet the space in (i am str5a): "<<str5a<<endl<<endl;
输出结果为:Example1–to delet the space in (i am str5a): iamstr5a
3.2 容器vector和迭代器
3.2.1 容器
1、初始化: 值得注意的是,容器的元素长度可以不一样vector<string> str = {"1","12","123"};
//定义初始化,可以定义不同长度的元素在一个容器中
vector<string> str1 = {"1","12","123"};
cout<<"---------------to init the vector type data--------------"<<endl;
cout<<"str1={a,ab,abc} the str[1] is: "<<str1[1]<<endl<<endl;
输出结果为---------------to init the vector type data--------------
str1={1,12,123} the 1 number is: 12
2、添加元素: v.push_back(e)
在尾部增加元素。
// 向末尾添加元素
str1.push_back("1234");
cout<<"---------------add data in the end of vector --------------"<<endl;
cout<<"str1={1,12,123,1234} the str1[3] is: "<<str1[3]<<endl<<endl;
输出结果为---------------add data in the end of vector --------------
str1={1,12,123,1234} the 3 number is: 1234
3、其他操作:
注意:vector对象(以及string对象)的下标运算符[i]
,只能对确知已存在的元素执行下标操作,不能用于添加元素。 以下两种情况都是错误的!!!
string a = "";
vector<int> b;
for(int i = 0; i < 2; i++)
{
a[i] = char(i);
}
for(int i = 0; i < 2; i++)
{
b[i] = i;
}
3.2.2 迭代器
1、获取头尾元素: 头元素 直接*str.begin()
即可;尾元素需要将尾迭代器向后移动一位,否则传递出来的是空指针,即尾元素*--str.end()
// 获取迭代器首尾元素;尾部元素需要用*--str.end(),直接得到的*str.end()一般是个空指针
string str2 = "hello_iterator";
vector<string> str3 = {"abc","ab","a"};
auto str2a = str2.begin();
cout<<"-----------get the begin and end mumber in vector and string ----------"<<endl;
cout<<"the str2={hello_iterator} first number is: "<<*str2a<<endl;
auto str3a = str3.end();
cout<<"the str3={abc,ab,a} end number[*--str3.end()] is: "<<*--str3a<<endl<<endl;
输出结果为:-----------get the begin and end mumber in vector and string ----------
the str2={hello_iterator} first number is: h
the str3={abc,ab,a} end number[*–str3.end()] is: a
2、获取容器内数据: 例如在vector<string> str = {"abc","ab","a"};iter = str.begin()
注意*iter[2]
和(*iter)[2]
的区别,前者*iter[2]==str[0+2]
;后者(*iter)[2]==str[0][2]
。
// 对迭代指针的一些操作
// 获取字符串内元素
auto str3b = str3.begin();
cout<<"-----------get the data in iterator ----------"<<endl;
cout<<"in str3={abc,ab,a} the str3c is: "<<*str3b<<endl;
cout<<"in str3={abc,ab,a} the str3c[1] is(==str3[2]): "<<str3b[2]<<endl;
cout<<"in str3c={abc} the (*str3c)[2] is(==str3[0][2]): "<<(*str3b)[2]<<endl;
输出结果为:-----------get the data in iterator ----------
in str3={abc,ab,a} the str3c is: abc
in str3={abc,ab,a} the str3c[1] is(==str3[2]): a
in str3c={abc} the (*str3c)[2] is(==str3[0][2]): c
3、其他操作:
3.3数组
1、数组的长度长度必须是const表达式,或者不写。
2、数组不允许直接赋值给另一个数组。
int a[] = {1,2,3};
int b[] = a; //错误
int c[];
c = a;//错误
3.3.1复杂数组
1、指针类型的数组(指针数组),关键字<type>* <var_name>
,例如int *arrp[10]
,表示10个int* 类型的指针数组。
2、指向数组的指针(数组指针),关键字<type> (*<var_name>)
,例如int (*parr)[10]
表示指向10个整形数组的指针。
运算符优先级:赋值运算符<逻辑运算符<关系运算符<算术运算符<括号
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *arrp[10]; //int类型指针的数组
int (*parr)[10]; //指向10个整形元素的数组的指针
// arrp = &arr; //错误!
parr = &arr;
cout<<parr<<endl; //输出数组首地址
cout<<parr[0]<<endl; //输出数组首地址
cout<<*parr[2]<<endl; //并非输出数组的值,而是数组的地址的十进制数,做法完全不推荐
cout<<(*parr)[2]<<endl; //输出数组的值
3、数组的引用,关键字<type> (&<var_name>)
,例如int (&refarr)[10] = arr
表示10个整形数组的引用。不能定义数据类型是引用的数组。
3.3.2 C风格字符串
1、从C继承来的字符串,用空字符(\0)结束。
2、相关操作:
①strlen(p)
------返回p的长度,空字符不计算在内;
②strcmp(p1, p2)
------比较p1和p2的相等性。如果p1==p2,返回0;如果p1>p2,返回一个正值;如果p1<p2,返回一个负值;
③strcat(p1, p2)
------将p2附加到p1之后,返回p1;
④strcpy(p1, p2)
------将p2拷贝给p1,返回p1。
3.3.3 数组和指针
arr[j] == *(&arr[0]+j) == *(arr+j) == *(j+arr) == j[arr]