C++知识记忆

  1. using namespace std;
    这句代码是告诉使用的命名空间是std,否则需要在cout,endl之类的名词之前加std::cout才能3使用。

语法基本

输出语句:

std::cout<<"Hello World!\n";
printf("nihaoshijie");
printf就好比一个函数一样
\+符号叫转义字符

system 系统命令:

system("pause");/*暂停的意思 程序到这里暂停了,在按任意键继续运行*/
system("cls");/*清屏*/ 
system("shutdown /s")/*关机的作用*/
system("shutdown /a")/*取消关机的作用*/ 
system("D:\\123\\123.jpg");/*打开文件*/
system(color 14);/*控制台颜色变化*/

变量和常量

起名规矩:

  • 必须是字母或者字母+数字组合,符号仅_可用
  • 名字不能用数字开头
    变量的定义方式:
  • 类型 名字{初始值}; int a{2};
  • 类型 名字=初始值;int a=2
    常量的定义方式
  • 直接用值; 5;
  • const 类型 名字{初始值};const int a{2};
  • 类型 const 名字 {初始值};int const a{2};
  • #define 名字 值 #define a 2

布尔和整形

基本概念:
不管是常量还是变量,本质都是在内存中申请一块区域,用来存放我们的数据,只不过常量申请的内存区域不允许修改,而变量申请的内存区域,允许修改。以上说的可以修改和不可以修改,只是站在编译器的角度,实际上,不管是常量还是变量,甚至是已经编译好的代码
定义和初始化的区别:

int age;/*定义*/ 
int age{2};/*初始化*/ 
int age{};/*初始化为0*/

输入输出函数:
输出函数

unsigned short salary{500};//0-65535 
std::cout <<"您的工资"<< salary <<"就这么些钱";

输入函数

unsigned short salary{};//0-65535 
std::cin >>salary;//这是输入函数 
std::cout <<"您的工资"<< salary <<"就这么些钱";

带符号的整数

/* 字符型下面是占用1字节 取值-128-127 2^8*/ 
signed char 
char 
/*下面是占用占用2字节 取值-32768-32767 2^16*/ 
short 
short int 
signed short 
signed short int 
/*下面是占用4字节 2^32 取值-217483648到214783647 */ 
int 
signed 
signed int 
/*下面是占用4/8字节 4字节-217483648到214783647 8字节-9223372036854775808到 -9223372036854775807 */ 
long 
long int 
signed long 
signed long int 
/*下面是占用8字节 2^64 取值-9223372036854775808到 -9223372036854775807*/ 
long long 
long long int 
signed long long 
signed long long int

不带符号的整数类型

unsigend char //占用1字节 取值范围0-255 
unsigned short wchar_t//占用2字节 取值范围0到65535 
unsigned //占用4字节 取值范围0-4294967295 unsigend int //占用4字节 取值范围0-4294967295 
unsigend long //占用4/8字节 4

布尔类型

bool //占用1字节 取值true或false

赋值与运算

赋值的概念

a=150;b=30;

运算的概念
除法的结果不是四舍五入而是取值

名称运算符
先递增++a
后递增a++

举例:

int a{10}; 
int b=5 + ++a; 
std::cout << b<<std::endl;/*输出16*/ 
std::cout << a<<std::endl;/*输出11*/ 
int a{10}; int b=5 + a++; 
std::cout << b<<std::endl;/*输出15*/ 
std::cout << a<<std::endl;/*输出11*/

进制的概念

进制表达方式
二进制0b+二进制+后缀
八进制0+八进制+后缀
十进制十进制数+后缀
十六进制0x十六进制数+后缀
后缀类型
L/llong型(4/8字节)
LL/lllong long型(8字节)
U/u无符号型(unsigned),可以和L/l或者LL/ll组合使用 比如123ULL

类型转换

类型转换顺序表

优先级类型
最高long double
.double
.float
.unsigned long long
.long long
.unsigned long
.long
.unsigned int
最低int
int a{500};
unsigned b{1000}; 
std::cout <<a-b<<std::endl;
所以这个代码的最终结果是以unsigned输出的。

