当前位置:   article > 正文

C++学习笔记——语法篇_c++固定格式

c++固定格式

目录

一、初识C++

1、固定格式

2、第一个程序:hello world

3、注释

4、变量与常量

5、关键字/标识符

二、数据类型

1、整型

2、实型(浮点型)

3、字符型和字符串类型

4、转义字符

5、布尔类型

6、数据的输入

三、运算符

1、算数运算符

2、赋值运算符

3、比较运算符

4、逻辑运算符

四、程序运行结构

1、选择结构:if语句

2、循环结构:while语句、for语句

五、数组

1、一维数组

2、二维数组

六、函数

1、函数的定义

2、函数的调用

3、函数的常见样式

4、函数的声明

七、指针

1、指针的定义和使用

2、指针所占的内存空间

3、空指针和野指针

4、const修饰指针

5、指针和数组、指针和函数

八、结构体

1、结构体的定义和使用

2、结构体数组

3、结构体指针

4、结构体嵌套结构体

5、结构体做函数参数

6、结构体中的const使用场景

7、结构体案例


一、初识C++

1、固定格式

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. // 这里写代码...
  6. system ("pause");
  7.     return 0;
  8. }

2、第一个程序:hello world

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     cout << "hello world" << endl;
  6.     return 0;
  7. }

3、注释

单行注释://     

多行注释:/* */

4、变量与常量

变量:数据类型 变量名=变量值;

int a = 5;

常量:宏常量、const修饰变量

宏常量:#define 常量名 常量值

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     #define day 7
  6.     cout << "一周总共有" << day << "天" << endl;
  7.     return 0;
  8. }

const修饰变量:const 数据类型 常量名=常量值

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     const int month = 12;
  6.     cout << "一年有" << month << "个月" << endl;
  7.     return 0;
  8. }

5、关键字/标识符

在定义变量或者常量的时候不要用下面这些关键字。

标识符命名规则:

1、不能是关键字;2、只能由字母、数字、下划线组成;

3、第一个字符必须为字母或下划线;4、字母严格区分大小写。

二、数据类型

1、整型

int 变量名 = 变量值;

数据类型存在的意义:给变量分配合适的内存空间。

sizeof关键字:sizeof(数据类型/变量)

利用sizeof关键字可以统计数据类型所占内存大小。

2、实型(浮点型)

单精度:float

双精度:double

float 变量名 = 变量值;

两者唯一的区别在于表示的有效数字范围不同。

float:占用4字节,7位有效数字。

double:占用8字节,15-16位有效数字。

还有一种小数表示法:科学计数法(少用),float a = 3e2,3e2表示:3*10^2

float a = 3.14f;一般我们会在数字后面加上一个f,否则编译器会默认是双精度类型的。

float默认情况下会在小数点后显示5位。

3、字符型和字符串类型

字符型:char 变量名 = 一个字符;

注:只能用单引号,不能用双引号,而且只能有一个字符,不能是字符串。

C和C++中都只占用1个字节。

字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放入到存储单元。

查看字符的ASCII码:cout << (int)a << endl;

 (int)a:把字符型强制转化成整型,a是97,A是65。

字符串类型:

C语言:char 变量名[] = 字符串值;

C++:string 变量名 = 字符串值;

这两种风格在C++中都可以用,记得要用双引号。

4、转义字符

现阶段常用的有:\n、\\、\t

\t一共占8个位置,如果是aaaa\t,那么输出结果为:aaaa+4个空格,如果是aaa\t,输出结果为:aaa+5个空格。

5、布尔类型

bool 变量名 = true/false;

bool型只有两种:true、false,本质上1代表真值,0代表假值,布尔类型只占1个字节大小。

6、数据的输入

cin >> 变量1 >> 变量2 >> 变量3

输入之前记得先声明变量类型。

三、运算符

1、算数运算符

两个整数相除,结果依然是整数,去抹去小数部分。

前置递增++a表示:先让变量+1,然后再进行表达式的运算;

后置递增a++表示:先进行表达式的运算,后让变量+1。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     int a = 10;
  6. int b = ++a *10;
  7.     int c = 10;
  8. int d = c++ *10;
  9.     cout << "a=" << a << endl;
  10.     cout << "b=" << b << endl;
  11.     cout << "c=" << c << endl;
  12. cout << "d=" << d << endl;
  13. // 输出的结果:a=11,b=110,c=11,d=100
  14.     return 0;
  15. }

2、赋值运算符

=、+=、-=、*=、/=、%=

3、比较运算符

==相等于,!=不等于

>、<、>=、<=

4、逻辑运算符

四、程序运行结构

程序运行结构:顺序结构、选择结构、循环结构

1、选择结构:if语句

单行:if(条件){条件满足执行的语句}

多行:if(条件){条件满足执行的语句}

           else{条件未满足执行的语句}

