C++ 基础知识 ∈ C++ 编程笔记
Part.I Introduction
这篇文章主要介绍C++中的一些基础知识,是对自己之前记得比较乱的笔记的一个再汇总和整理,主要包括一下几个部分:
- 面向对象的C++和面向过程的C语言之间的区别
- C++中常用的符号和转义字符
- C++中的保留字和
cctype
函数 - C++输入输出与内存
Chap.I C++ 简介
C++是一种面向对象的编程语言。因为笔者最开始接触编程是学习的C语言,首先简要介绍一下C
和C++
的区别之处:
- C是面向过程的(procedure oriented programming—POP)。强调执行的过程,其原理就是将问题分解成一个一个详细的步骤,然后通过函数实现每一个步骤,并依次调用。
- C++是面向对象的(object oriented programming—OOP)。强调对象,由对象实施动作。它是一种以对象为中心的编程思想,就是通过分析问题,分解出一个一个的对象,然后通过不同对象之间的调用来组合解决问题。建立对象的目的不是为了完成某个步骤,而是为了描述某个事物在解决整个问题的过程中的行为。
关于C和C++的区别,网上有个很出名的例子:『把大象放入冰箱里面』。这个例子涉及两个对象:大象和冰箱(别问我为什么没有开冰箱的人,冰箱自己会开👀);三个动作:打开冰箱、放入大象、关闭冰箱
如果是面向过程的语言会这样操作:首先打开冰箱门,然后把大象放入进去,最后关闭冰箱门。
如果是面向对象的语言会这样操作:首先定义一个冰箱类,他有打开的方法,放置的方法,关闭的方法。然后再定义一个大象类。接下来构建冰箱和大象的对象,然后冰箱对象调用打开门的方法,冰箱对象再调用放置大象对象的方法,最后冰箱对象关门。
ps:单看这个例子,好像面向对象比较复杂一些。实际上,面向过程适合解决一些步骤比较少的操作;面向对象则适合解决操作比较繁琐,对象关系复杂的问题(使用面向对象的思想可以让关系更清晰)。
Chap.I C/C++ 标准
我们在很多地方会看到关于C/C++的标准,比如K&R C、ANSI C、ISO C、C89、C99、C11、C14、C20等。这是什么意思呢?笔者理解为:语言的一种规范(怎样写是合乎规则的,是合理合法的),下面有几篇文章可以详细了解一下:
什么是ANSI C标准?
C++ 最新(2021)标准特性、框架、教程
头文件命名约定
头文件类型 | 约定 | 示例 | 说明 |
---|---|---|---|
C++旧式风格 | 以.h结尾 | iostream.h | C++程序可以使用 |
C旧式风格 | 以.h结尾 | math.h | C、C++程序可以使用 |
C++新式风格 | 没有扩展名 | iostream | C++程序可以使用,使用namespace std |
转换后的C | 加上前缀c,没有扩展名 | cmath | C++程序可以使用,可以使用不是C的特性,如namespace std |
Part.II 符号含义
Chap.I 常用符号含义
下面是一些运算符号及其含义
符号 | 含义 | 符号 | 含义 |
---|---|---|---|
+ | 加 | - | 减 |
* | 乘 | / | 除 |
++ | 自增,整数值增加1 | -- | 自减,整数值减少1 |
< | 小于 | <= | 小于等于 |
== | 等于 | > | 大于 |
>= | 大于等于 | != | 不等于 |
% | 取模 | ∣ ∣ || ∣∣ | 或 |
&& | 和 | ! | 非 |
& | 位『与』运算 | ∣ | ∣ | 位『或』运算 |
^ | 位『异或』运算 | ~ | 位『取反』运算 |
<< | 二进制『左移』运算(左边的二进制位丢弃,右边补0) | >> | 二进制『右移』运算(正数左补0,负数左补1,右边丢弃) |
= | 赋值,右边赋值给左边 | x= | 进行x 运算并赋值,x 可以是加减乘除,取模,左右移,位运算等 |
. | 成员运算符 | -> | 成员运算符,左边是指针 |
& | 指针运算符,返回变量的地址 | * | 指针运算符,指向一个变量 |
?: | 条件运算符 | e1?e2:e3 | e1成立,执行e2,;否则e3 |
注:
- 位运算『或』指的是
a
或b
是1
,那么返回1
;位运算『异或』指的是a
和b
不一样,则返回1
。 - 关于位的『异或』运算,一般有这样的常用结论:
1^3=2;2^3=1;
这是笔者偶然看一位大佬的代码所学到的,其解释如下:1
的二进制码为01
,3
的二进制码为11
,他俩『异或』就是10
即2
。2^3=1;
同理。 &a
返回变量a
的实际地址;*a
将指向变量a
。
运算符的优先级如下(上面的优先于下面的):
类别 | 运算符 | 结合性 |
---|---|---|
后缀 | () [] -> . ++ - - | 从左到右 |
一元 | + - ! ~ ++ - - (type)* & sizeof | 从右到左 |
乘除 | * / % | 从左到右 |
加减 | + - | 从左到右 |
移位 | << >> | 从左到右 |
关系 | < <= > >= | 从左到右 |
相等 | == != | 从左到右 |
位与 AND | & | 从左到右 |
位异或 XOR | ^ | 从左到右 |
位或 OR | ∣ | ∣ | 从左到右 |
逻辑与 AND | && | 从左到右 |
逻辑或 OR | ∣ ∣ || ∣∣ | 从左到右 |
条件 | ?: | 从右到左 |
赋值 | = += -= *= /= %=>>= <<= &= ^=
∣
=
|=
∣= | 从右到左 |
逗号 | , | 从左到右 |
Chap.II ASCII 码表与转义字符
ASCII 码表格
ASCII
码是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准ISO/IEC 646
。ASCII
第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符。它定义了字符之间的大小顺序,可以用数字来表示字母。
#include <stdio.h>
int main(){int a=65,b=97;printf("%c,%c",a,b);getchar();}
------------ output ---------
A,a
有两类字符程序员不能直接使用,第一类是不可打印的字符,如换行符,响铃符,制表符等等,这些字符没有办法通过直接输入得到直接的输出;第二类是在 C++
中有特殊含义的字符,这类字符同样没有办法通过直接输入得到直接的输出,这两类字符都只能通过转义序列进行实现,下面是一些C++
转义序列的编码:
字符名称 | ASCII符号 | C++代码 | 十进制ASCII码 | 十六进制ASCII码 |
---|---|---|---|---|
换行符 | NL(LF) | \n | 10 | OxA |
水平制表符 | HT | \t | 9 | ox9 |
垂直制表符 | VT | \v | 11 | OxB |
退格 | BS | \b | 8 | Ox8 |
回车 | CR | \r | 13 | OxD |
振铃 | BEL | \a | 7 | Ox7 |
反斜杠 | \ | \\ | 92 | ox5C |
问号 | ? | \? | 63 | Ox3F |
单引号 | ' | \' | 39 | 0x27 |
双引号 | " | \" | 34 | 0x22 |
Part.III 关键字&字符函数
Chap.I 关键字
关键字也常被称为保留字
关键字 | 关键字 | 关键字 | 关键字 |
---|---|---|---|
alignas | alignof | bool | asm |
auto | break | case | catch |
char | char16_t | char32_t | const |
constexpr | class | const_cast | continue |
decltype | default | delete | do |
double | dynamic_cast | else | enum |
explicit | export | false | float |
for | extern | friend | goto |
if | inline | int | long |
mutable | namespace | new | noexcept |
nullptr | operator | private | protected |
public | register | reinterpret_cast | return |
short | signed | sizeof | static |
static_assert | static_cast | struct | switch |
template | this | thread_local | throw |
true | try | typedef | typeid |
typename | virtual | union | unsigned |
using | void | volatile | wchar_t |
while |
Chap.II cctype 函数
C++从C语言中继承了一个与字符相关的函数库(cctype),它可以确定字符是否为大写或小字母、数字、标点符号等工作,这些函数包含在以下头文件中#include<cctype>
下面是 cctype
中的函数:
函数名称 | 返回值 |
---|---|
isalnum() | 如果参数是字母数字,即字母或数字,该函数返回true |
isalpha() | 如果参数是字母,该函数返回true |
iscntrl() | 如果参数是控制字符,该函数返回true |
isdigit() | 如果参数是数字(0~9) ,该函数返回true |
isgraph() | 如果参数是除空格之外的打印字符,该函数返回true |
islower() | 如果参数是小写字母,该函数返回true |
isprint() | 如果参数是打印字符(包括空格),该函数返回true |
ispunct() | 如果参数是标点符号,该函数返回true |
isspace() | 如果参数是标准空白字符,如空格、进纸、换行符、回车、水平制表符或者垂直制表符,该函数返回true |
isupper() | 如果参数是大写字母,该函数返回true |
isxdigit() | 如果参数是十六进制数字,即0~9 、a~f 或A~F ,该函数返回true |
tolower() | 如果参数是大写字符,则返回其小写,否则返回该参数 |
toupper() | 如果参数是小写字符,则返回其大写,否则返回该参数 |
Part.III 输入输出&内存
Chap.I 输入输出
学习一门语言,首先要学会的就是输出Hello World!
,所以学会输入输出是最最基础的!
Sec.I C语言的输入输出
C语言的输入输出比较麻烦,它一般要进行如下include
#include <stdio.h>
然后,输入输出如下:
scanf("%f",&f); // 输入一个浮点数赋值给f,需要用 % 来格式化
printf("Number = %d", testInteger); // 输出,需要用 % 来格式化
C语言输入输出必须通过
%
来格式化:%d
为整数,%f
为浮点数,%c
为char
…另外,还有getchar() & putchar()
,gets() & puts()
函数,详细可参看菜鸟教程
Sec.II C++的输入输出
C++的输入输出很简单,它一般要进行如下的include
#include <iostream>
using namespace std;
接着,输入输出如下:
int a;
cin >> a; // 将输入的数据赋给a
cout << "Hello World!\n"; // 输出,"\n"也可以换成 << endl;
另外,关于输出,一般有三种:cout, cerr, clog
,它们的区别如下:
cout
经过缓冲后输出,默认情况下是显示器。这是一个被缓冲的输出,是标准输出;它在内存中对应开辟了一个缓冲区,用来存放流中的数据,当向cout
流插入一个endl
,不论缓冲区是否满了,都立即输出流中所有数据,然后插入一个换行符。可以被输出到文件,即可以重定向输出
。cerr
不经过缓冲而直接输出,一般用于迅速输出出错信息,是标准错误,默认情况下被关联到标准输出流,但它不被缓冲,也就说错误消息可以直接发送到显示器,而无需等到缓冲区或者新的换行符时,才被显示。clog
流也是标准错误流,作用和cerr
一样,区别在于cerr
不经过缓冲区,直接向显示器输出信息,而clog
中的信息存放在缓冲区,缓冲区满或者遇到endl
时才输出。
缓冲区的目的,就是减少刷屏的次数——比如,你的程序输出圣经中的一篇文章。不带缓冲的话,就会每写一个字母,就输出一个字母,然后刷屏。有了缓冲,你将看到若干句子『同时』就出现在了屏幕上(由内存翻新到显存,然后刷新屏幕)。
Chap.II 内存相关
根据内存分配的方法,C++有4种管理数据内存的方式:自动、静态、动态(有时也叫自由存储空间或堆)、线程存储(C++11新增)
- 自动存储:在函数内部定义的常规变量使用自动存储空间,被称为自动变量(automatic variable)。实际上,自动变量是一个局部变量,其作用域为包含它的代码块。
- 静态存储:静态存储是整个程序执行期间都存在的存储方式。使变量成为静态的方式有两种:一种是在函数外面定义它;另一种是在声明变量时使用关键字static:
static double fee = 56.50;
- 动态存储:
new
和delete
运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理了一个内存池,这在C++中被称为自由存储空间(free store
)或堆(heap
)。该内存池同用于静态变量和自动变量的内存是分开的。 - 自动存储只作用于包含它的代码块;静态存储在整个程序执行期间都存在;动态存储使用
new
和delete
运算符让程序员如何使用内存具有更大的控制权,数据生命周期不受函数和程序生存时间限制。 - 如果使用
new
运算符在自由存储空间(或堆)上创建变量后,没有调用delete
,则即使包含指针的内存由于作用域规则和对象生命周期的原因而被释放,在自由存储空间上动态分配的变量或结构也将继续存在。实际上,将会无法访问自由存储空间中的结构,因为指向这些内存的指针无效。这将导致内存泄漏。被泄漏的内存将在程序的整个生命周期内都不可使用;这些内存被分配出去,但无法收回。