转换方式

  • 自行定义a 使其a=a-b;
  • 前面强制使用(类型) 例如:(int)(a-b)
  • 静态转换
    static_cast<目标类型>(要转换的内容)
    例如:int a = static_cast< int >(b);

类型占用内存

 int a{}; 
 std::cout<<sizeof(a);//int型所占内存的大小

字符

在这里插入图片描述

string

  • string s;
    可以s[1]这样去访问。
  • s.size()
    字符串s的大小
  • s.resize()
    修改字符串长短
  • s.substr()
    截取字符串
#include<string>
#include<iostream>
using namespace std;
int main()
{
  string s("12345asdf");
  string a = s.substr(0,5);     //获得字符串s中从第0位开始的长度为5的字符串
  cout << a << endl;
}

推断类型

auto类型

auto a {200}; 
auto b{100LL};

typeid(变量).name的使用

auto a {200}; 
auto b{100LL}; 
auto c{U'A'}; 
std::cout<<"变量a的类型为"<<typeid(a).name()<<std::endl; 
std::cout<<"变量b的类型为"<<typeid(b).name()<<std::endl; 
std::cout<<"变量c的类型为"<<typeid(c).name()<<std::endl;

枚举变量

枚举变量的格式

 enum class 类型名称:基本类型 
 {
  选项 1, 
  选项 2 
  };

举例:

int main() 
{ 
enum class name :int 
{ 
ZHANG,zhang=ZHANG, 
WU, 
LI, 
WANG 
};
name c{ name::ZHANG }; 
std::cout << (int)c; }//输出的是0,枚举定义的关系是自动递增的

枚举的注意事项

  • 枚举类型默认定义为int类型
  • 枚举成员只能是整数类型
  • 最后是没有逗号的
  • 注意强制转换
  • 自动叠加

自定义变量名称

自定义变量名称的三种方式

  1. define A TypeName。

    #define A TypeName //以后代码中的A可以被替换为Tpyename
    

    注意事项:
    #define是预处理指令,所有预处理指令后面都不需要加分号。
    相当于替换,只有这个是无脑替换!谨记。可以让下面两种方式替换这个的替换值。

  2. typedef TypeName A;

    typedef TypeName A; //以后TpyeName类型名字可以用A代替
    

    注意事项:
    不是无脑替换,鼠标放上去会显示定义类型
    但是输出类型依旧是原类型(int)
    类型在前,更改的名字在后!

  3. using A=TypeName;

    using A=TypeName; //以后TypeName类型的名字可以用A代替
    

命名空间

命名空间的概念:

  • std:cout 就是命名空间 cout是一条指令,它放在std里面,这里std就是命名空间
  • std::cin std::hex。这里冒号叫做限定符 std::oct这些都是std命名空间里面的东西。
  • 有方法可以不输入std
    using std::cout;
    using namespace std;/一劳永逸/
  • std::hex是16进制输出

命名空间自行定义

namespace 变量名称 
{ 
变量1;
 变量2; 
}

举例:

#include <iostream> 
namespace money 
{ 
int ZHANG{ 100 }; 
int LI{ 200 }; 
}
int main() 
{ 
using namespace std; 
/*using money::ZHANG; cout << ZHANG;*/ 
cout << money::ZHANG; 
}

可以实现嵌套

#include <iostream> 
namespace money
{ 
int ZHANG{ 100 }; 
int LI{ 200 }; 
namespace people 
{ 
int ZHANG{ 101 }; 
int LI{ 200 
}; 
}
}
int main() 
{ 
using namespace std;
 //using money::ZHANG; 
 cout << money::people::ZHANG; }

注意事项

  • 一定要写在main函数外面(不能在函数体内)
  • 可以在一个嵌套
  • 子级命名空间调用父级命名空间仍需要限定符

自定义数据类型struct

自定义数据类型struct结构

struct 名称 
{ 
类型 名称; 
};
  • 结构的本质是按照我们自己的方式去定义一块连续的内存结构
  • 声明一个结构变量的本质是向计算机申请一块内存区域,而这块内存的大小,至少是我们定义的结构成员需要占用的内存之和。
  • 使用结构则是按照我们定义好的方式从这块内存读取和写入数据

