C++学习笔记(适用于有 C语言基础的)

本文是自己学习C++的笔记,适用与有C语言基础的同学一起学习,中间一些和C语言一致的部分大多没有写

目录

文章目录

第1章 基本概念

1 using的两种用法

1 直接包含整个命名空间

这种方法相当于把整个std中的名称全部包含进来了

#include <iostream>
using namespace std;
int main()
{
    cout<<"hello world"<<endl;
}
  • 优点
  1. 可以直接用std中的名称
  2. std所有的都可以直接用
  • 缺点
  1. 可能会容易出现命名相同的情况

2 只包含命名空间中的某个名称

#include <iostream>
using std::cout;
int main()
{
    cout<<"hello world"<<endl;
}

相对最好

3 直接不包含命名空间

繁琐

#include <iostream>
int main()
{
    std::cout<<"hello world"<<endl;
}

2 转义字符

\n //换行
\t //水平制表符
\v //垂直制表符
\b //退格
\r //回车
\f //换页
\a //警告字符
\   //转义字符

\n和endl的区别没搞清楚

3 幻数

在C++编程中,幻数通常指的是程序中直接使用的常数。这些常数可能是数字、字符串或其他类型的字面量,它们在代码中直接出现,没有明确的命名或定义。使用幻数会使代码的可读性和可维护性降低,因为当需要修改这些值时,必须手动在代码中搜索并替换它们。此外,幻数的存在也增加了代码的耦合性,使得代码更难以重用和测试。