多条件:if(条件1){条件1满足执行的代码}

              else if(条件2){条件2满足执行的代码}

               ......

              else{以上条件都不满足执行的代码}

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     // 用户输入分数,如果在500-600区间内,恭喜考上本科,如果大于600,恭喜考上重点,否则,复读。
  6.     int score = 0;
  7.     cout << "请输入一个分数:" << endl;
  8.     cin >> score;
  9.     if(score>600)
  10.     {
  11.         cout << "考上重点大学!" << endl;
  12.     }
  13.     else if(500<=score && score<=600)
  14.     {
  15.         cout << "考上本科!" << endl;
  16.     }
  17.     else
  18.     {
  19.         cout << "去复读!" << endl;
  20.     }
  21.     return 0;
  22. }

嵌套if语句:if语句中再嵌套if语句

接上面的例子,在大于600分的重点档里,600-630:211,630-680:985,680+:清北。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     int score = 0;
  6.     cout << "请输入一个分数:" << endl;
  7.     cin >> score;
  8.     if(score>600)
  9.     {
  10.         if (score > 600 && score <= 630)
  11.         {
  12.             cout << "考上211大学!" << endl;
  13.         }
  14.         else if(score > 630 && score <= 680)
  15.         {
  16.             cout << "考上985大学!" << endl;
  17.         }
  18.         else
  19.         {
  20.             cout << "考上清北!" << endl;
  21.         }
  22. }
  23.     else if(500<=score && score<=600)
  24.     {
  25.         cout << "考上本科!" << endl;
  26. }
  27.     else
  28.     {
  29.         cout << "去复读!" << endl;
  30.     }
  31.     return 0;
  32. }

小练习:三只小猪称体重:分别输入三只小猪的体重,判断哪只最重。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     int a=0,b=0,c=0;
  6. cin >> a >> b >> c;
  7.     if(a>b)
  8.     {
  9.         if(a>c)
  10.         {
  11.             cout << a << endl;
  12.         }
  13.         else
  14.         {
  15.             cout << c << endl;
  16.         }
  17. }
  18.     else
  19.     {
  20.         if(b>c)
  21.         {
  22.             cout << b << endl;
  23.         }
  24.         else
  25.         {
  26.             cout << c << endl;
  27.         }
  28. }
  29.     return 0;
  30. }

三目运算符和switch语句

三目运算符:条件?条件满足执行的语句:条件不满足执行的语句;

switch语句:

switch(需要判断的变量)

{

  case 常量1 :当变量=常量1时需要执行的语句;break;

  case 常量2 :当变量=常量2时需要执行的语句;break;

  ......

  default:其他情况下执行的语句;break;

}

注意在判断时只能是一个整型或者字符型,不能是一个区间。

优点是结构清晰,执行效率高于if。

练习:给电影打分。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.     int score = 0;  
  6.     cin >> score;
  7.     switch(score)
  8.     {
  9.         case 9:
  10.         cout << "经典佳作!" << endl;
  11.         break;
  12.         case 8:
  13.         cout << "不错的电影!" << endl;
  14.         break;
  15. // ...
  16.         default:
  17.         cout << "都一般!" << endl;
  18.         break;
  19. }
  20.     return 0;
  21. }

2、循环结构:while语句、for语句

while语句:while(条件){条件满足时执行的语句}

练习:系统随机生成1-100之间的数字,玩家进行猜测,如果猜错,提示玩家数字过大或者过小,如果猜对,恭喜玩家获得胜利,并退出游戏。

生成随机数:rand()%要生成的随机数的区间最大值,如rand()%100,表示生成0-99的随机数。

  1. #include <iostream>
  2. using namespace std;
  3. #include <ctime>
  4. int main()
  5. {  
  6.     // 添加随机数种子,利用当前系统时间生成随机数,防止每次随机数都一样。
  7.     srand((unsigned int)time(NULL));
  8.     int num = rand()%100+1;
  9.     int guess = 0;
  10.     while(1)
  11.     {  
  12.         cin >> guess;
  13.         if(guess>num)
  14.         {
  15.         cout << "猜大了" << endl;
  16.         }
  17.         else if(guess<num)
  18.         {
  19.         cout << "猜小了" << endl;
  20.         }
  21.         else
  22.         {
  23.             cout << "猜对了" << endl;
  24.             break;
  25.         }
  26.     }
  27.     return 0;
  28. }

do...while语句:do(循环语句)while(循环条件)

与while不同的是,它会先执行一次循环语句,再判断循环条件。

练习:水仙花数是指一个3位数,它的每个位上的数字的3次幂之和等于它本身,例如:1^3+5^3+3^3=153,请利用do...while语句,求出所有3位数中的水仙花数。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.     // 1、先获取所有的三位数100-999,;2、在所有的三位数中找到水仙花数。
  6.     int num = 100;
  7.     do
  8.     {  
  9.         int a,b,c;
  10.         // a:个位,b:十位,c:百位。
  11.         // 如果想拿到一个数字的个位数,只需要对它模以10即可。
  12.         a = num % 10;
  13.         b = num / 10 % 10;
  14.         c = num / 100;   
  15.         if(a*a*a + b*b*b + c*c*c == num)
  16.         {
  17.             cout << num << endl;
  18.         }
  19.         num++;
  20.     } while (num<1000);
  21.     return 0;
  22. }