举例:

#include <iostream> 
int main() 
{ 
struct gift 
{ 
char logo{ 'A' }; 
unsigned price{ 1000 };
unsigned size{ 200 };
 };
 gift giftA{ 'A',1320,170 };
 gift giftB{ 'B',530,150 }; 
 gift giftC{ 'C',510,110 }; 
 std::cout <<"礼物的标签为" << giftA.logo<< "价格为" << giftA.price<< "大小为" << giftA.size << std::endl; 
 std::cout << "礼物的标签为" << giftB.logo << "价格为" << giftB.price << "大小为" << giftB.size << std::endl; 
 std::cout << "礼物的标签为" << giftC.logo << "价格为" << giftC.price << "大小为" << giftC.size << std::endl; }

位运算

  1. 输出二进制内容
    std::bitset<要显示的二进制位数>(要显示的变量);

    #include <iostream>
    #include <bitset> 
    int main() { 
    int a {2}; 
    std::cout<<std::bitset<32>(a);//将2以32位2进制输出 
    }
    
  2. 左移:<<
    高位丢弃,低位补0.

  3. 右移:>>
    在正数的时候补0,负数的时候补1。

  4. 求反运算符:~

  5. 与运算符:&

  6. 或运算符:|

  7. 异或运算符:^

运算符优先级

请添加图片描述
请添加图片描述
2. a++ 和 ++a的优先级

  • c = b+++a;
    解析为:
    c=b++ +a 因为后缀 ++ 在前缀 ++ 的优先级前面 所以计算b++
    变相的等于 c=a+b++

if语句

if(条件 bool类型) 
{ 语句; }
else 
{ 语句; }
if(条件 bool类型) 
{ 语句; }
else if(条件 bool类型) 
{ 语句; }
else if(条件 bool类型) 
{ 语句; }
... 
else { 语句; }

switch语句

  1. switch语句的基本用法
  • 值只能是整数或者是字符类型

  • “case常量表达式:”即处理入口(也称其为“标号”),常量表达式相当于入口编号,入口编号是不能重复的,所以每一个case的常量表达式的值必须互不相同。

  • 处理入口编号不能重复,但可以颠倒。也就是说,入口编号的顺序不重要。各个case(包括default)的出现次序可任意。

    #include <iostream> 
    int main() 
    { 
    int day{}; 
    std::cout << "请输入编号:"; 
    std::cin >> day; 
    switch (day) 
    { 
    case 0:std::cout << "今天是星期天"; break; 
    case 1:std::cout << "今天是星期一"; break; 
    case 2:std::cout << "今天是星期二"; break; 
    case 3:std::cout << "今天是星期三"; break; 
    case 4:std::cout << "今天是星期四"; break; 
    case 5:std::cout << "今天是星期五"; break; 
    case 6:std::cout << "今天是星期六"; break; 
    default:std::cout << "输出的数有问题!"; break;
    } }
    
  1. switch的嵌套
#include <iostream> 
int main() { 
int day{}, eat{}; 
std::cout << "请输入编号:"; 
std::cin >> eat; 
switch (day) { 
case 0:std::cout << "今天是星期天"; 
std::cin >> day; 
std::cout << "请输入今天吃什么。1是蛋糕,2是牛奶,3是二锅头"; 
     switch (eat) {
     case 1:std::cout << "蛋糕"; break; 
     case 2:std::cout << "蛋糕"; break; 
     case 3:std::cout << "蛋糕"; break; default:
     std::cout << "输出的数有问题!"; break; }break; 
case 1:std::cout << "今天是星期一"; break; 
case 2:std::cout << "今天是星期二"; break; 
case 3:std::cout << "今天是星期三"; break; 
case 4:std::cout << "今天是星期四"; break; 
case 5:std::cout << "今天是星期五"; break; 
case 6:std::cout << "今天是星期六"; break; 
default:std::cout << "输出的数有问题!"; break; } }