为了避免幻数带来的问题,程序员通常会采取一些策略来管理这些常数。例如,可以使用宏定义(#define)或枚举(enum)来替代幻数。这样,当需要修改这些值时,只需要修改宏定义或枚举的值,而不需要在代码的多个地方进行搜索和替换。同时,这也提高了代码的可读性和可维护性。

ps: cout中<<的作用**

流运算符,可以把它理解为数据流向

"<<"输出流运算符: 作用是把运算符右边的数据输出到运算符左边的目标。

比如cout << 3.14,就是把数字3.14输出到控制台。

">>"流输入运算符: 类比"<<"

float num;

cin >> num;

流运算符可以连续使用

比如cout << 3.14 << “ ” << “hello world!”,控制台就会显示

3.14 hello world!

反过来也是。

float numA;

int numB;

cin >> numA >> numB;

就会依次读入一个float和一个int,这两个在输入时用空格分隔。

vscode cin的问题

找到设置选项,输入run in terminal ,勾选Whether to run code in Integrated Terminal.

第2章 基本数据类型和计算

##1 数字的前缀后缀(进制和符号)

  • 16进制 前缀(0x): 0xFFFFF
  • 8进制 前缀(0(零不是O)): 0123
  • 无符号 后缀u/U
  • long 后缀L或l ,(不推荐用小写L,容易搞混)
  • 对于浮点数
    • float 后缀F或f,
    • double 默认不用加
    • long double 后缀为L

##2 算数优先级

* / % 第一优先

+ - 第二优先
在这里插入图片描述

//常用的+-*/%不说了
// | 按位或
// ~ 按位非
// & 按位与
// ^ 按位异或

3 设置字符占位长度

  cout << setw(10) << 10 + 20 << endl;
  cout << setw(10) << 10 * 20 << endl;

setw(10)将下一个输出的字段宽度设置为括号中的字符数

4 定义变量可以用","隔开后分行

int apples = 10,    //可以这么加注释
	children = 3;

5 多次赋值

a = b = 100; //将100先赋值给b,再赋值给a

6 a++与++a

	int a = 0;
    cout <<"a=" << a << endl;
    cout << "a++=" << a++ << endl;  //先赋值再加一
    cout << "a=" << a << endl;
    cout << "++a=" << ++a << endl;  //先加一再赋值
    cout << "a=" << a << endl;

输出

=0

a++=0

a=1

++a=2

a=2

7 const常量

const int a = 1;
int main()
{
    a++;  //不小心修改了常量,此处会报错
    return 0;
}

8 关于float/double/long double 的精度问题

在这里插入图片描述

代码:(fixed的用法也在此处)

#include <iostream>
#include <iomanip>
//这个代码用于测试float精度的概念
using namespace std;


int main()
{
    float x = 0.123456789f;								 //后面加f表示float
    double y = 0.123456789123456789; 					  //不加默认为double
    long double z = 0.123456789123456789123456789l; 	   //加L表示long double
    cout << setprecision(30) <<fixed;						//修改显示格式
    cout <<setw(30) <<"float保留的位数"<< x <<endl;
    cout <<setw(30)<<"double保留的位数"<< y <<endl;
    cout <<setw(30)<<"long double保留的位数"<< z <<endl;
    cout <<setw(30)<<"long double保留的位数"<< z <<endl;
    return x;
}

output:
          float保留的位数0.1234567               9104328155517578125
         double保留的位数0.12345678912345678     3796584090851
    long double保留的位数0.12345678912345678912  2727263186
  • 后面加f表示float

  • 不加默认为double

  • 加L表示long double

    **这个精度是一个粗略值,如果出现一个相差108的两个数相加,较大的数是没有变化的 **

    float a = 12345678.0;
    float b = 0.1;
    cout << setw(30) << a +b << endl;
    
    output:12345678
    

9 拓展字符集wchar_t

wchat_t(wide characters:宽字符),PC往往是2字节,底层是unsigned short,部分编译器也可以是4字节,特别是Unix工作站.

wchar_t wide_letter = L'z';
wchar_t wide_letter = L'\x0438';
wcin>>wide_letter;
wcout<<wide_letter;   //值得注意的是,并不一定会输出,因为可能操作系统并不会识别

ps:练习题不通过if等语句判断两个数的大小;

//输出较大的那个
//解法1
c = ( a + b ) / 2 + abs( a - b );
//解法2
int num[2]={ a , b };
c = num[ a < b ];

第3章 处理基本数据类型

1 数据类型转换

如果两个操作数不同类型,就把取值范围比较窄的那个转换为另一个值较宽的类型.

应该尽可能避免编写混合表达式

应该避免出现宽类型赋值给窄类型,如果故意为之(这并不是常见现象,若出现很多,因考虑是否应该选择更合适的类型),应该使用 显式强制转换 .

将float变量赋值给int时,会丢失小数部分**(全部舍弃而不是四舍五入)**

将float赋值给double,也将丢失精度.

运算时应该**统一选用类型(是其中的一个因素)**请看下面的例子

//假定a为一个不超过255的数;
//方式1:
unsigned char a;
unsigned int b,c;
c = a + b;
//方式2
unsigned int a,b,c;
c = a + b;

上述例子中虽然a的值不超过255,但是由于a与一个unsigned int数据进行计算,虽然节约了空间(不一定),中间存在多次隐式格式转换,运算会慢.

2 显式强制转换

即强制转换

int a = 100000;
char b = 0;
b = (char)(a);  //c语言中的老式的转换方法,包含了新式的4种方法
			   //仍然可用,但是不够清晰,可能得不到想要的结果
//新式的
b = static_cast<char>(a);

3 sizeof()

sizeof()是一个操作符,而不是某个函数

int main()
{
    sizeof(1);
    return 0;
}

这已经是一个完成的程序了.虽然并没有输出,但是也没有报错,sizeof()应该说是一个长得奇怪的加减乘除.

需要注意的是,sizeof()的返回值是size_t类型(其实就是uint_t),如果用size_t类型则需要#include<iostream>

4 枚举数据类型

枚举类型的定义

    int i;
    const int j= 5;
    enum example{FIRST_DAY = 1};
    enum Weekday{Monday = 1,    //默认为0,但是可以直接初始化为其他值
                Mon=1,          //枚举成员不一定有唯一值
                Tuesday=5,      //中间成员也可以自己随意定义
                Wednesday,      //默认为上一行的值+1
                Thursday=5,     //重新从5开始递增 
                Friday,         //默认为上一行的值+1
                Saturdary,
                //Sat = i,		//会报错,赋值必须为常量
                //Sat = j,		//常量 
                //Sat = FIRST_DAY,//常量
                 //Sat = j+FIRST_DAY,//常量
                Saturday};

匿名枚举:不给枚举类型起名字,直接定义好几个变量,之后无法再定义这个类型的枚举变量

enum {First = 1,Second = 2}me,you,he;

枚举变量的定义

 enum Weekday{Mon,
              Tues=5} yesterday=Tues;  //这是一种声明方法,
    							  //不给初始值则为随机数,可能超过该枚举类型中包括的范围,   
Weekday today = Tues;	//这是另一种,枚举变量只能从Weekday的值中选
Weekday tomorrow = static_cast<Weekday>(7); 
//显式强制转换的时候可以取min(Weekday)到max(Weekday)中间的任意值

整型不会自动转换为枚举,但是枚举可以自动转换为整型

5 typedef的用法&用途

typedef shdfnowaoiefh  int;
shdfnowaoiefh i=0;

用途:主要用于例如:

不同的操作系统或芯片int表示的位数不同,那可以给int起一个别名,

这样移植代码的时候只需要把int换成 long 或short即可.

6 static的两种用法

  1. 定义静态变量
  2. 定义局部函数

7 volatile的用法

编译器重复使用某一变量的时候,可能会优化使其从之前加载过的寄存器中读取,但是此时其内存中的数据可能已经改变了,这就造成不可预料的结果.volatile修饰的变量每次都会从内存中读取.

8 extern 外部变量

第4&5章 判断循环

1 条件运算符

d=c? a:b;		//若c为真,则d=a,反之,d=b 
//甚至可以三个选项组合
cout<<(a<b? "a小于b":(a==b? "a等于b":"a大于b"));

2 continue&&break

continue:跳过这次循环

break:跳出循环

第6章数组字符串

1 数组的定义

  1. 数组长度必须为定值
  2. 数组长度尽量不要设置为幻数
  3. 用变量代替数组长度的时候要加const

多维数组定义时,只能省略行数,其他均不可省略,即只能省略第一维.

2 string的使用

部分见头文件string

第7章 指针

指针常量和指向常量的指针

指针常量:指针是个常量,但是指向的地址存储的不一定是常量

const int * point;

指向常量的指针:

int* const point;

指向常量的指针常量:

const int* const point;

动态内存分配

自由存储区

new&delete
//变量
double * pvalue = 0;
//第一种分配方法
pvalue = new double;
*pvalue = 99.0;
//第二种分配方法
pvalue = new double (999.0)
/*******************************/
//数组
pstring = new char[20];

delete pvalue;	//释放内存
pvalue = 0;		//指针归位
//数组
delete [] pstring;	//这个括号很重要.
pstring = 0;

一定记得不用的内存要删除掉!!!


第8章 使用函数编程

1参数与变元

参数:函数定义的时候的形参

变元:函数使用的时候的实际值

特点\分类 普通参数 指针参数 引用参数
样式 int function(int a) int function(int * a) int function (int & a)
特点 函数对变元的副本进行操作 函数对地址a所在的数值进行操作 函数对a的本体进行操作
原本的值不变 可以改变* a 改变的是原来的变量,且非常不明显
不推荐使用

如果确定不需要对传送的参数进行修改,就可以直接将参数定为常量.

int larger(const int & m, const int & n);

2关于函数形参默认值

直接对参数赋值就行了,但是有默认值的要放在最后定义,因为有默认值的参数可以省略处理,假如放在中间容易造成混淆

函数本体不需要写入默认值,声明出赋值就好了.

3 返回值

返回地址的时候不要返回局部变量的地址

不要从函数中返回自动局部变量的地址

不要从函数中返回自动局部变量的地址

可以new一个新变量返回,缺点是很容易内存泄露.用完一定要释放内存

内联函数

inline int larger(int m, int n)
{
    return m>n?;
}

前面加上inline,便是内联函数

作用:防止函数过短,跳转花费时间很长,建议编译器把这行代码直接插入到原代码中.

建议的意思是编译器可能不采纳,如果不采纳,可能效率反而降低

把函数声明位inline,那么它就必须在调函数的每个源文件使用,所以必须放在头文件中.

第9章函数

1函数的重载

通过例子理解:对于取较大值的函数larger(a,b). 我们很可能既要用于整型,又要用于浮点,若还想用同一个名字,那么需要用到用到函数的重载

要求:(or)

  1. 参数的个数不同
  2. 参数的类型至少有一个不同

效果:

  1. 编译器会自动选择合适的函数

什么叫合适啊?

  1. 如果有完全一致的,无脑选

  2. 如果有可以无丢失自动转换的也行(有long的函数,可以(不一定)直接处理int的,double 可以处理float)

  3. int即可以无损到double,又可以到long,则会报错,编译器不抛硬币.

解决办法就是把其中一个参数做一个强制类型转换,编译器就可以处理了,但是最好还是两个都做,这样给人更好的阅读体验.

````cpp
long larger(long a,long b);
double larger(double a,double b);

int main ()
{
    int a_int,b_int;
    cout << "Enter two integers: ";
    cin >> a_int >> b_int;
    cout << "The larger of " <<static<long>(a_int) << " and " << b_int  << " is " 
        << larger(static<long>(a_int),static<long>(b_int)) << endl;
    return 0;
}

double larger(double a,double b)
{cout << "(this is double)"<< endl;
 return a>b?a:b;}
long& larger(long& a,long& b)
{cout <<"(this is long)"<< endl;
    return a>b?a:b;}

output:this is double;

````

上述代码会使用double,两个larger函数中,long的那个可以对参数的**本体**进行修改,所以传入的必定为本体,而不是[复制出来的副本](#1参数与变元),所以强制类型转换出来的临时变量并没有被使用.要解决这个问题,可以将声明函数改为`long larger(const long & a, const long & b);`

注意只返回了long 如果返回引用,也必须加上const

2 函数模板

template <class xxx>xxx larger(xxx a,xxx,b)
{
 return a>b? a:b;   
}

template:表示是一个模板

<class xxx>:尖括号包裹住参数列表,class xxx表示xxx为参数名(相当于xxx表示某种类型,有时候class也会用typename代替)

#include <iostream>
using namespace std;
template <class xxx> xxx larger(xxx a, xxx b);
int main()
{   long a_long,b_long;
    double a_double,b_double;
    float a_float,b_float;
    int a_int,b_int;
    //input the nums
    cout << "Enter two integers: ";
    cin >> a_int >> b_int;
    cout << "Enter two floats: ";
    cin >> a_float >> b_float;
    cout << "Enter two doubles: ";
    cin >> a_double >> b_double;
    cout << "Enter two longs:";
    cin >> a_long >> b_long;
 	//complete
    cout << "long: " << larger(a_long,b_long) << endl;
    cout << "double:" << larger(a_double,b_double) << endl;
    cout << "float:" << larger(a_float,b_float) << endl;
    cout << "int: " << larger(a_int,b_int) << endl;
    return 0;}

template <class xxx> xxx larger(xxx a, xxx b)
{   return a>b ? a:b;}

3 显式指定模板参数

  1. 编译器有时候不能确定该用哪种参数创建函数
  2. 编译器不知道该用哪个版本的函数
  3. 避免太多的函数版本,可以强迫编译器调用某种模板

例:large<long>(a_int,b_int):指定xxx为long

4定义模板说明

#include <iostream>

using namespace std;
//声明
template <class TReturn, class TArg> TReturn larger(TArg a, TArg b);
template<>long* larger(long* a, long* b);

int main()
{
    long a_long,b_long;

    cout << "Enter two longs:";
    cin >> a_long >> b_long;
  
    cout << "long: The larger of " << a_long << " and " << b_long << " is " <<  larger<int>(a_long,b_long) << endl;
    cout << "int: The larger of " << a_long << " and " << b_long << " is " << * larger<long*>(&a_long,&b_long) << endl;//注意此处*的使用
    return 0;
}
//模板
template <class TReturn, class TArg> TReturn larger(TArg a, TArg b)
{
    cout<<"standard version"<< endl;
    return a>b ? a:b;
}
//模板说明:特殊情况下的怎么调用
template<>long* larger(long* a, long* b)
{
    cout<<"specialized version"<< endl;
    return *a>*b ? a:b;

}

5 非类型的模板函数

#include <iostream>

using namespace std;

template <int lower,int upper,class TArg>bool isin_range(const TArg);

int main()
{
    double a = 5;
    cout << isin_range<0,1>(a)<<endl;
    return 0;
}


template <int lower,int upper,class TArg>bool isin_range(const TArg a)
{
    return (( a > lower )&&(a < upper))?true:false;
}

6 函数指针

long fun1();
//声明一个函数指针
long (*pfun)(long*,int) = fun1;	//一个指向函数的指针声明
//返回类型(*指针名)(参数类型列表)
//声明指针时应该总是初始化它

汇总 常用头文件

iostream

1. cin: 输入

cin默认只读到第一个空白字符,因为提取运算符把空格当作输入之间的分隔符,甚至不能使用提取运算符一次读取一个输入字符,因为任何空白字符包括’\n’都会看作分隔符.

如果想要读到一整句话,则需要

#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
    char a1[20];
    cin.getline(a1, 20);
    cout << a1 << endl;
    return 0;
}

cin.getline(text,maxlength,'!');

将输入的最多maxlength个字符存入text中,以’!'结束.

其中第三个参数可缺省,缺省时以`\0`为结束

2. cout: 输出

3. fixed & scientific

fixed :固定采用小数点

scientific:固定采用科学计数法
[fixed的用法,scientific类似](# 8关于float/double/long double的精度问题)

4. hex&dec&oct

使用方法类似与fixed,分别表示16进制和10进制以及8进制

5 表

在这里插入图片描述

iomanip

io代表输入输出,manip是manipulator(操纵器)的缩写
它是I/O流控制头文件,就像C里面的格式化输出一样。
以下是一些常见的控制函数的:

1.setw(int n)

预设输出宽度

2.setfill(char c)

使用c作为填充字符

    cout<<setfill('*');
    cout << setw(9) << red  << endl;
output:
//    ***ff0000

3.setbase(int n)

预设整数输出进制

4.setprecision(int n)

用于控制输出流浮点数的精度(四舍五入)

cstdlib

应用于整数的数字函数

1. abs()

绝对值

2. div()

除法

#include <iostream>
#include <cstdlib>
using namespace std;
int main ()
{
    int value =93;
    int divisor = 17;
    div_t results;
    results = div(value , divisor);
    cout <<results.quot <<"    "<< results.rem << endl;
}//quot=value / divisor	rem = value % divisor

quot是商,rem是余数

3. rand()

随机数:从 0 到RAND_MAX的伪随机数(固定的随机数)

获得从0- N(自定义)的随机数(不包含N)

const int N= 10;

int random_value = static_cast<int>(
    							  ( N*static_cast<long>(rand()) )
                                     /(RAND_MAX+1L) )  //注意此处的强制类型转换

4. srand()&time(0)

srand(),括号内为种子数,一般与time(0)一起用.

int main ()
{
    cout <<"默认的随机数:输出4个从0 到"<< RAND_MAX << "随机数"<< rand()<< " " << rand()<< " " << rand()<< " " << rand()  << endl;
    srand((unsigned int)time(0));
    cout <<"给了一个新的种子数后:输出4个从0 到"<< RAND_MAX << "随机数"<< rand()<< " " << rand()<< " " << rand()<< " " << rand()  << endl;
}

output :
	默认的随机数:输出4个从032767随机数41 18467 6334 26500
	给了一个新的种子数后:输出4个从032767随机数27566 5718 31705 5451

cmath

这些函数的变元可以是任意浮点类型,返回结果与变元类型相同.

  • 参数为float 输出为float

  • 参数为double 输出为double

  • 参数为int 输出为double

1. sqrt()

开方

2表

在这里插入图片描述
在这里插入图片描述

limits

包含所有标准数据类型的上下限信息.

1.numeric_limits<类型名>

numeric_limits<int>::max();
numeric_limits<int>::min();
numeric_limits<int>::digits();		//二级制数字的位数,不包括符号位,此处输出为31
numeric_limits<unsigned int>::digits();		//二级制数字的位数,此处输出为32

string

部分见2 string的使用

1 string 类定义

using namespace std;
string s1;  //长度为0
string s2 = "it just a example";
string s3("it just a example");
string s4(5,'z');		//	s4 = "zzzzz"
cout << s1.length() << endl;//显示长度
s1 = s2 + s3;			//

2 getline()

const int cA1_SIZE = 20;
string text;
char a1[cA1_SIZE];
getline(cin,text);	//从第一个参数,输入到第二个,不考虑长度,第三个参数为停止字符,可省略
cin.getline(a1,cA1_SIZE);

[注意区分getline 和 cin.getline](#1. cin: 输入)

3 substr()

获取一个子字符串.

string a1 = "1224748556556";
string b1 = a1.substr(4,6);	//	第一个参数是索引地址,第二个是读取个数

4 compare()

string a,b;
a.compare(b);
a.compare(2,4,b,3,4);    //用a从索引2,长度4.与b的索引2,长度4比较

比较a和b,如果a大于b就返回正,等于返回0,小于返回1

不是比较长度,而是比较从索引按顺序,谁的先大.

5 find()

string a ="123422343234";
string b = "23";
a.find('x');
a.find(b);		//返回相同的第一个字符的索引
a.find(b,3)		//带搜索起点

找到返回索引地址,找不到返回string::npos即非法地址.编译器不同,数值不同

6 find_first_of()

int main()
{
    string a ="0 123,08 41~!@#$%^&*(64123 \tad1\n23 412409";
    int i = 0;
    int number =0;
    for(i = 0;i < a.length(); i++)
    {	//检索这些符号
        if(a.find_first_of(" \n\t,.?!",i) != string::npos)
        {
            i = a.find('1',i);
            number++;
        }
        else break;
    }
    cout <<"表示间隔的符号出现了 "<< number <<"    次" <<endl;
    return 0;
}

7 insert()&replace()

a.insert(13,b,5)将b的前5个字符插入到a的索引为13的字符之前.

a.insert(13,b,5,6)将b的索引为5开始的前6个字符插入到a的索引为13的字符之前.

a.insert(13,7,'*')将7个’*'插入到a的索引为13的字符之前.

相关推荐

  1. Python自学(适用基础

    2024-04-29 13:26:01       23 阅读
  2. C语言基础学习

    2024-04-29 13:26:01       46 阅读
  3. C语言学习笔记

    2024-04-29 13:26:01       42 阅读
  4. C语言学习笔记

    2024-04-29 13:26:01       42 阅读
  5. C语言学习笔记

    2024-04-29 13:26:01       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-29 13:26:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-29 13:26:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-29 13:26:01       82 阅读
  4. Python语言-面向对象

    2024-04-29 13:26:01       91 阅读

热门阅读

  1. 基于springboot新农人交流论坛 - 源码免费

    2024-04-29 13:26:01       30 阅读
  2. 商家认证目表-DDL

    2024-04-29 13:26:01       27 阅读
  3. 如何提高前端开发效率?

    2024-04-29 13:26:01       35 阅读
  4. Nginx两个/多个域名同时使用80端口

    2024-04-29 13:26:01       32 阅读
  5. 【Vue】监听div宽高的变化(动态渲染echarts宽高)

    2024-04-29 13:26:01       37 阅读
  6. 【Linux】Centos7安装部署asterisk,搭建 SIP服务器

    2024-04-29 13:26:01       31 阅读
  7. 什么是EMI,它和EMC之间有什么区别

    2024-04-29 13:26:01       35 阅读
  8. 学习记录695@EasyExcel 读取数据每一行都为null

    2024-04-29 13:26:01       26 阅读
  9. 【EXCEL自动化11】pandas提取指定数据(补充)

    2024-04-29 13:26:01       31 阅读
  10. Debezium日常分享系列之:Debezium 2.7.0.Alpha1发布

    2024-04-29 13:26:01       33 阅读
  11. node环境Vue项目目录结构介绍

    2024-04-29 13:26:01       27 阅读