for语句:for(起始表达式;条件表达式;末尾循环体){满足条件执行的循环语句}

eg:for(inti=1;i<10;i++){cout << i << endl;}

练习:敲桌子游戏:从1开始到数字100,如果数字个位或者十位含有7,或者该数字是7的倍数,敲桌子,其余数字输出。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.     for(int i=1;i<=100;i++)
  6.     {
  7.         if(i%7==0 || i%10==7 || i/10==7)
  8.         {
  9.             cout << "敲桌子" << endl;
  10.         }
  11.         else
  12.         {
  13.             cout << i << endl;
  14.         }
  15.     }
  16.     return 0;
  17. }

嵌套循环:在循环体中再嵌套一层循环。

练习:利用嵌套循环打印下面的乘法口诀表。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.     // 1、列数*行数=结果;2、列数<=当前行数
  6.     for(int i=1;i<=9;i++)
  7.     {
  8.         for(int j=1;j<=i;j++)
  9.         {
  10.             cout << i << "x"  << j << "=" << j*i << " ";
  11.         }
  12.         cout << endl;
  13.     }
  14.     return 0;
  15. }

跳转语句:break、continue、goto

break:用于跳出选择结构或者循环结构。

continue:跳过本次循环中余下未执行的语句,继续执行下一次循环。

goto:可以无条件跳转语句。goto 标记,如果标记的名称存在,则会直接跳转到标记的语句执行。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.     cout << "11111" << endl;
  6.     cout << "22222" << endl;
  7.     goto FLAG;
  8.     cout << "33333" << endl;
  9.     cout << "44444" << endl;
  10.     FLAG:
  11.     cout << "55555" << endl;
  12.     return 0;
  13. }
  14. // 输出结果为:11111 22222 55555

五、数组

所谓数组,就是一个集合,里面存放了相同类型的数据元素。

特点:1、数组中的每个数据元素都是相同的数据类型;2、数组是由连续的内存位置组成的。

从0开始进行索引。

1、一维数组

一维数组的三种定义方式:

1、数据类型 数组名[数组长度];

2、数据类型 数组名[数组长度] = {值1,值2,...};

3、数据类型 数组名[] = {值1,值2,...};

如果规定了数组长度为5,但是只写入3个数,剩下的数会自动用0填充。

定义的时候必须初始化它的长度。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.     // 1、数据类型 数组名[数组长度];
  6.     int a[3];
  7.     // 给数组中的元素进行赋值:
  8.     a[0] = 10;
  9.     a[1] = 20;
  10.     a[2] = 30;
  11.     // 2、数据类型 数组名[数组长度] = {值1,值2,...};
  12. int b[3] = {10,20,30};
  13.     // 3、数据类型 数组名[] = {值1,值2,...};
  14. int c[] = {10,20,30};
  15.     // 访问数组元素:利用循环输出数组元素。
  16.     for(int i=0;i<3;i++)
  17.     {  
  18.         cout << a[i] << endl;
  19.     }
  20.     for(int j=0;j<3;j++)
  21.     {    
  22.         cout << b[j] << endl;
  23.     }
  24.     for(int s=0;s<3;s++)
  25.     {
  26.         cout << c[s] << endl;
  27.     }
  28.     return 0;
  29. }

直接cout<< a << endl;出来的是它的十六进制地址:0x61fe14

一维数组名的用途:

1、可以统计整个数组在内存中的长度;

2、可以获取数组在内存中的首地址。

注:数组名是一个常量,不可以进行赋值操作。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5. int a[5] = {1,2,3,4,5};
  6.     // 统计整个数组所占用的内存长度,这个输出为20
  7. cout << sizeof(a) << endl;
  8. // 统计单个元素所占的内存空间,这个输出为4,可以通过sizeif(a)/ sizeof(a[0])来获取数组长度。
  9. cout << sizeof(a[0]) << endl;
  10.     // 获得整个数组首地址,为了方便查看,可以利用long long把它转成十进制,这个输出为:6422016
  11. cout << (long long)a << endl;
  12.     // 获得某个元素的首地址,因为第一个元素的首地址和整个数组的首地址是一样的,这里演示第二个元素,输出为:6422020
  13. cout << (long long)&a[1] << endl;
  14.     return 0;
  15. }

练习:数组元素逆置。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.     int set[5] = {1,2,3,4,5};
  6.     cout << "原数组元素为:" << endl;
  7.     for(int i=0;i<5;i++)
  8.     {
  9.         cout << set[i] << endl;
  10. }
  11.     // 获取起始元素下标位置和末尾元素的下表位置
  12.     int start = 0;
  13.     int end = (sizeof(set)/sizeof(set[0]))-1;
  14.     while (start<end)
  15.     {
  16.         // 首尾元素互换
  17.         int temp = set[start];
  18.         set[start] = set[end];
  19.         set[end] = temp;
  20.         // 下标更新
  21.         start++;
  22.         end--;
  23.     }
  24.     //打印输出逆置后的数组
  25.     cout << "数组元素逆置后为:" << endl;
  26.     for(int j=0;j<5;j++)
  27.     {
  28.         cout << set[j] << endl;
  29. }
  30.     return 0;
  31. }