for循环

  • 语块中的变量是临时变量
  • 用break语句可以使流程跳出switch语句体,也可以用break语句在循环结构终止本层循环体,结束整个循环。
    • 只能在循环体内和switch语句体内使用break;
    • 当break出现在循环体中的switch语句体内时,起作用只是跳出该switch语句体,并不能终止循环体的执行。
  • continue语句的作用是跳过本次循环体中余下尚未执行的语句,立即进行下一次的循环条件判定,可以理解为仅结束本次循环。
for(int i=0;i<5;i++) 
{ 
std::cout<<i<<std::endl; 
}

while和do while语句

  1. while用法

    • 先判断
    • 再执行语句
    • 再判断
    • 条件表达式是bool值
    while(条件表达式)
     { 
     语句; 
     }
    
  2. do while用法

    1. 先执行语句
    2. 在判断
    3. 再执行
    do
    {
     语句; 
    } while (条件表达式);
    

数组

  1. 数组的用法

    int a[5]{0,1,2,3,4};
    

    注意:

    • 所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。
    • 大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。
    • 所有的数组都是以 0 作为它们第一个元素的索引,也被称为基索引,数组的最后一个索引是数组的总大小减去 1。
    • 如果您省略掉了数组的大小,数组的大小则为初始化时元素的个数。
      int a[]{0,1,2,3,4};
  2. 全局变量和局部变量

    • 局部变量定义在一个函数内部,在函数之外是不可访问的。
    • 全局变量定义在所有函数之外,并且在其作用域内的所有函数都可以访问。
    • 局部变量生存期
      • 只有在定义的函数正在执行时,局部变量才存在,这称为局部变量的生存期。当函数开始时,它的形参变量和它定义的任何局部变量都将在内存中创建,当函数结束时,它们被销毁。这意味着存储在函数形参或局部变量中的任何值在调用不同函数之后都会丢失。
    • 全局变量生存期
      • 随着程序结束而结束。
  3. 数组的初始化问题

    • 如果您省略掉了数组的初始化值,初始化值默认可以为0(必须有{})。

      int a[5]{};
      
    • 如果您只定义了数组元素,没有初始化。 int a[5];

      • 整形数组
        • 全局数组,未初始化时,默认值都是 0
        • 局部数组,未初始化时,默认值为随机的不确定的值
        • 局部数组,初始化一部分时,未初始化的部分默认值为 0 int a[5]{0,1,2}
      • char 型数组
        • 全局数组,未初始化的部分,默认值为 ‘ ’ (空格)
        • 局部数组,初始化一部分后,未初始化部分默认值为 ‘ ’ (空格)
        • 局部数组,未初始化时,默认值不可预知。
      • double ,float 型数组
        • 全局数组,未初始化时,默认值都是 0.0;
        • 局部数组,未初始化时,默认值为随机的不确定的值;
        • 局部数组,初始化一部分时,未初始化的部分默认值为 0.0;
      • bool 型数组
        • 全局数组,未初始化时,默认值都是 0;
        • 局部数组,未初始化时,默认值为 204;
        • 局部数组,初始化一部分时,未初始化的部分默认值为 0;

多维数组

  1. 多维数组的应用

    int a[4][3] {
     {0,1,2}, 
     {3,4,5}, 
     {6.7,8}, 
     {10.11,12} 
     };
     //上下两种初始化是等同的。
    int a[4][3] {
     {0,1,2,3,4,5,6,7,8,9,10,11,12}; 
     }
    

2. 所有的数组都是由连续的内存位置组成。

