C++从入门到放弃
C++ 数据类型
1. 结构体
- 定义结构体变量时,可以省略struct关键字
- 在结构体里面可以直接定义函数,该函数称为成员函数,在成员函数中可以直接访问结构体中的其他成员变量
- 成员的默认访问权限::struct是public,class是private
//1
//1>直接声明+定义
struct{
//结构体成员
}结构体变量名;
//2>赋值
结构体变量名.结构体成员 = 值;
//2
//1>声明
struct 结构体名{
结构体成员
};
//2>定义结构体变量
//struct 结构体名 结构体变量;
结构体名 结构体变量;//C++可以省略struct关键字
//3>赋值
结构体变量.结构体成员 = 值;
//3
//1>声明+起别名
typedef struct 结构体名{
int age
}结构体别名;
//2>使用别名定义结构体变量
结构体别名 结构体变量;
//3>赋值
结构体变量 = 值;
2. 联合体
- C++定义联合体变量时,可以省略union关键字
- C++支持匿名联合,匿名联合体是不同时定义任何变量(包含联合体类型的对象、引用或指向联合体的指针)的无名联合体定义,在同一时刻时,只有一个成员会起作用
- 匿名联合在使用时可以直接使用成员名来赋值或其他操作
#include <iostream>
using namespace std;
int main (){
union{
//匿名联合
unsigned int ui;
unsigned char uc[4];
};
ui = 0x12345678;
for(int i=0; i<4;i++)
{
//hex:十六进制打印整数
//showbase:显式"0x"进制标识
cout<<hex<<showbase<<(int)uc[i]<<' ';
}
cout<<endl;
getchar();
return 0;
}
./Cpp.exe
0x78 0x56 0x34 0x12
3. C++枚举和枚举类(“魔数”)
- C++ 定义枚举变量时可以省略enum关键字
- C++中枚举被看做独立的数据类型,不能把枚举变量直接当做整形变量那样去使用
/*
C/C++语言可以使用#define和const创建符号常量,而枚举不仅可以创建符号常量,还可以创建新的数据类型。它是由自己定义若干个枚举常量的集合,属于派生类型。“枚举”一词顾名思义就是将可能出现的情况一一列举出来。打简单比方,人类按肤色只分为三种:黄种人、白种人、黑种人不会再有其它肤色人种,也就是说一个变量仅只有几种情况,那么我们可以定义枚举类型。
*/
// 1) 声明 e_human 为新的类型,称作枚举
// 2) 声明 yellow,white,black 枚举量. 默认值0-2
enum e_human {yellow, white, black};
// 4) 声明 e_human 类型的变量,就像声明基本类型 int 变量一样,例:int number;
e_human person;
// 5) 赋值上与基本类型不一样,不进行强转情况下,只能赋值定义的枚举量
person = yellow;
// 6) 可以将枚举量赋值给非枚举变量
int i_yellow = yellow;
// 7) 枚举量不能进行算术运算,如 person++ 是不允许的. 违反类型限制,失去枚举类型的初衷
// person++; // [错误]
// 8) 枚举量可以参加与其他类型变量的运算,编译器自动将枚举量转换为int类型
int i;
i = person + 1;
// 9)如果只打算使用枚举量而不去创建枚举类型变量,则可以省略枚举类型的名称
enum {yellow, white, black};
// 10) 显示赋值枚举量,指定的值必须是整数
enum e_human_two {yellow = 1, white = 100, black = 3};
// 11) 可全部赋值,也可部分赋值. yellow 默认情况为 0,white = 100,因此 black 为 101
enum e_human_two { yellow, white = 100, black };
// 12) 与5)等同.书中说道获取取值上限,知道枚举量最大值方法为:找到大于这个的最大值、最小值的2的幂减一
person = e_human(2);// 赋位于枚举定义的取值范围,超出范围则结果无意义
- 枚举类
C++新标准可以指定枚举类的基本类型,默认基本类型为int类型
枚举类相对于普通枚举类型的优势
- 强作用域,将其作用域限制在枚举类中,不同的枚举类中可以拥有同名的对象,不会发生冲突
//使用普通枚举类型
enum e_week1 {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
enum e_week2 {Sun, Mon, Tue, Wed, Thu, Fri, Sat};//ERROR : 会冲突
//使用枚举类
enum class e_week1 {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
enum class e_week2 {Sun, Mon, Tue, Wed, Thu, Fri, Sat};//不冲突
- 使用
e_week
的枚举值Sun
时需要加上::
e_week::Sun
- 转换限制,枚举类对象不可以与整形隐式的相互装换
- 可以枚举类的指底层类型
enum class 枚举类型名{枚举值列表};
enum class 枚举类型名:底层类型{枚举值列表};
//枚举类
//语法形式
//enum class 枚举类型名:底层类型{枚举值列表};
enum class e_week {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
enum class e_week {Sun, Mon = 1, Tue, Wed, Thu, Fri, Sat};
enum class e_week:char {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
4. C++字符串
1> c++中兼容C语言字符
- 字面值常量字符串:
XXX
- 字符指针:
char* p = "XXX";
- 字符数组:
char arr[3] ={'X','X','X'};
- 字符指针中保存的字符串是保存在常量区的,因此字符指针可以改变但是字符指针指向的字符串不可以改变,字符指针可以进行
++/--
操作 - 字符数组中保存的变量时保存在堆栈的,因此字符数组中保存的字符串是可以改变,字符数组名可以看作
char* const
,不可以进行++/--
操作,但是字符数组的每个成员是支持++/--
操作 - 字符数组表示字符串的缺点
当执行字符串的连接,拷贝,比较等操作时,都要显示调用库函数
当字符串长度很不确定是,需要用new动态创建字符数组,最后通过delete释放
字符串实际长度大于为他分配的控件时,就会产生数组下标越界访问错误
字符串使用中容易出现的问题:
- 段错误
- 内存越界
通过dubg查找越界段错误问题
gcc -g //编译成gdb调试文件
gdb ./a.out //通过gdb运行可执行文件
r //开始运行
n //下一步
s //进入函数内部
当出现段错误时会触发信号
bt //检查段错误对应位置
2> C++ string类
string类的字符串是new动态分配的存放于堆区
- string 类常用的构造函数
string();
string str1;//默认构造函数,无参构造建立一个长度为0的串
string(const char *s);
string str2("abc");//调用参数为`const char*` 的构造函数
string(const string& s);
string str3(str2);//调用复制(拷贝)构造函数
- 析构函数
当string对象离开作用域销毁时,会自动调用析构函数delete
掉new
创建的对象
- string 类常用操作符
- 字符串拷贝: =
string str1 = "hello";
string str2 = "world";
str1 = str2;//拷贝
cout<<str1<<' '<<str2<<endl; //hello hello
- 字符串拼接: += / +
string str1 = "hello ";
string strw = "world";
str1 += str2;
cout<<str1<<endl; //hello world
+=
对于字符串,字符有效,对于数字会转为asc码
string s;
s+="hello";
s+=" world";
s+='5';
s+=10;//10对应的asc码是换行
int a=5;//想把a加入字符串
s+=(a+'0');
cout<<s;
- 字符串比较: == != > < >= <=
string str1 = "hello ";
string str2 = "world";
str1 == str2 ? 1:2;
cout<<str1<<endl; //world
- 字符串随机访问: []
string str = "hello world";
str[0] = 'H';
str[6] = 'W';
cout<<str<<endl; //Hello World
- string类常用的成员函数
getline
获取一行数据\n
结尾
string str = "hello world";
//1>获取有效字符串长度 size()
int length = str.size();
cout<<length<<endl; //11
c_str
string
转换为 const char*
const char* str = str.c_str();
printf("%s",str)//hello world
erase
删除某个元素
/**begin是头迭代器,end是尾迭代器*/
string str="5418340";
str.erase(s.begin());//删除第一个元素
str.erase(--s.end());//删除最后一个'/0'前面的元素
cout<<str;
substr
函数 截取字符串
/**begin是头迭代器,end是尾迭代器*/
string s="5418340";
s=s.substr(1,3);//取418,取索引为1,往后截断3个
s=s.substr(1,-1);//索引为1,截断到最后
cout<<s;
/*
0. 用途:一种构造string的方法
1. 形式:s.substr(pos, n)
2. 解释:返回一个string,包含s中从pos开始的n个字符的拷贝(pos的默认值是0,n的默认值是s.size() - pos,即不加参数会默认拷贝整个s)
3. 补充:若pos的值超过了string的大小,则substr函数会抛出一个out_of_range异常;若pos+n的值超过了string的大小,则substr会调整n的值,只拷贝到string的末尾
*/
- 读取键盘输入的数据到string类型的字符串中
//1>cin
cin>>str; //碰到' '结束
//2>getline 要包含string头文件
getline(cin,str);//默认碰到'/n'结束
getline(cin,str,',');//以','为分隔符
- string
3> 动态数组应用代码
#include<iostream>
#include<cstring>
using namespace std;
char* getname(void);
int main(void)
{
char* name;
name = getname();
cout << "The length of " << name << " is " << strlen(name) << endl;
delete [] name;
name = getname();
cout << "The length of " << name << " is " << strlen(name) << endl;
delete [] name;
system("pause");
}
char* getname()
{
char temp[80];
cout << "Enter last name: ";
cin >> temp;
char* pn = new char[strlen(temp)+1];
strcpy(pn, temp);
return pn;
}
/*
动态数组实际是在getname函数中建立的,通过临时字符数组temp存储输入的字符串,通过strlen(temp)+1计算需要的字符串长度提供给new,实现开辟对应大小的内存空间,并通过strcpy(pn, temp)将字符串复制到新开辟的内存处
这样做可以每次都创建刚好能够存储输入字符串的内存块,在读取大量字符串的程序中,可以节省大量内存
需要注意的是,这里new和delete放在了不同的函数中,这样是可以的,但容易忘记delete
*/
5. C++的布尔类型(bool)
- 在C++中bool类型为基本数据类型,用来表示逻辑值,逻辑真用
true
,逻辑假用false
表示 - bool类型在内存中占一个字节:
1
表示true
,0
表示false
- bool类型的变量可以接受任意类型的表达式结果,值
非0
则true
,为0
则false