Appearance
C++基础
基本变量类型
- 整形
整形有四种定义:
cpp
short a = 10;
int b = 10;
long c = 10;
long long d = 10;
// 也可以用下面的形式声明
// 用花括号包裹变量是C++11开始允许的
int _age{10}, _name = {"Tom"};
声明与定义的区别:
int b; // 这个是声明
int b = 10; // 这个是定义
虽然都可以表示10这个数值,但是它们占用的内存空间大小,以及最大、最小值是不同的。
类型 | 占用字节 | 取值范围 |
---|---|---|
short | 2 | -2^15~2^15-1 |
int | 4 | -2^31~2^31-1 |
long | 8 | -2^63~2^63-1 |
long long | 8 | -2^63~2^63-1 |
想知道类型大小可以使用sizeof关键字。例如:sizeof(int);
浮点型
字符型
字符型变量创建需要使用单引号
ASCII编码要记住两个:a-97; A-65
如下语句可以查看ASCII码
cpp
cout<< (int)a<<endl;
类型 | 占用字节 | 取值范围 |
---|---|---|
char | 1 | 2^1 |
- 字符串型
如下语句可以定义字符串:
cpp
char str1[] = "hello"; // 变量名后要有中括号,等号后要用双引号
- 布尔
布尔,又叫bool类型,它只有两个值
真 | true | 1 |
假 | false | 0 |
运算符
- 加减乘除
cpp
int a = 9;
int b = 2;
cout << a + b;
cout << a - b;
cout << a * b;
cout << a / b; // 注意除数不可以为 0 !!!
cout << a % b; // 取模,即取余数。小数不可做取模运算
- 递增递减
cpp
int a = 1;
cout << a++; // 输出1
cout << ++a; // 输出2
cout << a--; // 输出1
cout << --a; // 输出0
- 赋值运算符
cpp
// =,以及 符号= 如:
int a = 2;
a += 1; // 等同于 a = a + 1;
a -= 1; // 等同于 a = a - 1;
a *= 1; // 等同于 a = a * 1;
a /= 1; // 等同于 a = a / 1;
a %= 1; // 等同于 a = a % 1;
- 比较运算符
cpp
// 用于比较,并返回一个真值或假值
int a = 2;
int b = 199;
cout << (a > b) << endl; // 假,返回0
cout << (a < b) << endl; // 真,返回1
cout << (a >= b) << endl; // 返回0
cout << (a <= b) << endl; // 返回1
cout << (a != b) << endl; // 返回1
cout << (a == b) << endl; // 返回0
- 逻辑运算符
cpp
// 用于根据表达式的值返回真值或假值
int a = 0;
int b = -1;
cout << !a << endl; // a真则取假,a假则取真
cout << (a && b) << endl; // a、b同时为真才为真,否则为假
cout << (a || b) << endl; // a或b有真就真,都假才假
- 三目运算符
cpp
int a = 2;
int b = 3;
int c = a>b?a:b; // 如果a大于b则返回a,否则返回b
流程结构
任何程序语言必然包含三种流程结构:顺序结构,选择结构,循环结构。
- 顺序结构,即代码逐行执行,没有任何跳转
- 选择结构,即代码视条件是否满足选择性地执行
- 循环结构,即代码视情况反复执行
着重介绍选择结构和循环结构。
选择结构
选择结构需要使用判断语句来实现。判断语句分为if判断语句和switch判断语句。 判断语句以if为主干,分成单条件情况和多条件情况。
if...else... 该语句用于处理单条件情况
if...else if... 该语句用于处理多条件情况
cpp
int a;
cout << "请输入a的值:" << endl;
cin >> a;
// 可以没有else
if( a > 2 ){
cout << "a是大于2的" << endl;
}
// 单条件情况
if( a > 2 ){
cout << "a是大于2的" << endl;
}else{ // else后没有小括号
cout << "a是小于等于2的" << endl;
}
// 多条件情况
if (a <= 2) {
cout << "a是小于等于2的" << endl;
}else if(a > 2 && a < 4){ // else if 后需要小括号
cout << "a是大于2小于4的" << endl;
}else{
cout << "a是大于等于4的" << endl;
}
switch判断语句可以视为方便的多条件判断语句,不用频繁写if...else if...结构。
cpp
int a;
cout << "请输入a的值:" << endl;
cin>>a;
switch(a){
case 0:
cout << "a是0" << endl;
break;
case 1:
cout << "a是1" << endl;
break;
case 2:
cout << "a是2" << endl;
break;
default:
cout << "a是其他值" << endl;
break;
}
/*
switch 小括号里需要判断的必须是个具体的值(数字、字符、字符串)
break 代表退出当前 switch 判断结构。不写 break 意味着继续执行下一个判断
default 代表所有条件都不满足的情况
*/
循环结构
循环结构有三种,for、while、do while 循环结构控制语句有三种:break、continue、goto(不建议使用)
cpp
// while循环结构——演示
int i = 0;
while(i<10){ // 一定注意不要写死循环,即判断条件永远为真
i++;
if(i==5){
break; // 意味着当i等于5的时候跳出while循环
}
}
cout << i << endl;
/*
可以尝试去掉if结构再运行
while(i<10){ // 一定注意不要写死循环,即判断条件永远为真
i++;
if(i==5){
break; // 意味着当i等于5的时候跳出while循环
}
}
*/
cpp
// do-while循环结构——演示
int i = 0;
do{
i++;
cout << i << endl;
}while(i<10);
cpp
// do-while循环结构——演示
int i = 0;
int b = 0;
for(int i = 0;i<10;i++){ // 注意这里的i与外面的i是不同的
b++;
if(i==5){
continue; // 由于这句的存在,循环体会跳过后面的代码,所以b会少输出一个数
}
cout << b << endl;
}
cout << i << endl;
// for循环的结构内相当于一个新的区域
数组
cpp
// 一维数组
// 定义方法:
// 1. 数据类型 数组名[数组长度];
// 2. 数据类型 数组名[数组长度] = { 值1,值2, ...};
// 3. 数据类型 数组名[] = { 值1, 值2, ...};
int arr1[5]; // 数组元素下标从0开始,数组值默认为0
int arr2[5] = { 1,2,3,4,5};
char arr3[] = {'a','b','c'};
// 修改\添加
arr3[0] = 'b'; // 修改
arr3[3] = 'd'; // 添加
cout << arr3[0] << endl;
cout << arr3[3] << endl;
cpp
// 二维数组
// 定义方法:
/*
1. 数据类型 数组名[行数][列数];
2. 数据类型 数组名[行数][列数] = { {值1,值2},{值3,值4}, ...};
3. 数据类型 数组名[行数][列数] = { 值1,值2, ...};
4. 数据类型 数组名[][列数] = { 值1, 值2, ...};
花括号内部不分成更多组花括号的话,系统会自动推测长度,从而匹配各个下标对应的值
*/
int arr1[2][2]; // 两行两列,总共能存4个值
char arr2[2][3] = {'a','b','c','d','e','f'};
cout << arr2[0][2] << endl;
cout << arr2[1][2] << endl;
函数
cpp
/*
返回值类型 函数名(参数列表){
函数体
}
注意,函数里不可以定义函数,但可以声明
*/
int add(int, int); // 函数声明时参数名不重要,类型重要
int add(){ // 定义函数时,参数要写清类型
return a+b;
}
add(1,2); // 调用函数,参数不用写类型
/*
如果有返回值,则要写对应的返回值类型。如果没有,返回值类型要写void
如果void,则没必要写return
*/
函数内容全部写在一处,修改和理解起来都很困难,所以最好是分多个文件去写。(基础篇中先介绍最简单的,后续的篇章中再涉及更复杂的分法)
cpp
// xxx.h 创建一个.h文件(头文件),用于声明变量和函数
// learncpp.h
void add(int a);
// learncpp.cpp
#include "learncpp.h" // 非官方提供的,都需要通过双引号引用
void add(int a){
cout << a+1 << endl;
}
指针
指针用于间接访问内存。32位操作系统下占用4个字节的内存空间,64位操作系统下占用8个字节。
Tips: 计算机有两个区域存储变量,一个叫栈,一个叫堆。一般的变量会直接在栈中存储,而有些变量则会存储到堆中(暂时可以不关心哪些存在栈中,哪些存在堆中)。当计算机想要寻获存在堆区域的某一些变量的时候,会首先访问存储地址,然后根据地址再进一步查找。
Tips2: 如果不理解上面这段,可以先把内存假想成一个超巨大的旅馆,变量是旅客,“变量存储”就是旅客住进旅店。当想要找到旅客时,只需要旅客所在的房间号即可。
cpp
int a = 100;
int* b = &a; // 通过 类型* 变量名这种方式声明一个指针变量,然后使用 &符号,获取a的内存地址值
// 指针变量,存的是地址值,切记切记!
cout << b << endl; // 会输出地址值。地址值是十六进制存储的
cout << *b << endl; // 会输出地址里存储的值,也就是输出"旅客"
// 这里最大的问题是会记混。多书写几次记牢即可。要能够熟练写出:
// 1. 指针变量的声明和定义
// 2. 如何获取变量地址
// 3. 如何获取地址里存放的值
指针也有空指针、野指针。
- 空指针,即指针变量指向编号为0的空间,用于初始化指针变量。该内存是不可访问的(0~255是系统占用的、不可访问的内存空间)
- 野指针,指针变量指向非法的内存空间
cpp
int* p = NULL; // 指向NULL,定义空指针
int* n = (int*)0x1100; // 假设0x1100是一块已开辟空间,当前操作会指向该空间,但实际上不应该随意将指针指向当前空间,赋予其操作权限
const修饰 指针,称为 常量指针。常量指针的指向可改,但是指向地址内的值不可改
const修饰 变量,该变量类型为指针,则它被称为 指针常量。这种情况下,指针指向不可改,值可改
实际上,指针、变量都可以被const修饰。此时,指向和值都不可以改。
cpp
int a = 10;
int b = 100;
const int* p = &a;
*p = 20; // 该句会有错误提示,因为它是一个常量指针,值不可更改
p = &b;
// ------------------------------------------
int* const n = &a;
*n = 10;
n = &b; // 该句会有错误提示,因为它是一个指针常量,指向不可更改
// ------------------------------------------
int* const k = &a;
*k = 10;
k = &b; // 都会有错误提示,指向和值都不可更改
指针和数组
cpp
int arr[3] = {0,1,2};
int* p = arr; // 数组名即数组首地址
cout << *p << endl;
p++;
cout << *p << endl;
p++;
cout << *p << endl;
p++;
cout << *p << endl; // 该行是多写的。可以运行看一下是什么情况
// 最后一个输出超出了数组的内存空间
// 使用指针,可以快捷访问类似数组这样按顺序存储的数据结构
指针和函数
cpp
void swap(int* a,int* b){
int temp = *a;
*a = *b;
*b = temp;
}
// 下面这些写在main函数里
int a = 10;
int b = 100;
swap(&a,&b);
cout << a << endl;
cout << b << endl;
// a和b的值被互换了
结构体
结构体是用户自定义的数据类型,允许用户将不同数据类型组合成一个数据类型。
cpp
// 创建方式
//struct 结构体名 { 结构体成员列表 };
struct Student {
string name;
int age;
};
// 创建结构体变量
// struct 结构体名 变量名;
// struct 结构体名 变量名 = { 值1,值2,...};
struct Student student;
struct Student student = { "tony",16 };
// struct 结构体名 {} 变量名;
// 这种方式可以同时创建与声明变量。推荐使用上面两种。
struct People {
string name;
string gender;
} people;
// 声明变量之后可以为其中的内容赋值
people.name = "张三";
people.gender = "男";
cout << people.name << endl;
cout << people.gender << endl;
结构体数组
cpp
// 定义方式
// struct 结构体名 数组名[元素个数] = {{}, {}, {}};
struct Student student[2] = {
{"tony",16},
{"tom",18}
};
cout << student[1].name << endl;
// struct 结构体名 {} 变量名[]; 方括号内可以给定数组长度,也可不给。
struct People {
string name;
string gender;
} people[];
结构体指针
通过指针访问结构体中的成员。访问符号是->(结构体后打'.',当语句完成时系统会自动帮忙转换)。
结构体可以嵌套。
cpp
struct People {
string name;
string gender;
} people;
people.name = "张三";
people.gender = "男";
People* p = &people;
cout << p->name << endl;
传址调用结构体
cpp
struct People {
string name;
string gender;
};
void printStructures(People* p) {
p->name = "冬青";
}
int main() {
struct People p = { "张三", "男" };
printStructures(&p);
cout << p.name << endl;
system("pause");
return 0;
}
// 使用指针的原因如下:
/*
1. 函数中使用传值,会将整个值复制进内存,也就是当值的长度超长时,也不得不传递一个超长的值。如果使用指针,以传址方式传递,那么32位系统只需传递4字节,64位系统只需传递8字节,大大节省内存空间
*/