容器(安全数组)

  1. 一个容器就是一些特定类型对象的集合。
    顺序容器(sequential container)为程序员提供了控制元素存储和访问顺序的能力。

  2. 标准库中的顺序容器包括:
    i. vector:可变大小数组。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢。
    ii. deque:双端队列。支持快速随机访问。在头尾位置插入/删除速度很快。
    iii. list:双向链表。只支持双向顺序访问。在list中任何位置进行插入/删除操作速度都很快。
    iv. forward_list:单向链表。只支持单向顺序访问。在链表任何位置进行插入/删除操作速度都很快。
    v. array:固定大小数组。支持快速随机访问。不能添加或删除元素。
    vi. string:与vector相似的容器,但专门用于保存字符。随机访问快。在尾部插入/删除速度快。

  3. array的概念

    • std::array是在C++11中才引入的,与内置数组相比,array是一种更安全、更容易使用的数组类型。
    • 与内置数组类似,array对象的大小是固定的。因此,array不支持添加和删除元素以及改变容器大小的操作。
    • 与内置数组一样,标准库array的大小也是类型的一部分。当定义一个array时,除了指定元素类型,还要指定容器大小。
    • 为了使用array类型,我们必须同时指定元素类型和大小。
    • array仅仅是为普通数组添加了一些成员或全局函数,这使得数组能够被当成标准容器来使用。
  4. array的应用

    #include <array> 
    std::array<变量类型,元素数量>变量名{初始化};
    
    #include <array> 
    std::array<int,5>a{0,1,2,3,4};
    
    • 输出有几个元素:a.size()

    • 设置所有元素的值:a.fill(5)

    • 返回内容:a.at(要取的元素)

    • 数组的比较:

      std::array<int,5>a{ 0,1,2,3,4 };
      std::array<int,5>b{ 0,1,2,3,4 }; 
      std::cout << (a==b) << std::endl;
      
    • 与另一个array的内容交换
      两个array的数据类型和size必须相同。

      array数组1.swap (array数组2);
      
  5. vector的概念

    • vector是表示可以改变大小的数组的序列容器。
    • 就像数组一样,vector使用连续存储空间存储元素,这意味着它们的元素也可以使用指向其元素的指针进行偏移来访问,并与数组一样高效。但与数组不同的是, vector的大小可以动态变化,并且是由容器自动处理的。
    • 在内部实现上,vector使用动态分配的数组来存储它们的元素。在插入新元素时,vector的大小增大,可能需要重新分配数组,这意味着可能要分配新数组并将原有数组中所有元素移动到这个新数组中。
    • 重新分配数组的时间成本相对高昂,因此,vector不会在每次向容器添加元素时都重新分配数组。vector容器可能会分配一些额外的存储空间来适应可能的增长,因此容器的实际容量可能比其包含的元素个数要大。
    • 因此,与数组相比,vector消耗更多内存,以换取以更有效的方式管理存储空间。
    • 与其他动态序列容器(deques,lists和forward_lists)相比,vector可以非常高效地访问其元素(就像数组一样)并且相对高效地从其末尾添加或删除元素。
  6. vector的应用

    std::vector<数据类型>名称;
    

    例:

    #include <iostream> 
    #include <vector> 
    int main() 
    { 
    std::vector<int>a{5,6,7}; 
    cout << a[1];//这样也完全可以输出6来,vector知识一个定义方式罢了,你就按数组的方式用就完事了
    }
    
    • for(int &i:数组)
    • for循环里面i不加&是只读,加&是读写
      #include <iostream> 
      #include <vector> 
      int main() { 
      std::vector<int>a{5,6,7}; 
      for (int i : a) { i = i * 2; std::cout << i << " "; }//输出10,12,14
      for (int i : a) { std::cout << i << " "; } //输出5,6,7
      }
      
    1. 可以不设置0个元素
      std::vector<int>a;
      
    2. 可以设置为几个元素,若何不设置初始值,则初始值为0.
      std::vector<int>a(10); 
      for (int i : a) { std::cout << i << " "; }//输出10个0
      
    3. 可以设置为几个元素初始值都一样
      std::vector<int>a(10,80); 
      for (int i : a) { std::cout << i << " "; }//输出10个80
      
    4. 可以添加新的值到vector中,push_back
      std::vector<int>a; 
      a.push_back(2); 
      for (int i : a) { 
      std::cout << i << " "; 
      }
      
    5. 重新初始化 assign
      std::vector<int>a; 
      a.assign(5, 8);
      for (int i : a) 
      { 
      std::cout << i << " "; 
      }
      
    6. 清空 clear
      std::vector<int>a{1,2,3,}; 
      a.clear(); 
      for (int i : a) { std::cout << i << " "; }
      
    7. 判断是否清空 empty←这是布尔类型
      std::vector<int>a{1,2,3,};
      a.clear(); 
      if(a.empty()) 
      { 
      std::cout<<"清空"; }
      else 
      { 
      std::cout<<"未清空"; }
      
    8. erase(),unquie();