冒泡排序:最常用的排序算法,对数组内元素进行排序。

升序排序、降序排序。

练习:对42805719进行升序排列

1、比较相邻的元素,如果第一个比第二个大,就交换他们两个。

      第一轮对比完成后结果为:240571389

2、找到第一个最大值:9

     这个9就像一个气泡一样冒出来,所以叫它冒泡排序。

3、重复上面的步骤,每次比较次数-1,直到不需要比较。

     第一轮对比8次(元素数-1),第二轮对比7次...

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.     int set[9] = {4,2,8,0,5,7,1,3,9};
  6.     cout << "未排序之前的数组为:" << endl;
  7.     for(int i=0;i<9;i++)
  8.     {
  9.         cout << set[i] << endl;
  10. }
  11.     // 开始冒泡排序:总共排序的轮数=元素个数-1
  12.     for(int i=0;i<9-1;i++)
  13.     {
  14.         // 内层循环对比=元素个数-当前轮数-1
  15.         for(int j=0;j<9-i-1;j++)
  16.         {
  17.             // 如果第一个数字比第二个数字大,交换两个数字
  18.             if(set[j] > set[j+1])
  19.             {  
  20.                 // 实现两个元素的交换。
  21.                 int temp = set[j];
  22.                 set[j] = set[j+1];
  23.                 set[j+1] = temp;
  24.             }
  25.         }
  26. }
  27.     cout << "排序后结果为:" << endl;
  28.     for(int s=0;s<9;s++)
  29.     {
  30.         cout << set[s] << endl;
  31. }
  32.     return 0;
  33. }

2、二维数组

二维数组的四种定义方式:

1、数据类型 数组名[行数][列数];

2、数据类型 数组名[行数][列数] = {{数据1,数据2},{数据3,数据4}};

3、数据类型 数组名[行数][列数] = {{数据1,数据2,数据3,数据4}};

4、数据类型 数组名[][列数] = {{数据1,数据2,数据3,数据4}};

推荐第二种,更为直观。

按照以下坐标进行访问:

利用for循环打印二维数组中的每个元素:

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.     int set[2][3] = {{1,2,3},{4,5,6}};
  6.     for(int i=0;i<2;i++)
  7.     {
  8.         for(int j=0;j<3;j++)
  9.         {
  10.             cout << set[i][j] << endl;
  11.         }
  12.     }
  13.     return 0;
  14. }

二维数组名:

1、查看二维数组所占用的内存空间;

2、获取二维数组首地址。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5. int set[2][3] = {{1,2,3},{4,5,6}};
  6.     // 1、查看二维数组占用的内存空间大小
  7.     cout << "二维数组占用的内存空间为:" << sizeof(set) << endl; 
  8.     cout << "二维数组第一行占用的内存空间为:" << sizeof(set[0]) << endl;
  9.     // 可以利用sizeof求行数:整个/每行;求列数:每行/每个。
  10.     cout << "二维数组的行数为:" << sizeof(set)/sizeof(set[0]) << endl;
  11.     cout << "二维数组的列数为:" << sizeof(set[0])/sizeof(set[0][0]) << endl;
  12.  
  13.     // 2、查看二维数组的首地址
  14.     cout << "二维数组的首地址为:" << set <<endl;
  15.     // 转成十进制:
  16.     cout << "二维数组的首地址为:" << (long long)set <<endl;
  17.     cout << "二位数组第一行首地址为:" << (long long)&set[0] <<endl;
  18.     cout << "二位数组第一个元素首地址为:" << (long long)&set[0][0] << endl;
  19. // 二维数组的首地址=二维数组第一行的首地址=位数组第一个元素的首地址
  20.     return 0;
  21. }

练习:考试成绩统计:

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {  
  5.     int grade[3][3] = {{100,100,100},{90,50,100},{60,70,80}};
  6.     for(int i=0;i<3;i++)
  7.     {  
  8.         int sum = 0;
  9.         for(int j=0;j<3;j++)
  10.         {  
  11.             sum += grade[i][j];
  12.             // cout << grade[i][j];
  13.         }
  14.         cout << sum << endl;
  15.     }
  16.     return 0;
  17. }

六、函数

1、函数的定义

函数的定义要有以下五个步骤:

返回值类型、函数名、形参列表、函数体语句、return表达式

返回值类型 函数名 (形参列表)

{

   函数体语句;

   return表达式;

}

如:计算两个数相加的函数。

int add(int a,int b)

{

    int sum = a + b;

    return sum;

}

2、函数的调用

函数名(实参)

练习:调用上面的加法函数。

int main()

{  

    int num1 = 10;

    int num2 = 20;

    int s = add(num1,num2);

    cout << s << endl;

    return 0;

}

在函数定义的时候,a和b并没有真实的数据,只是一个形式上的参数,简称形参;后面调用的时候,实参的值会传递给形参。

函数调用时实参将数值传递给形参,这就叫值传递。

3、函数的常见样式

常见四种:无参无返、有参无返、无参有返、有参有返。

