C++学习笔记 —— 基础知识

(一)基础知识

1. 发展历史

  • C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程泛型编程
  • C++ 被认为是一种中级语言,它综合了高级语言和低级语言的特点。
  • C++ 是由 Bjarne Stroustrup 于 1979 年在新泽西州美利山贝尔实验室开始设计开发的。C++ 进一步扩充和完善了 C 语言,最初命名为带类的C,后来在 1983 年更名为 C++。
  • C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。

2. 变量

2.1 数据类型

  • 在c++中,变量保存的是它所存储的值的内存地置。当您创建一个变量时,就会在内存中预留一些空间。
  • 空间预留多少合适,这就由变量的数据类型所决定。
  • 在C++中数据类型不仅可以预留空间,还可以决定内存中存什么。
  • 在C++中数据类型包括:char、int、float、double、bool、void等。
2.1.1 基本的数据类型

C++ 为程序员提供了种类丰富的内置数据类型和用户自定义的数据类型。下表列出了七种基本的 C++ 数据类型:

类型关键字
布尔型bool
字符型char
整型int
浮点型float
双浮点型double
无类型void
宽字符型wchar_t

2.2 修饰符

在C++中,charintdouble前面可以添加修饰符,改变原来类型的含义,来适应更多情景的需求。
下面列出了数据类型修饰符:

  • signed
  • unsigned
  • long
  • short

其中,signedunsignedlongshort用来修饰整型,signedunsigned用于修饰字符,long用来修饰双精度型。

2.3 字符串

C++延续了 C 的字符串风格,用 null 字符 \0 终止的一维字符数组。

char a[6] = {'H', 'E', 'L', 'L', 'O', '\0'};

下面的声明和初始化创建了一个 HELLO 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 HELLO 的字符数多一个。而在打印时不会输出 \0 。
根据上面的书写方法,我们可以写成:

char a[6] = "HELLO";

两种书写方法,输出的效果是一样的。

2.4 数组

  • 数组可以存储一固定大小、类型相同的集合。但它往往被认为是一系列相同类型的变量。
  • 数组的声明并不是声明一个个单独的变量,比如 number0、number1、…、number99,而是声明一个数组变量,比如 numbers,然后使用 numbers[0]、numbers[1]、…、numbers[99] 来代表一个个单独的变量。数组中的特定元素可以通过索引访问。
    在C++中,在声明一个变量的时候要指定元素类型和元素的数量。
type arrayName[size];
// 其中size必须为一个大于0的整型变量。
// type 可以是任意有效的 C++ 数据类型

2.5 变量的作用域

在C++ 有三个地方可以声明变量:

  • 在一个函数或代码块内部声明的变量,叫局部变量
  • 在函数参数的定义中声明的变量,叫形式参数(形参);
  • 在所有函数外部声明的变量,叫全局变量

下面是一个例子:

#include <iostream>
#include <string>

using namespace std;

string a = "全局变量"; 
 
void vari(string b){
	string c = "局部变量"; 
	
	cout << "a 是:" << a << endl;
	cout << "b 是:" << b << endl;
	cout << "c 是:" << c << endl;
}

int main() {
	
	vari("形式参数");
	return 0;
}

运行结果:

a 是:全局变量
b 是:形式参数
c 是:局部变量

4. 常量

常量是什么,常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量
常量可以是任何的基本数据类型,可分为整型数字、浮点数字、字符、字符串和布尔值。
常量就像是常规的变量,只不过常量的值在定义后不能进行修改

4.1 常量的类型

在 C++ 中常量有多种类型,操作系统会根据常量的数据类型,来分配内存和决定在静态存储区中存储什么。

下面列出了 C++ 中常量的类型:

  • 整型常量
  • 浮点常量
  • 布尔常量
  • 字符常量
  • 字符串常量
4.1.1 整型常量

整型常量可以是不同进制的常量。
在 C++ 中用不同的前缀来表示常量的进制,0x 表示十六进制,0 表示八进制,不带前缀则表示十进制。
在 C++ 中不仅有前缀还有后缀,后缀是 UL 的组合。后缀不区分大小写,顺序可以任意。

  • U:表示无符号整数(unsigned)
  • L:表示长整数(long)
212         // 合法的
215u        // 合法的
0xFeeL      // 合法的
078         // 非法的:8 不是八进制的数字
032UU       // 非法的:不能重复后缀
4.1.2 浮点常量