auto end_unique = unique(vec.begin(), vec.end());
//unique的返回值是一个迭代器,它指向最后一个不重复元素之后的位置,也就是 1 2 3 4 5 7 8 7 8中的第一个8之后的7
vec.erase(end_unique, vec.end());//erase函数给定删除的区域
iteratorerase(iterator position);//删除指定位置
    1. vector< string > s;
      这就定义了一个字符数组了好比。

哈希容器 (unordered_map)

用法实例:

#include<unordered_map>
using namespace std;

int main()
{
	unordered_map <string, int> hash;
	
	//以下是三种插入键值对的方法
	hash["Apple"] = 1;   //如果原先没有该pair,则会插入该pair。如果有,则会修改value值
	hash.insert(make_pair("Orange", 2));
	hash.insert(pair<string,int>("Banana", 3));
	
	//以下是两种查找key是否存在于unordered_map的方法
	if (hash.find("Apple") != hash.end()) //方法一:查找key是否在map中
		cout << "Apple exists"<<endl;
	if (hash.count("Banana") != 0)  //方法二:查找key是否在map中
		cout << "Banana exists" << endl;

	//以下是两种遍历key和value的方式
	for (auto iter = hash.begin(); iter != hash.end(); ++iter)
		cout << "first :" << iter->first << "second :" << iter->second << endl;
	for (auto element : hash)
		cout << "first :" << element.first << "second :" << element.second << endl;

}

哈希容器 (unordered_set)

#include <set>

定义及初始化
set<int> a;

1 容量函数
容器大小:st.size();
容器判空:st.empty();
查找键 key 的元素个数:st.count(key);

2 添加函数
在容器中插入元素:st.insert(const T& x);
任意位置插入一个元素:st.insert(iterator it, const T& x);

3 删除函数
删除容器中值为 elem 的元素:st.pop_back(const T& elem);
删除it迭代器所指的元素:st.erase(iterator it);
清空所有元素:st.clear();

4 访问函数
st.find(key);
查找键 key 是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end()


stack(栈)

Stack(堆栈)是一个容器类的改变,为程序提供了堆栈的全部功能,实现了一个先进后出的数据类型。

  • empty() 堆栈为空返回真;
  • pop()移除栈顶元素;
  • push()在栈顶增加元素;
  • size()返回栈中元素;
  • top()返回栈顶元素

指针

  1. 地址的概念

    • 地址:地址就是内存中对每个字节的编号。
    • 深入理解:在程序代码中是通过变量名对内存单元进行存取操作的,但是代码经过编译后已经将变量名转换为该变量在内存中的存放地址,对变量值的存取都是通过地址来操作的。
  2. 指针的概念:
    指针:是一个其值为地址的变量。(就是一个存储地址的变量)

    • 指针是以字节为单位
    • 总结:在程序中定义了一个变量i,在进行编译的时候就会给该变量分配一个内存大小和内存地址,通过这个地址可以访问到所需的变量,这个变量的地址就是该变量的指针。
    • 即使int占4个字节,指针也只有一个。
  3. 变量和编译器的关系

    • 假设定义了int i{},j{};使其相加 sum=i+j;
      含义是:根据变量名与地址的对应关系,找到变量i的地址1000,然后从1000读取4个字节数据放到CPU寄存器中,再找到变量j的地址1004,从1004开始读取4个字节的数据放到CPU的另一个寄存器中,通过CPU的加法中断计算出结果。
  4. 指向的概念
    将变量i的地址存放到变量p中,p就指向i。

  5. 指针变量的概念
    一个变量的地址称为该变量的指针。
    如果有一个变量专门用来存放另一个变量的地址(即指针),这就是指针变量。

    int* p{};//C17要求必须初始化,当然最好也是初始化,不然非常危险。 
    int *p2{};//*号在靠在前在后都一样
    
  • 其中*是表示该变量是一个指针变量
  • 变量名即为定义的指针变量名
  • 数据类型是所指向的变量的数据类型 。
  1. 指针变量的赋值
