C++从入门到精通【Day2】基本语句、数组与指针

一、选择结构

1.if语句

进行逻辑判断是程序中最基础最重要最核心的逻辑功能。

if语句是最基础的判断语句之一

语法:

if(需要执行的判断)
{   
    判断为ture时,会执行的代码;
}

例:

    int age;
    cout<<"请输入年龄:"<<endl;
    cin>>age;
    if(age<18)
    {
            cout<<"您是未成年人,不能游玩电子游戏"<<endl;
    }
    if(age>18)
    {
            cout<<"您是成年人,可以游玩电子游戏"<<endl;
    }

2.if else语句

if else语句是在if的基础上为条件不成立时提供执行的代码。

语法:

if(判断条件)
{
    判断为ture时,会执行的代码;
}
else
{
    判断为false时,会执行的代码;
}

例:

    int age;
    cout<<"请输入年龄:"<<endl;
    cin>>age;
    if(age<18)
    {
            cout<<"您是未成年人,不能游玩电子游戏"<<endl;
    }
    else
    {
            cout<<"您是成年人,可以游玩电子游戏"<<endl;
    }

3.else if语句

在很多情况下,判断条件不止有一个,这时候可以用else if语句来实现

语法:

if(判断条件1)
{
    条件1判断为true时,会执行的代码;
}
else if(判断条件2)
{
    条件2判断为true时,会执行的代码;
}
else if(判断条件3)
{
    条件3判断为true时,会执行的代码;   
} 
······
else
{
    以上条件全部为false时,会执行的代码;
}

4.逻辑判断语句的嵌套

在很多场景中,不仅会含有多个并列条件,还有许多满足前置条件才会进行第二次判断的多层判断需求,对于这种需求我们需要对判断语句进行嵌套。

以下是基础的双层嵌套:

if(条件1)
{
    code1;
    if(条件11)
    {
        code11;
    }
    else
    {
        code12;
    }
}
else
{
    code2;
}

一般来说,嵌套的层数是不作限定的,判断语句也可以根据需求作出改变。

可以通过使用逻辑运算符来对嵌套进行简化。

5.switch控制语句

        针对多条件判断选择,除了以上的判断语句的重复运用和嵌套运用,C++还提供了一种专用语法:switch控制语句。

        它在功能上与判断语句的组合使用相差无几,只是书写起来更为简洁。

语法:

switch (表达式)
{
case 常量1:
    code1;
    break;//break用于中断switch语句,否则会向下执行其他case段
case 常量2:
    code2;
    break;
default:
    code3;//当没有任何与case条件的值与表达式得到的值相匹配时,执行default的代码code3
}

例:

   int sex;
    cout<<"请输入你的性别: 男1女0"<<endl;
    cin>>sex;
    switch (sex)
    {
        case 1:
            cout<<"你是男的"<<endl;
            break;
        case 0:
            cout<<"你是女的"<<endl;
            break;
        default:
            cout<<"你输入的性别有误"<<endl;
    }

二、循环结构

        在程序中,循环功能也是至关重要的基础功能之一。

1.while循环语句

语法:

while(条件)
{
    code;//符合条件后执行
}

当条件一直符合时,代码会一直无限循环下去。

例:

int num=1;
while ( num==1 )
{
    while(num==1)
    {
        cout<<"Hello"<<endl; //将会一直打印Hello
    }
}

2.do while循环语句

       语法:

do
{
    code; //循环体的代码
}while (条件) //条件判断为真,继续循环

        do while循环其实是while循环的一个变换形式,从代码中不难看出它们的区别在于:

        ·while如果条件判断不成立,可以做到一次都不执行循环体的代码(先判断再执行);

        ·do while即使条件判断不成立,也至少要先执行一次循环体的代码(先执行再判断)。

3.for循环语句

        C++还提供了for循环语句,功能与while循环语句差不多,但仍有一些区别:

语法:

for(循环因子初始化语句; 条件判断 ; 循环因子变化语句)
{
    code;//循环体的代码    
}

for语句内的三个条件:循环因子初始化语句,条件判断,循环因子变化语句都是可以省略的,但一般不建议这么做。

例:

    //打印出1~20的奇数
    for(int i=1;i<=20;i+=2)
    {
        cout<<i<<endl;
    }

4.循环语句的嵌套

其实循环语句的嵌套类似于上文提到的逻辑判断语句的嵌套

以下是用while循环语句嵌套来实现九九乘法表:

int line=1;
    while(line<10) 
    {   
        cout<<"第"<<line<<"行:"<<endl;
        
        int num=1;
        while (num<=line)
        {
            cout<<num<<"*"<<line<<"="<<num*line<<" ";
            if (num%line==0)
            {
                cout<<endl;
            }
            num++;
        }
        line++; //行数递增
    }