浮点常量由整数部分小数点小数部分指数部分组成。我们可以使用小数形式或者指数形式来表示浮点常量。

当使用小数形式表示时,必须包含整数部分小数部分,或同时包含两者。
当使用指数形式表示时, 必须包含小数点指数,或同时包含两者。带符号的指数是用 eE 引入的。

3.14159       // 合法的 
314159E-5L    // 合法的 
510E          // 非法的:不完整的指数
210f          // 非法的:没有小数或指数
.e55          // 非法的:缺少整数或分数
4.1.3 布尔常量

布尔常量总共就两个:

  • true:表示真;
  • false:表示假。
4.1.4 字符常量

字符常量是括在单引号中
如果常量以 L(大写的)开头,则表示它是一个宽字符常量(例如 L’x’),此时它必须存储在 wchar_t 类型的变量中。否则,它就是一个窄字符常量(例如 ‘x’),此时它可以存储在 char 类型的简单变量中。

字符常量可以是一个普通的字符(例如 ‘x’)、一个转义序列(例如 ‘\t’),或一个通用的字符(例如 ‘\u02C0’)。

转义字符

在 C++ 中,并不认为 '," ,\ 是字符。

  • 单引号是单个字符的界限 ‘s’ ;
  • " 双引号是字符串的界限 “Hello” ;
  • ** 反斜线是转义符号 ‘\t’ (水平制表符)。

其中,转义字符是一些特定的字符,有着特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。
所以的 ASCII码 都可以用 \ 加数字(八进制数字)来表示。而在 C 中定义了一些字母前加 \ 来表示ASCII编码表中一些常见的控制字符,如\0 ,\t ,\n 等,就称为转义字符,因为后面的字符,都不是它本来的ASCII字符意思了。
下表列出了一些这样的转义序列码:

转义序列含义
\\ 字符
\’’ 字符
\"" 字符
\?? 字符
\a警报铃声
\b退格键
\f换页符
\n换行符
\r回车
\t水平制表符
\v垂直制表符
\ooo一到三位的八进制数
\xhh . . .一个或多个数字的十六进制数

举个例子:

//	转义字符
const char A = '\101';	// “101”是个八进制数字
cout << A << endl;

执行结果:

A
4.1.5 字符串常量

字符串常量是用双引号(“”)括起来的0个或者多个字符组成的序列
在存储中编译器会为每个字符串结尾加上 ‘\0’ 作为字符串结束标志。
例子1:

const string HELLO = "Hello World!";
cout << HELLO << endl;

执行结果:

Hello World!

4.2 定义常量

在 C++ 中,有两种定义常量的方式:

  • #define 预处理器;
  • const 关键字。
4.2.1 #define 预处理器
  • 预处理器
    预处理器是一些指令,指示编译器在编译之前所需完成的预处理。
    所有的预处理器指令都是以符号 # 开头。预处理指令不是 C++ 语句,所以它们不会以分号(;)结尾。

#define 预处理指令用于创建符号常量。该符号常量通常称为,指令的一般形式是:

#define 常量名 常量的值;

例子:

#include <iostream>
using namespace std;

#define PI  3.1415926

int main(){
	cout << PI << endl;
	return 0;
}

执行结果:

3.1415926
4.2.2 const 关键字

const 关键字定义的常量比较特殊,声明的是一个变量,还具有常量的属性。值不可被改变,不能重新赋值,具有只读性,所以,有人又称 const 声明的是一个常变量
定义方法为:

const 数据类型 常量名 =;

例子:

const int num = 10;
cout << num << endl; 

执行结果:

10

const 关键字声明的常量,是可以通过指针改变的。

6. 存储类

存储类是用来定义 C++ 的变量和函数的范围和生命周期。
下面列出 C++ 程序中可用的存储类:

  • auto
  • register
  • static
  • extern
  • mutable
  • thread_local

6.1 auto 存储类

auto 关键字使用:

  1. 声明变量时根据初始化表达式自动推断该变量的类型;
  2. 声明函数时函数返回值的占位符
auto f=3.14;      //double
auto s("hello");  //const char*
auto z = new auto(9); // int*
auto x1 = 5, x2 = 5.0, x3='r';//错误,同时声明多个变量时,必须是初始化为同一类型

6.2 register 存储类

register 定义的是一个局部变量。这个局部变量不是存储在RAM中,而是存储在寄存器中。这也就意味着变量占用空间的最大尺寸等于寄存器的大小,并且不能对它应用一元的 ‘&’ 运算符(因为它没有内存位置)。

 register int  miles;