无返回值都用void声明返回值类型。

  1. #include <iostream>
  2. using namespace std;
  3. // 1、无参无返:void
  4. void test01()
  5. {
  6.     cout << "test01函数" << endl;
  7. }
  8. // 2、有参无返:void
  9. void test02(int a)
  10. {
  11.     cout << "test02函数,传入的参数:" << a << endl;
  12. }
  13. // 3、无参有返
  14. int test03()
  15. {
  16.     cout << "test03函数" << endl;
  17.     return 3;
  18. }
  19. // 4、有参有返
  20. int test04(int b)
  21. {
  22.     cout << "test04函数,传入的参数:" << b << endl;
  23.     return b;
  24. }
  25. int main()
  26. {  
  27.     // 调用无参无返函数
  28.     test01();
  29.     // 调用有参无返函数
  30.     test02(2);
  31.     // 调用无参有返函数,如果有返回值了就需要有变量来接收。
  32.     int s = test03();
  33.     cout << "test03返回值为:" << s << endl;
  34.     // 调用有参有返函数
  35.     int t = test04(4);
  36. cout << "test04返回值为:" << t << endl;
  37.     return 0;
  38. }

4、函数的声明

告诉编译器函数名称及如何调用函数,函数的实际主体可以单独定义。

为什么要写函数的声明?——之前只能在main函数体前写函数,这样程序才会执行,但是如果想把函数写在main函数体后面,需要先告诉编译器函数的存在,这就需要利用函数的声明。

声明可以写多次,但是定义函数只有一次。

练习:比较函数,两个整形数字进行比较,返回较大的值。

  1. #include <iostream>
  2. using namespace std;
  3. // 声明比较函数max的存在
  4. int max(int a,int b);
  5. int main()
  6. {  
  7.     int a = 10;
  8.     int b = 20;
  9.     cout << max(a,b) << endl;
  10.     return 0;
  11. }
  12. // 定义比较函数max
  13. int max(int a,int b)
  14. {
  15.     return a>b?a:b;
  16. }

七、指针

1、指针的定义和使用

指针的作用:可以通过指针间接访问内存。

内存编号是从0开始记录的,一般用十六进制数字表示,可以用指针变量保存地址。

指针的定义:

数据类型 变量名 = 变量值;

数据类型 * 指针变量名;

指针变量名 = &变量名;

或者直接:数据类型 * 指针变量名 = &变量名

指针的使用:

通过解引用的方式来找到指针指向的内存。

* 指针变量名

&取地址,*取值。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     int a = 10;
  6.     // 定义指针
  7.     int* p;
  8.     p = &a;
  9. // 或者直接:int* p = &a;其中,p就是指针(地址)。
  10. // 获取指针中存放的地址:
  11.     cout << "指针中存放的地址编号为:" << p << endl;
  12.     // 输出结果为:指针中存放的地址编号为:0x61fe14
  13.     // 获取指针中存放的地址中存放的数据:解引用,在指针前加一个*就是解引用,可以找到指针指向的内存中的数据。
  14.     cout << "指针中地址编号中存放的数据为:" << *p << endl;
  15.     // 输出结果为:指针中地址编号中存放的数据为:10
  16.     return 0;
  17. }

2、指针所占的内存空间

指针也是一种数据类型,一般来说,在32位操作系统下占4个字节,64位下占8个字节。

3、空指针和野指针

空指针:指针变量指向内存为0的空间,用于初始化指针变量。

空指针指向的内存是不可以访问的。

如果一开始不知道指针指向哪里合适,可以用空指针。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     // 1、空指针用于初始化指针变量
  6. int* p = NULL;
  7.     // 2、空指针不可访问
  8.     *p = 100;
  9. // 这个运行会报错!
  10.     return 0;
  11. }

野指针:指针变量指向非法的内存空间。

在程序中要尽量避免出现。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     // 野指针:我们随便编了一个内存地址
  6. int* p = (int*)0x1100;
  7. // 这个运行会报错!
  8.     return 0;
  9. }

4、const修饰指针

①const修饰指针:常量指针——指针指向可以修改,指针指向的值不能修改。

const int * p = & a;

②const修饰常量:指针常量——指针指向的值能修改,指针指向不能修改。

int * const p = & a;

③const既修饰指针,又修饰常量——指针指向和指针指向的值都不能修改。

小技巧:可以把const译成常量,*译成指针,const *就是常量指针,*const就是指针常量。

5、指针和数组、指针和函数

1、指针和数组:利用指针访问数组中的元素。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     int arr[10] = {1,2,3,4,5,6,7,8,9,10};
  6.     int *p = arr;
  7.     // 数组名就是地址,数组名是第一个元素的地址,和数组地址虽然值一样,但指向大小不一样。
  8. cout << "利用指针来访问第一个元素:" << *p << endl;
  9.     // 让指针往后移4个字节即可(一个整型 元素占4个字节)
  10. p++;
  11.     cout << "利用指针来访问第二个元素:" << *p << endl;
  12.     return 0;
  13. }

还可以直接p[i],下标从0开始