以下是用for循环语句嵌套来实现九九乘法表:

    for(int line=1;line<=9;line++)
    {
        cout<<"第"<<line<<"行"<<endl;
        for (int num = 1; num <=line; num++)
        {   
            cout<<num<<"*"<<line<<"="<<num*line<<" ";
        }
        cout<<endl;
    }

三、跳转语句

        在某些场景中,我们可能会需要跳过某次循环或者结束循环,针对这一问题,C++提供了continue语句和break语句。

1.continue语句

continue关键字,跳过本次循环进入下次循环

例:

for(int i=1;i<=5;i++)
{
    cout<<i<<endl;
    continue; //结束本次循环,进入下一次循环
    cout<<"hello"<<endl; 
}

结果会输出 1,2,3,4,5 而没有hello,因为continue语句结束了这五次循环,continue语句以下的代码没有得到执行。

2.break语句

break关键字,直接结束整个循环

例:

for(int i=1;i<=5;i++)
{
    cout<<i<<endl;
    break; //结束整个for循环
    cout<<"hello"<<endl; 
}

结果会仅会输出1,因为break结束了整个循环。

3.goto语句

goto区别于continue和break的区别在于它可以实现无条件跳转

语法:

标记1:
    code1;
    code2;
goto 标记1;
标记2:
    code3;
    code4;

goto会让程序重新跳转到标记的位置开始执行。

例:

int i=1;
loop:
cout<<i<<" ";
i++;
if(i<=10)
{    goto loop;}

只要i<=10,程序会一直跳转回loop标记处。

goto不只能跳出循环,还能跳到程序中的任一位置,是非常自由的。

四、数组

1.数组的定义

数组是由一批相同数据类型的元素所组成的集合,分配了一块连续的内存来存储一个数组。

语法:

<数组的数据类型> <数组名> [<数组长度>]
例如:int v[6]; //声明了一个可以存放6个整型数据的数组

数组中的每个元素都有编号,称为下标索引,以第一个元素开始从0开始编号

可以通过<数组名>[<下标索引>]来使用数组中的元素,如

v[0]=10;给数组的第一个元素赋值10
v[5]=50;给数组的第六个元素赋值50

数组也可以声明的同时赋值:

int v[3]={11,22,33}

2.数组的特点

(1)任何数据类型都可以构建数组

·基本数据类型:int , float , double , char , string , bool等

·复合数据类型:结构体 , 联合体等

·指针类型:int* , char* , float*等

·枚举类型:enum

以上均可以形成数组。

(2)固定大小

C++中数组一旦定义完成,它的长度大小即固定 

如int v[5]; 数组v的大小固定为5。

C++中不会做数组边界检查,也就是说下标索引超出数组范围时,编译过程中不会报错,如

int v[5]={1,2,3,4,5}
v[10]=1;
cout<<v[50]<<endl;

以上代码编译都能通过,但是运行起来可能会有未知问题。

(3)内存连续且有序

数组内存空间是连续分配的,并且每个元素分配的大小取决于存放的数据类型。如:

int v[5]={1,2,3,4,5}

v[0],v[1],v[2],v[3],v[4]的数据类型都是int,因此它们都占4字节内存。

我们可以通过这个特点使用 sizeof(数组)/sizeof(数组某个元素) 来得到数组元素的个数。  

(4)元素可修改

数组中的每一个元素都可以重新赋值进行修改,但是不能修改数据类型。

(5)数组变量不记录数据

对于这个数组变量v,它本身并非记录了数组内的全部元素,而是记录了v[0]元素的内存地址。

    int v[]={1,2,3,4,5};
    cout<<v[0]<<endl; //结果为1
    cout<<v<<endl; //结果为0x61fefc (v[0]的内存地址,用16进制表示)
    

由上可见访问数组v本身 即访问 数组第一个元素v[0]的内存地址

数组元素访问规律如下:

·通过下标索引1可以找到第二个元素内存地址,得到v[1]

·通过v[0]地址+单个元素空间大小(数组v是整型的,所以此处填4字节),找到v[1]

·通过v[1]地址+4字节,可找到v[2]

······以此类推

3.多维数组

多维数组即对数组进行嵌套,数组内的每个元素依旧是数组。

根据嵌套的层次可以有:二维数组、三维数组、四维数组...

使用语法:

//二维数组
int v[3][3]=        //二维数组其实可以近似的看作一张二维表
    {   {11,12,13},
        {21,22,23},
        {31,32,33}
    }                //这是一张3x3的二维表

        如以上二维数组,调用第2行第3列的数据即v[2][3]

三维数组则可以看作是一个三维坐标系一样