寄存器只用于需要快速访问的变量,比如计数器。

6.3 static 存储类

static 存储类告诉编译器在程序的生命周期内保持局部变量的存在,也就是说 static 关键字所修饰的的关键字,在程序结束之前是不会被创建销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
static 关键字除了修饰局部变量外,还可以修饰全局变量,在修饰全局变量时,会使变量的作用域限制在声明它的文件内。

6.4 extern 存储类

extern 存储类用于声明一个全局变量,这个全局变量对所有的程序文件都是可见的。
举个例子:

// main.cpp
#include <iostream>

int c;

extern void write_extern();

int main() {
	c = 15;
	write_extern();
}

在新建一个 support.cpp 来实现两程序间的共享:

// support.cpp

#include <iostream>

using namespace std;

extern int c;

void write_extern(void) {
	cout << "Count is " << c << endl;
}

6.5 thread_local 存储类

使用 thread_local 说明符声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。
thread_local 说明符可以与 static 或 extern 合并。
可以将 thread_local 仅应用于数据声明和定义,thread_local 不能用于函数声明或定义。
以下演示了可以被声明为 thread_local 的变量:

thread_local int x;  // 命名空间下的全局变量
class X
{
    static thread_local std::string s; // 类的static成员变量
};
static thread_local std::string X::s;  // X::s 是需要定义的
 
void foo()
{
    thread_local std::vector<int> v;  // 本地变量
}

7. 控制结构

程序控制结构是指以某种顺序执行的一系列动作,用于解决某个问题
理论和实践证明,无论多复杂的算法均可通过顺序选择循环 3种基本控制结构构造出来。
每种结构仅有一个入口和出口。由这3种基本结构组成的多层嵌套程序称为结构化程序

7.1 循环

一般程序在执行的时候是,第一句、第二句 ······ 第N句,这样顺序执行的。可是,有的时候,一段代码可能需要重复执行很多次,这时候要是执行一遍写一次的话,这样工作量就太大啦。于是,为解决这个问题 C++ 引入了循环操作。
在 C++ 中有多种循环类型:while 循环、for 循环、do…while 循环、嵌套循环。

7.1.1 while 循环

只要给定的条件为真,while 循环语句会重复执行一个目标语句。
怎么使用 while 语句呢?那就接着往下看吧:

while( 条件 ){	// 当条件为真时,while会一直重复执行大括号中的内容,直到条件为假
	代码块
}

举个例子:

#include <iostream>
using namespace std;
 
int main ()
{
   // 局部变量声明
   int a = 10;

   // while 循环执行
   while( a < 20 )
   {
       cout << "a 的值:" << a << endl;
       a++;
   }
 
   return 0;
}

执行结果:

a 的值:10
a 的值:11
a 的值:12
a 的值:13
a 的值:14
a 的值:15
a 的值:16
a 的值:17
a 的值:18
a 的值:19
7.1.2 for 循环

语法

for ( init; condition; increment )
{
   statement(s);
}

下面是 for 循环的控制流:

  • init 会首先被执行,且只会执行一次。这一步允许您声明并初始化任何循环控制变量。也可以不在这里写任何语句,只要有一个分号出现即可。
  • 接下来,会判断 condition。如果为真,则执行循环主体。如果为假,则不执行循环主体,且控制流会跳转到紧接着 for 循环的下一条语句。
  • 执行完 for 循环主体后,控制流会跳回上面的 increment 语句。该语句允许您更新循环控制变量。该语句可以留空,只要在条件后有一个分号出现即可。
  • 条件再次被判断。如果为,则执行循环,这个过程会不断重复(循环主体,然后增加步值,再然后重新判断条件)。在条件变为假时for 循环终止

举个例子:

#include <iostream>
using namespace std;
 
int main ()
{
   // for 循环执行
   for( int a = 10; a < 20; a = a + 1 )
   {
       cout << "a 的值:" << a << endl;
   }
 
   return 0;
}

执行结果:

a 的值:10
a 的值:11
a 的值:12
a 的值:13
a 的值:14
a 的值:15
a 的值:16
a 的值:17
a 的值:18
a 的值:19

7.2 判断

判断结构要求程序员给出一个或多个条件,用户给出的值,符合条件,则为真,程序执行一段代码。如果,不符合条件,则为假,执行另一段代码。
在 C++ 中沿用了 C 中的判断语句,具体有:

语句描述
if 语句一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。
if…else 语句一个 if 语句 后可跟一个可选的 else 语句,else 语句在布尔表达式为假时执行。
嵌套 if 语句您可以在一个 if 或 else if 语句内使用另一个 if 或 else if 语句。
switch 语句一个 switch 语句允许测试一个变量等于多个值时的情况。
嵌套 switch 语句您可以在一个 switch 语句内使用另一个 switch 语句。

8. 函数

函数是一组一起执行一个任务的语句。每个 C++ 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。

您可以把代码划分到不同的函数中。怎么划分那就看你想怎么划分了,我通常是一个任务一个函数。

C++ 标准库提供了大量的程序可以调用的内置函数。例如,函数 strcat() 用来连接两个字符串,函数 memcpy() 用来复制内存到另一个位置。

函数还有很多叫法,比如方法子例程程序,等等。

8.1 函数定义

函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。

C++ 中的函数定义的一般形式如下:

return_type function_name( parameter list ){
   body of the function
}

在 C++ 中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:

  • return_type:指的是返回值的类型,一个函数可以返回一个值。如果, return_typevoid ,这时这个函数就可以没有返回值;
  • function_name:这是函数的实际名称。函数名参数列表一起构成了函数签名。
  • parameter list:参数列表,参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型顺序数量。参数是可选的,也就是说,函数可能不包含参数。参数在声明的时候可以被初始化,不过初始化的参数应在列表的右侧。
  • body of the function:函数主题,函数主体包含一组定义函数执行任务的语句。

举个例子:
两个数比较大小

// 函数返回两个数中较大的那个数
int max(int num1, int num2 = 2)
{
	// 局部变量声明
   int result;
 
   if (num1 > num2)
      result = num1;
   else
      result = num2;
 
   return result; 
}

8.2 函数声明

函数声明会告诉编译器,函数名称和如何调用函数。函数的实际主体可以单独定义
函数声明包括:

函数类型 函数名(参数列表);

在函数声明时,参数的名子不重要,但是必须得有参数的类型。比如上面的 max() 函数声明,可以写成:

int max(int, int)

这样函数依然成立,且意思不变。

8.3 调用函数

当程序调用函数时,程序控制权转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序
如果,这个函数有返回值,则结束时,这个值就被存储在调用函数本身;
比如:

#include <iostream>
using namespace std;

int max(int num1, int num2 = 2) {
	int result;

	if (num1 > num2) {
		result = num1;
	} else {
		result = num2;
	}

	return result;
}

int main(){
	int m = max(4, 5);
	cout << "最大的是:" << m << endl;
	
	return 0;
}

编译执行后:

最大的是:5

此时,输出 max() 函数本身存储的是最大的值 。

8.4 内联函数

内联函数主要是起到,在函数调用时节约调用时的开销。
在 C++ 中,内联函数可以通过 inline关键字 来定义 (注意:是定义而非声明)

下面通过一个例子来讲解:

  1. inline 关键字定义 sum() 函数为内联函数;
  2. 定义num1num2 两个变量,并赋值;
  3. sum() 调用,并将 num1num2 作为 sum() 的参数。
#include <iostream>
using namespace std;

inline int sum(int a, int b){
	return a + b;
}

int main() {
	int num1 = 1;
	int num2 = 2;
	
	cout << sum(num1, num2) << endl;
	return 0;
}

在 main() 函数中,只需要写函数名,就可以调用。内联函数被调用,相当于把函数体中的内容,在重新写一遍来提高执行速度。
上面的 main() 函数可以写成:

int main() {
	int num1 = 1;
	int num2 = 2;
	
	cout << num1 + num2 << endl;
	return 0;
}

需要注意的是,内联函数只能是简单的函数

8.5 重载函数

重载函数,函数名相同,参数不同。
就是创建多个名字相同参数不同的函数,在调用该函数时,编译器根据你传入参数的类型个数来确定执行那个函数。
举个例子:

#include <iostream>
#include <string> 
using namespace std;

void f(){
	cout << "第一个函数。" << endl;
}

void f(int a){
	cout << "第二个函数。" << endl;
}

void f(string c, int a){
	cout << "第三个函数。" << endl;
}
int main() {
	
	int x = 3;
	string y = "fdsg";
	
	f(y, x)f(x);
	f();
	 
	return 0;
}

执行结果:

第三个函数。
第二个函数。
第一个函数。

欢迎大神们进群指导学习

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋禊

兴趣才是前进路上最亮的灯

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值