int a{ 3 }; 
int* p {&a}; 
std::cout << "a的内存地址p:" << p << std::endl; 
std::cout << "*p:" << *p << std::endl; 

int a{ 3 }; 
int* p; 
p = &a;

char* str="hello world";  //这个的含义是把这个常量字符串的内存地址给到指针
  • 使用取址运算符“ & ”来表示变量的地址
  • 可以用两种方式去使用。
  • 因为是局部变量所以地址会变
  • 全局变量地址不会变
  • 严禁将数直接赋值给指针变量
  • 严禁数据类型不相同的定义
  1. 操作内存地址

    *p = 80;
    
  2. 指针的自增自减
    地址加一 :P++
    变量a加一:(*P)++

指针(数组)

  1. 必背知识点
    记住p是地址,*p是变量的值。(记住这句话下面所有的都不用搞混)
  2. 数组与指针
    当定义一个一维数组时,系统会在内存中为该数组分配一个存储空间,其数组的名称就是数组在内存中的首地址。若在定义一个指针变量,并将数组的首地址传给指针变量,则该指针就指向了这个一维数组。指针的本质就是一种特殊的变量类型。
  • 定义数组指针
int a[10]{}; 
int* p{&a[0]}; 
int* p{a}; //这种方式也可以
int a[10]{}; 
int* p{}; 
p=&a[0]; 
p=a;//这种方式也可以
int* p=a;//这种方式也可以,也是给p这个指针数组a 的首地址
  • C++中,数组名代表数组第一个元素(即为序号0的元素)的地址。因此,下面两个语句等价:
p=&a[0]; 
p=a;
int a[10]{}; 
std::cout << a;//这里输出a就是a的地址
//上述"p=a"的作用是把a数组的首地址赋值给指针变量p,而不是把数组a各元素的值赋值给p。
  • 数组的地址是连续的
#include <iostream>
int main()
{
int a[10]{0,1,2,3,4,5,6,7,8,9};
int* p{ a };
int* p2{&a[0]};
for (int i = 0; i < 10; i++)
{
p = &a[i];
std::cout << *p << " ";
std::cout << p <<std::endl;
}
/*第二种方式*/
std::cout << std::endl;
for (int i = 0; i < 10; i++)
{
std::cout << *p2 << " ";
std::cout << p2++<<std::endl;
}
}
  • p+i或者a+i 就是a[i]的地址
  • p+5或者a+5 就是a[5]的地址
  • *(p+i)或 *(a+i) 是p+i或a+i所指向的数组元素,即a[i]。
  • *(p+5)或 *(a+5) 是p+5或a+5所指向的数组元素,即a[5]。
  • 这a[i], *(p+i), *(a+i) 三种方式等价,都是a数组中序号为i的元素。
  • 下标法:a[i]
  • 指针法: *(a+i)或 *(p+i)
  1. 指针的大小
    指针也是个变量,它的内存大小固定为4字节(32位)。
    指针也是个变量,它的内存大小固定为8字节(64位)。
  2. 一维数组与指针自增,自减
  • *p++ :先得到p指向变量的值(*p),再进行p++(p是地址)
  • *p-- :先得到p指向变量的值(*p),再进行p–(p是地址)
  • *++p :先进行p++(p是地址),再取(*p)
  • *–p :先进行p–(p是地址),再取(*p)
  • (*p)++ :先取(*p)里面的值,然后让值+1
  • (*p)-- :先取(*p)里面的值,然后让值-1
  • ++(*p) :先取(*p)里面的值,然后让值+1
  • –(*p) :先取(*p)里面的值,然后让值-1
  • 注意:在std::cout<<里面输出时,注意后 ++ 是输出完毕之后才进行的 ++ 操作。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值