2、指针和函数:利用指针作函数参数,可以修改实参的值。

  1. #include <iostream>
  2. using namespace std;
  3. // 函数:两个数字进行交换
  4. // 1、值传递
  5. void swap01(int a,int b)
  6. {
  7.     int temp = a;
  8.     a = b;
  9.     b = temp;
  10.     cout << "swap01中的a=" << a << endl;
  11.     cout << "swap01中的b=" << b << endl;
  12. }
  13. // 2、地址传递:如果我们想在函数体中真的修改外部的a、b的数据,就用这个
  14. void swap02(int *p1,int *p2)
  15. {
  16.     int temp = *p1;
  17.     *p1 = *p2;
  18.     *p2 = temp;
  19.     cout << "swap02中的a=" << *p1 << endl;
  20.     cout << "swap02中的b=" << *p2 << endl;
  21. }
  22. int main()
  23. {
  24.     int a = 10;
  25. int b = 20;
  26.     // 1、值传递
  27.     swap01(a,b);
  28.     cout << "运行swap01后外部的a=" << a << endl;
  29. cout << "运行swap01后外部的b=" << b << endl;
  30.     // 2、地址传递
  31.     swap02(&a,&b);
  32.     cout << "运行swap02后外部的a=" << a << endl;
  33. cout << "运行swap02后外部的b=" << b << endl;
  34.     return 0;
  35. }

原因:地址传递是直接改了地址,地址交换了,里面存储的数据自然也就交换了。

3、指针配合函数、数组的案例:

案例:封装一个函数,利用冒泡排序,实现对整型数组的升序排序。

例如一个数组:int arr[10] = {4,3,6,9,1,2,10,8,7,5};

  1. #include <iostream>
  2. using namespace std;
  3. // 冒泡排序函数:参数1:数组地址,参数2:数组长度
  4. void bubble(int *arr,int len)
  5. {
  6.     for(int i=0;i<len-1;i++)
  7.     {
  8.         for(int j=0;j<len-i-1;j++)
  9.         {
  10.             if(arr[j]>arr[j+1])
  11.             {
  12.                 int temp = arr[j];
  13.                 arr[j] = arr[j+1];
  14.                 arr[j+1] = temp;
  15.             }
  16.         }
  17.     }
  18. }
  19. // 打印数组的函数:
  20. void printarr(int *arr,int len)
  21. {
  22.     for(int i=0;i<len;i++)
  23.     {
  24.         cout << arr[i] << endl;
  25.     }
  26. }
  27. int main()
  28. {
  29.     int arr[10] = {4,3,6,9,1,2,10,8,7,5};
  30. int len = sizeof(arr)/sizeof(arr[0]);
  31.      // 一般来说,需要传入数组、数组的长度。
  32. bubble(arr,len);
  33.     printarr(arr,len);
  34.     return 0;
  35. }

核心:

如何把一个数组传入一个函数中?——用指针接收首地址;

熟练运用冒泡排序;

在函数中使用数组,最好还要传入它的长度。

八、结构体

结构体属于用户自定义的数据类型,允许用户储存不同的数据类型。

整型、字符型等,这些数据类型都属于内置的数据类型。

如果要写一个动物的数据类型?——结构体可以实现。

1、结构体的定义和使用

定义结构体:struct 结构体名 {结构体成员列表};

使用结构体的三种方式:

1、struct 结构体名 变量名

2、struct 结构体名 变量名 = {成员1值,成员2值...}

3、定义结构体时顺便创建变量

  1. #include <iostream>
  2. using namespace std;
  3. #include <string>
  4. // 创建学生数据类型,学生包括:姓名、年龄、分数
  5. // 自定义数据类型就是一些内置数据类型的集合。
  6. struct Student
  7. {  
  8.     // 成员列表:姓名、年龄、分数
  9.     string name;
  10.     int age;
  11.     int score;
  12. }s3; // 方法三:定义结构体的时候顺便创建变量
  13. int main()
  14. {  
  15.     // 方法一:struct 结构体名 变量名
  16.     struct Student s1;
  17.     // 给s1属性赋值,通过.访问结构体变量中的属性
  18.     s1.name = "张三";
  19.     s1.age = 18;
  20.     s1.score = 100;
  21.     cout << "姓名:" << s1.name << endl << "年龄:" << s1.age << endl << "分数:" << s1.score << endl;
  22.     // 方法二:struct 结构体名 变量名 = {值1,值2...};注意按顺序
  23.     struct Student s2 = {"李四",19,80};
  24. cout << "姓名:" << s2.name << endl << "年龄:" << s2.age << endl << "分数:" << s2.score << endl;
  25.     // 方法三:定义结构体的时候顺便创建变量
  26.     s3.name = "王五";
  27.     s3.age = 20;
  28.     s3.score = 90;
  29. cout << "姓名:" << s3.name << endl << "年龄:" << s3.age << endl << "分数:" << s3.score << endl;
  30.     return 0;
  31. }

一般来说用第一种、第二种比较多,第三种少一点。

定义的时候struct关键字不可以省略,创建的时候可以省略。

利用.访问它的成员。