遍历二维数组:

    //遍历二维数组v
    for(int i=0;i< sizeof(v) / sizeof(v[1]) ;i++)
    {
        for(int j=0;j<sizeof(v[1]) / sizeof(v[1][1]) ;j++)
        {
            cout<<v[i][j]<<" ";
        }
        cout<<endl;
    }

五、指针

指针是C++中至关重要的一部分,它是C++语言最强大的功能之一,同时也是最棘手的功能之一。

它的本质是协助程序员对内存进行直接操纵。

1.指针变量的定义

指针:特定类型数据在内存中的存储地址,即内存地址。指针这个名词其实就代表着地址这个意思。

指针只是一个逻辑概念,其实际应用是:指针变量。指针变量也就是指针(地址)的一个载体。

指针变量的定义语法:

变量类型* 指针变量名;

指针变量名=内存地址值;

int num=10;
int * p; //声明p这一指针变量,此时p这个变量只存储地址
p = &num; //赋值,为p存放num变量的内存地址
cout<< p ; //输出num变量的内存地址
cout<< *p; //输出p所存储的地址对应的值,也就是num的值10

*符号有两种含义:

声明时,*p表示的是指针变量p(存的是内存地址);

使用时,*p表示取指针变量p中内存地址的值,即取值;

&符号是一个单目运算符,表示取变量的内存地址。

2.野指针和空指针

野指针:被声明了但是未初始化(赋值)的指针。

        指针在声明后会被分配到的内存空间里,该内存空间里可能会有上一个程序使用时所残留的数据,需要初始化(赋值)进行覆盖,这时候该内存空间里的数据才是自己的东西。若未进行初始化(赋值),内存空间里会有其他程序的数据残留。

        野指针有非常大的安全隐患,为了避免野指针,我们应该养成良好的习惯,及时初始化,或者将指针置为空指针更为安全。

空指针:指针指向的地方为”空“,即不指向任何地方

int *p = NULL;
int *p = nullptr;

以上是两种空指针的写法,

·NULL是C++内置的宏,表示"什么都没有"的含义,本质是0

·nullptr是C++11标准引入的新的关键字

空指针仅作为过渡作用,在不使用的情况下实际上也是一种多余的垃圾代码,所以在应用中需要我们尽快为指针寻找用途。

3.指针运算

虽然指针变量记录的是内存地址,但是仍可以进行基础的数学运算。

对指针进行基础数学运算非常适合操纵数组并配合做动态内存分配

int num=10;
int *p = &num;
cout<<p<<endl; //结果为0x61ff08  (这里的地址是用16进制数表示的)
p++;
cout<<p<<endl; //结果为0x61ff0c

指针进行加减运算的结果,与数据类型有关,以以上代码为例,p为int类型,p++则为地址加了4个字节大小,故为结果为0x61ff0c。指针±n,则内存地址 ±n * 数据类型大小。

以int数组为例,数组中每个元素的内存地址的间隔就是4个字节,因此通过指针运算可以得到其他元素的内存地址。

4.const指针(常量指针)

const是C++的关键字,也就是常量的意思。 

(1)指向const的指针

       指向const的指针 :指针指向的区域的数据,是不变的,但是可以更改指针指向的区域。

语法:(将const写在 * 之前):

const 数据类型 * 指针;
数据类型 const * 指针;

例:

int num1=10,num2=100;
const int * p = &num1; //指针p指向num1的区域

*p = 20; //尝试为num1区域的值更改为20,但是执行不了,因为这个区域被指针p指向了

p = &num2; // 指针的指向可以改变

(2)const指针

const指针:指针本身不可以更改,但是指向的区域的数据可以更改。

语法:(将const写在 * 之后)

数据类型 * const 指针 = 地址 ; // 必须初始化地址,因为指针不可修改了

例:

int num1=10,num2=100;
int * const p = &num1; //指针p指向num1的区域

*p = 20; //可以执行,可以改变指向的num1的区域的数据

p = &num2;  //不能更改指向的区域

3.指向const的const指针

由上面两类可以得出,这类指针的 指向区域  和 指向区域内的数据  都不可以更改。

语法:(*的前后都写const)

const 数据类型 * const 指针 = 地址 ; // 必须初始化地址,因为指针不可修改了

例:

int num1=10,num2=100;
const int * const p = &num1; //指针p指向num1的区域

*p = 20; //不可以改变指向的num1的区域的数据

p = &num2;  //不能更改指向的区域

六、数组与指针的运用

 1.动态内存分配 

动态内存分配:即由程序员手动进行内存空间的分配、内存空间的释放等内存管理操作。

编写代码中面临的问题:

        在程序中,若一个变量在使用一次后,后续的程序中没有任何作用了,若不对这个变量进行释放,那么直到程序就会一直占用内存空间。

         C++中,变量、数组等对象的创立,是由C++自动分配内存的,称为静态(自动)内存分配,但它是不会进行内存空间的自动清理,因此需要我们手动的管理内存,即手动分配,用完清理。