2、结构体数组

struct 结构体名 数组名[元素个数] = {{},{},...{}}

  1. #include <iostream>
  2. using namespace std;
  3. #include <string>
  4. // 1、定义学生结构体,包括:姓名、年龄、分数
  5. struct Student
  6. {  
  7.     string name;
  8.     int age;
  9.     int score;
  10. };
  11. int main()
  12. {  
  13.     // 2、创建结构体数组,给结构体数组中的元素赋值
  14. struct Student stu_arr[3] = {{"张三",18,100},{"李四",19,80},{"王五",20,90}};
  15.     // 3、修改结构体数组中的元素值
  16. stu_arr[2].name = "尼古拉斯·赵四";
  17.     // 4、遍历结构体数组并输出
  18.     for(int i=0;i<3;i++)
  19.     {
  20.         cout << "姓名:" << stu_arr[i].name << endl;
  21.         cout << "年龄:" << stu_arr[i].age << endl;
  22.         cout << "分数:" << stu_arr[i].score << endl;
  23.     }
  24.     return 0;
  25. }

3、结构体指针

  1. #include <iostream>
  2. using namespace std;
  3. #include <string>
  4. // 1、定义学生结构体,包括:姓名、年龄、分数。
  5. struct Student
  6. {  
  7.     string name;
  8.     int age;
  9.     int score;
  10. };
  11. int main()
  12. {  
  13.     // 2、创建学生结构体变量。
  14. struct Student s = {"张三",18,100};
  15. // 3、通过指针指向结构体变量。
  16.     struct Student* p = &s;
  17.    
  18.     // 4、通过指针访问结构体变量数据,需要利用符号->,也可以用(*p).访问。
  19.     cout << "姓名:" << p->name << endl << "年龄:" << p->age << endl << "分数:" << p->score << endl;
  20.     return 0;
  21. }

4、结构体嵌套结构体

结构体中的成员可以是另一个结构体,如老师辅导学员,一个老师的结构体中记录一个学生的结构体。

  1. #include <iostream>
  2. using namespace std;
  3. #include <string>
  4. // 定义学生结构体(要先于老师),包括:姓名、年龄、分数
  5. struct Student
  6. {  
  7.     string name;
  8.     int age;
  9.     int score;
  10. };
  11. // 定义老师结构体:工号、姓名、年龄、学生结构体
  12. struct Teacher
  13. {
  14.     int id;
  15.     string name;
  16.     int age;
  17.     struct Student stu;    
  18. };
  19. int main()
  20. {  
  21.     struct Teacher tea;
  22.     tea.id = 1010;
  23.     tea.name = "孙老师";
  24. tea.age = 32;
  25.     tea.stu.name = "张三";
  26.     tea.stu.age = 18;
  27.     tea.stu.score = 100;
  28.     cout << "老师工号:" << tea.id << endl << "老师姓名:" << tea.name << endl << "老师年龄" << tea.age << endl << "老师带的学生:" << tea.stu.name << endl << "学生年龄:" << tea.stu.age << endl << "学生分数:" << tea.stu.score << endl;
  29.     return 0;
  30. }

5、结构体做函数参数

将结构体作为参数向函数中传递,传递方式有两种:值传递和地址传递。

  1. #include <iostream>
  2. using namespace std;
  3. #include <string>
  4. // 定义学生结构体,包括:姓名、年龄、分数
  5. struct Student
  6. {  
  7.     string name;
  8.     int age;
  9.     int score;
  10. };
  11. // 1、值传递
  12. void print01(struct Student s1)
  13. {  
  14.     s1.age = 20;
  15.     cout << "值传递中打印的s1信息为:" << endl << "姓名:" << s1.name << endl << "年龄:" << s1.age << endl << "分数:" << s1.score << endl;
  16. }
  17. // 2、地址传递
  18. void print02(struct Student * p)
  19. {
  20.     p->age = 20;
  21.     cout << "地址传递中打印的s2信息为:" << endl << "姓名:" << p->name << endl << "年龄:" << p->age << endl << "分数:" << p->score << endl;
  22. }
  23. int main()
  24. {  
  25.     struct Student s1;
  26.     s1.name = "张三";
  27.     s1.age = 18;
  28. s1.score = 100;
  29.     print01(s1);
  30. cout << "值传递后打印的s1信息为:" << endl << "姓名:" << s1.name << endl << "年龄:" << s1.age << endl << "分数:" << s1.score << endl;
  31.     struct Student s2;
  32.     s2.name = "李四";
  33.     s2.age = 19;
  34. s2.score = 80;
  35.     print02(&s2);
  36. cout << "地址传递后打印的s2信息为:" << endl << "姓名:" << s2.name << endl << "年龄:" << s2.age << endl << "分数:" << s2.score << endl;
  37.     return 0;
  38. }

 地址传递会真正改变实参,值传递不会。

6、结构体中的const使用场景