(1)new运算符

        new运算符用于申请并分配内存空间,并提供指向该空间的指针

语法:

new 数据类型; //申请普通变量空间
new 数据类型[n]; //申请数组空间

例:

int *p1 = new int;
int *p2 = new int[5];

(2)delete运算符.

delete运算符用于释放内存,仅可用于new运算符申请的内存空间。

语法:

delete 指针; //删除普通变量空间
delete[] 指针;//删除数组空间

例:

int *p = new int[5];
p[0]=1;
delete[] p;

(3)指针悬挂问题

        当一个指针p1指向另一个指针p2时,对指针p2进行delete操作,此时p2的内存空间被回收了,由于指针p1此时搜索不到指针p1的内存地址,此时指针p1不能正常使用,它将会指向一个未知的随机的值。该问题可能会引发安全问题。

        这种指针指向区域被回收的问题被称为:指针悬挂。

2.数组元素的插入、移除

C++未提供对数组元素进行插入、移除的功能,需要手动实现(后续会学习到vector容器)。

移除元素的核心思路:

1.通过new申请新数组的内存空间,并复制数据到该新数组

2.通过delete删除旧数组的空间占用

3.将旧数组指针指向新数组的地址

移除操作实例:

int *Oldp = new int [4] {10,20,30,40};   //旧数组
cout<<"旧数组:"<<endl;
for(int i=0;i<4;i++)
{
    cout<<Oldp[i]<<" ";         //遍历旧数组
}
int *Newp = new int [4];  //声明新数组
for(int i = 0;i<4;i++)
{
    if(i == 2)
    {
        continue; //假设不需要第三个元素,则跳过
    }
    if(i > 2)
    {
        Newp[i-1]=Oldp[i];   //若已经跳过第三个元素,将第i个旧数组元素赋值给第i-1个数组元素
    }
     else
    {
        Newp[i]=Oldp[i];    //若没有跳过第三个元素,则直接赋值
    }
}

cout<<endl<<"新数组:"<<endl;
for(int i=0;i<4;i++)
{
    cout<<Newp[i]<<" ";         //遍历新数组
}

delete [] Oldp; //释放旧数组的内存空间
Oldp = Newp; //将旧数组的指针指向新数组的内存空间
cout<<endl<<"新数组: "<<endl;
for(int i=0;i<4;i++)
{
    cout<<Oldp[i]<<" ";  //此时相当于遍历新数组
}

插入操作的核心思路:

1.创建新数组,将旧数组元素和新插入元素一起复制到新数组中

2.要注意,新元素在指定位置插入时,老数组元素要配合做下标增加

插入操作示例:

int *Oldp = new int [4] {10,20,30,40};   //旧数组
cout<<"旧数组:"<<endl;
for(int i=0;i<4;i++)
{
    cout<<Oldp[i]<<" ";         //遍历旧数组
}
int *Newp = new int [6];  //声明新数组

//假设在下标1和下标3插入新元素:11和33
//循环新数组,依次进行元素填充(非插入的位置,填充老数组元素,插入的位置填充新元素)
int offset = 0; //偏移量,用来控制新老元素的下标对照
for (int i = 0; i < 6; i++)
{
    if(i == 1)
    {
        Newp[i] = 11;       //走到了下标1,插入新元素11
        offset++;           //每插入一个新元素,偏移量+1
        continue;
    }
    else if(i == 3)
    {
        Newp[i] = 33;  //走到了下标3,插入新元素33
        offset++;
        continue;
    }
    else
    {
        Newp[i] = Oldp[i-offset];  //   i   - 偏移量offset = 旧数组当前走到的下标 
    }
}

delete[] Oldp;
Oldp = Newp;
//遍历新数组
cout<<endl<<"新数组:"<<endl;
for(int i=0;i<6;i++)
{
    cout<<Oldp[i]<<" ";         
}

其他内容

1.枚举类型

枚举:本质上是一个整型常数的集合。它在C++中也是一种基本的数据类型。

它的主要作用是提高代码的可维护性和可读性

语法:关键字enum

enum 枚举名
{
    元素一,
    元素二,
    元素三,
    ···
};

枚举中的每一个元素都有整数编号,默认从0开始递增,也可以为它们各自赋值

例:

enum Season
{
    spring, //默认为0
    summer, //递增后为1
    autumn, //递增后为2
    winter  //递增后为3
};

enum Season
{
    spring=3, //赋值为3
    summer=4, //递增后为4
    autumn=7, //赋值为7
    winter=10  //赋值为10
};

cout<<spring<<endl;//输出为3
cout<<summer<<endl;//输出为4
cout<<autumn<<endl;//输出为7
cout<<winter<<endl;//输出为10

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值