用const来防止误操作。

  1. #include <iostream>
  2. using namespace std;
  3. #include <string>
  4. struct Student
  5. {  
  6.     string name;
  7.     int age;
  8.     int score;
  9. };
  10. // 打印函数。
  11. // 如果用值传递,当数据量过大时,值传递要拷贝的数据就很多了,为了节省空间,通常会用地址传递(指针),指针只占4个字节,而且还不会多余复制一份数据副本。
  12. void print(const struct Student *p)
  13. {  
  14. // 在这种地址传递的函数中,有可能会误更改数据比如:p->age=20;这样就会修改全局变量,为了防止这种情况发生,就会在前面加上const。
  15.     cout << "姓名:" << p->name << endl << "年龄:" << p->age << endl << "分数:" << p->score << endl;
  16. }
  17. int main()
  18. {  
  19.     struct Student s = {"张三",18,100};
  20. print(&s);
  21.     return 0;
  22. }

7、结构体案例

案例1:每名老师带5个学生,共有3名老师。设计学生和老师结构体,其中在老师结构体中,有姓名和一个存放5名学生的数组。学生结构体有姓名、考试分数。

创建数组存放3名老师,通过函数给每个老师及学生赋值,最终打印出所有数据。

  1. #include <iostream>
  2. using namespace std;
  3. #include <string>
  4. #include <Ctime>
  5. struct Student
  6. {
  7.     string name;
  8.     int score;
  9. };
  10. struct Teacher
  11. {
  12.     string name;
  13.     struct Student stu_arr[5];
  14. };
  15. // 给老师和学生赋值的函数,函数接收数组有两种方法:一种是指针,一种是下面这种
  16. void assignment(struct Teacher tea_arr[],int len)
  17. {
  18.     // 给老师赋值
  19.     string name_tealist = "ABC";
  20.     for(int i=0;i<len;i++)
  21.     {  
  22.         // 做一个拼接字符串的操作:
  23.         tea_arr[i].name = "teacher_";
  24.         tea_arr[i].name += name_tealist[i];
  25.         // 给每名老师带的学生赋值
  26.         for(int j=0;j<5;j++)
  27.         {  
  28.             // 学生姓名
  29.             string name_stulist = "ABCDE";
  30.             tea_arr[i].stu_arr[j].name = "student_";
  31.             tea_arr[i].stu_arr[j].name += name_stulist[j];
  32.             // 学生成绩,随机数,后面的51表示0-50之间的一个数。
  33.             int random = rand()%51 +50;
  34.             tea_arr[i].stu_arr[j].score = random;
  35.         }
  36.     }
  37. }
  38. void print(struct Teacher tea_arr[],int len)
  39. {
  40.     for(int i=0;i<len;i++)
  41.     {
  42.         cout << "老师姓名:" << tea_arr[i].name << endl;
  43.         for(int j=0;j<5;j++)
  44.         {
  45.             cout << "所带学生姓名:" << tea_arr[i].stu_arr[j].name << ",分数:" << tea_arr[i].stu_arr[j].score << endl;
  46.         }
  47.     }
  48. }
  49. int main()
  50. {    
  51.     // 随机数种子
  52. srand((unsigned inttime(NULL));
  53.     // 1、创建3名老师的数组
  54. struct Teacher tea_arr[3];
  55.     ///2、通过函数给3名老师赋值,并给老师带的学生赋值
  56.     int len = sizeof(tea_arr)/sizeof(tea_arr[0]);
  57. assignment(tea_arr,len);
  58.     // 3、打印输出所有的老师及学生信息
  59. print(tea_arr,len);
  60.     return 0;
  61. }

案例2:设计一个英雄的结构体,包括:姓名、年龄、性别。

创建结构体数组,数组中存放5名英雄(自己定义)。

通过冒泡排序算法,将数组中的英雄按照年龄进行升序排序,并打印结果。

  1. #include <iostream>
  2. using namespace std;
  3. #include <string>
  4. struct Hero
  5. {
  6.     string name;
  7.     int age;
  8.     string gender;
  9. };
  10. void bubble(struct Hero hero[],int len)
  11. {
  12.     for(int i=0;i<len-1;i++)
  13.     {
  14.         for(int j=0;j<len-i-1;j++)
  15.         {
  16.             if(hero[j].age > hero[j+1].age)
  17.             {
  18.                 struct Hero temp = hero[j];
  19.                 hero[j] = hero[j+1];
  20.                 hero[j+1] = temp;
  21.             }
  22.         }
  23.     }
  24. }
  25. void print(struct Hero hero[],int len)
  26. {
  27.     for(int s=0;s<len;s++)
  28.     {
  29.         cout << "姓名:" << hero[s].name << ",年龄:" << hero[s].age << ",性别:" << hero[s].gender << endl;
  30.     }
  31. }
  32. int main()
  33. {    
  34.     struct Hero hero[5] = {{"刘备",23,"男"},{"关羽",22,"男"},{"张飞",20,"男"},{"赵云",21,"男"},{"貂蝉",19,"女"}};
  35.     int len = sizeof(hero)/sizeof(hero[0]);
  36.     bubble(hero,len);
  37.     print(hero,len);
  38.     return 0;
  39. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/673064
推荐阅读
相关标签
  

闽ICP备14008679号