C++入门详细笔记(共八章)(下)

简介: C++入门详细笔记(共八章)

第五章 数组array


5.1 概述


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


特点1:数组中每个元素都是相同的数据类型


特点2:数组是由连续的内存位置组成的


5.2 一维数组


5.2.1 一维数组定义方式


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


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


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


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


总结1:数组名的命名规范与变量名命名规范一致,不要和变量重名


总结2:数组中下标是从0开始索引


例1:第一种方式


#include <iostream>
using namespace std;
int main()
{
  int arr[5];
  arr[0] = 0;
  arr[1] = 1;
  arr[2] = 2;
  arr[3] = 3;
  arr[4] = 4;
  // 访问数组中元素
  cout << arr[0] << endl;
  cout << arr[1] << endl;
  cout << arr[2] << endl;
  cout << arr[3] << endl;
  cout << arr[4] << endl;
  system("pause");
  return 0;
}


0
1
2
3
4
请按任意键继续. . .


例2:第二种方式


#include <iostream>
using namespace std;
int main()
{
  int arr[5] = { 0,1,2,3,4 };
  // 访问数组中元素
  cout << arr[0] << endl;
  cout << arr[1] << endl;
  cout << arr[2] << endl;
  cout << arr[3] << endl;
  cout << arr[4] << endl;
  system("pause");
  return 0;
}


输出结果一样


注意:如果初始化数据的时候,没有全部填写完,会用0来填补剩余的数据


int arr[5] = { 0,1 };


例3:第三种方式


#include <iostream>
using namespace std;
int main()
{
  int arr[] = { 0,1,2,3,4,5,6 };
  for (int i = 0; i < 7; i++)
  {
    // 访问数组中元素
    cout << arr[i] << endl;
  }
  system("pause");
  return 0;
}


0
1
2
3
4
5
6
请按任意键继续. . .


5.2.2 一维数组数组名


一维数组名称的用途


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


  1. 可以获取数组在内存中的首地址


#include <iostream>
using namespace std;
int main()
{
  int arr[] = { 0,1,2,3,4,5,6 };
  cout << "整个数组占用的内存空间:"<<sizeof(arr) << endl;
  cout << "每个元素占用的内存空间:" << sizeof(arr[0]) << endl;
  cout << "元素个数:" << sizeof(arr) / sizeof(arr[0]) << endl;  // 统计元素个数
  cout << "数组首地址:" << (int)arr << endl;                    //(int)强制转化为十进制
  cout << "数组中第一个元素地址:" << (int)&arr[0] << endl;
  cout << "数组中第二个元素地址:" << (int)&arr[1] << endl;
  system("pause");
  return 0;
}


整个数组占用的内存空间:28
每个元素占用的内存空间:4
元素个数:7
数组首地址:-1155598808
数组中第一个元素地址:-1155598808
数组中第二个元素地址:-1155598804
请按任意键继续. . .


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


错误示例:


arr = 100


注意:数组名是常量,不可以赋值


总结1:直接打印数组名,可以查看数组所占内存的首地址


总结2:对数组名进行sizeof,可以获取整个数组占内存空间的大小


练习案例1:五只小猪称体重


案例描述:


在一个数组中记录了五只小猪的体重,如: int arr[5] = {300, 350, 200, 400, 250};


找出并打印最重的小猪体重


#include <iostream>
using namespace std;
int main()
{
  int arr[5] = { 300, 350, 200, 400, 250 };
  int max = 0;
  for (int i = 0; i < 5; i++)
  {
    if (arr[i] > max)
    {
      max = arr[i];
    }
  }
  cout << "max=" << max << endl;
  system("pause");
  return 0;
}


max=400
请按任意键继续. . .


练习案例2:数组元素逆置


案例描述:请申明一个5个元素的数组,并且将元素逆置


(如原数组元素为:1,3,2,5,4;逆置结果为:4,5,2,3,1)


#include <iostream>
using namespace std;
int main()
{
  int arr[5] = { 1, 3, 2, 5, 4 };
  cout << "逆置前:" << endl;
  for (int i = 0; i < 5; i++)
  {
    cout << arr[i];
  }
  cout << endl;
  for (int i = 0; i < 5; i++) {
    int start = 0;
    int end = sizeof(arr) / sizeof(arr[0]) - 1;
    while (start < end)
    {
      int temp = arr[start];
      arr[start] = arr[end];
      arr[end] = temp;
      start++;
      end--;
    }
  }
  cout << "逆置后:" << endl;
  for (int i = 0; i < 5; i++)
  {
    cout << arr[i];
  }
  cout << endl;
  system("pause");
  return 0;
}


逆置前:
13254
逆置后:
45231
请按任意键继续. . .


例2


#include <iostream>
using namespace std;
int main()
{
  int arr[5] = { 1, 3, 2, 5, 4 };
  int arr1[5];
  int j = 0;
  for (int i = 0; i < 5; i++)
  {
    cout << arr[i];
    j = 4 - i;
    arr1[j] = arr[i];
  }
  cout << endl;
  for (int j = 0; j < 5; j++)
  {
    cout << arr1[j];
  }
  cout << endl;
  system("pause");
  return 0;
}


能实现一样的倒置功能


5.2.3 冒泡排序


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


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


  1. 对每一对相邻元素做相同的工作,执行完毕后,找到第一个最大值。


  1. 重复以上的步骤,每次比较次数-1,知道不需要比较


排序总轮数 = 元素个数 - 1


每轮对比次数 = 元素个数 - 排序轮数 - 1


从第0轮开始


大的数字在最后面冒出来



#include <iostream>
using namespace std;
int main()
{
  int arr[9] = { 4,2,8,0,5,7,1,3,9 };
  cout << "排序前:" << endl;
  for (int i = 0; i < 9; i++)
  {
    cout << arr[i] << " ";
  }
  cout << endl;
  //开始冒泡排序
  //总共排序轮数为 元素个数 - 1
  for (int i = 0; i < 9 - 1; i++)
  {
    //内层循环对比   次数 = 元素个数 - 当前轮数 - 1
    for (int j = 0; j < 9 - i - 1; j++)
    {
      //如果第一个数字,比第二个数字大,交换两个数字
      if (arr[j] > arr[j + 1])
      {
        int temp = arr[j];         //这三行代码实现这两数的交换
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
  //排序后结果
  cout << "排序后:" << endl;
  for (int i = 0; i < 9; i++)
  {
    cout << arr[i] << " ";
  }
  cout << endl;
  system("pause");
  return 0;
}


排序前:
4 2 8 0 5 7 1 3 9
排序后:
0 1 2 3 4 5 7 8 9
请按任意键继续. . .


5.3 二维数组


二维数组就是在一维数组上,多加了一个维度


5.3.1 二维数组的定义方式


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


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


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


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


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


例1:第一种定义


#include <iostream>
using namespace std;
int main()
{
  int arr[2][2];
  arr[0][0] = 0;
  arr[0][1] = 1;
  arr[1][0] = 2;
  arr[1][1] = 3;
  cout << arr[0][0] << endl;
  cout << arr[0][1] << endl;
  cout << arr[1][0] << endl;
  cout << arr[1][1] << endl;
  system("pause");
  return 0;
}


0
1
2
3
请按任意键继续. . .


例2:第二种定义


#include <iostream>
using namespace std;
int main()
{
  int arr[2][2] = { {1,2},{3,4} };
  cout << arr[0][0] << endl;
  cout << arr[0][1] << endl;
  cout << arr[1][0] << endl;
  cout << arr[1][1] << endl;
  system("pause");
  return 0;
}


例3:for嵌套输出二维数组


#include <iostream>
using namespace std;
int main()
{
  int arr[2][3] = { {1,2,3},{4,5,6} };
  //外层循环打印行数
  //内层循环打印列数
  for (int i = 0; i < 2; i++)
  {
    for (int j = 0; j < 3; j++)
    {
      cout << arr[i][j] << " ";
    }
    cout << endl;
  }
  system("pause");
  return 0;
}


1 2 3
4 5 6
请按任意键继续. . .


5.3.2 二维数组的数组组名


  • 查看二维数组所占用内存空间


  • 获取二维数组首地址


例1:


#include <iostream>
using namespace std;
int main()
{
  int arr[2][3] = { {1,2,3},{4,5,6} };
  cout << "int类型二维数组占用的内存空间大小:" << sizeof(arr) << endl;
  double arr1[2][3] = { {1,2,3},{4,5,6} };
  cout << "double类型二维数组占用的内存空间大小:" << sizeof(arr1) << endl;
  system("pause");
  return 0;
}


int类型二维数组占用的内存空间大小:24
double类型二维数组占用的内存空间大小:48
请按任意键继续. . .


例2


#include <iostream>
using namespace std;
int main()
{
  int arr[2][3] = { {1,2,3},{4,5,6} };
  cout << "二维数组占用的内存空间大小:" << sizeof(arr) << endl;
  cout << "二维数组第一行占用的内存空间大小:" << sizeof(arr[0]) << endl;
  cout << "二维数组第一个数据占用的内存空间大小:" << sizeof(arr[0][0]) << endl;
  cout << "二维数组多少个数据:" << sizeof(arr) / sizeof(arr[0][0]) << endl;
  cout << "二维数组行数:" << sizeof(arr) / sizeof(arr[0]) << endl;
  cout << "二维数组列数:" << sizeof(arr[0]) / sizeof(arr[0][0]) << endl;
  cout << "十六进制二维数组首地址" << arr << endl;
  cout << "十进制二维数组首地址" << (int)arr << endl;
  cout << "二维数组第一行首地址" << (int)arr[0] << endl;
  cout << "二维数组第二行首地址" << (int)arr[1] << endl;  //相差12,隔着三个数据
  cout << "二维数组第一个元素首地址" << (int)&arr[0][0] << endl;
  cout << "二维数组第二个元素首地址" << (int)&arr[0][1] << endl;
  system("pause");
  return 0;
}


二维数组占用的内存空间大小:24
二维数组第一行占用的内存空间大小:12
二维数组第一个数据占用的内存空间大小:4
二维数组多少个数据:6
二维数组行数:2
二维数组列数:3
十六进制二维数组首地址000000367812F768
十进制二维数组首地址2014508904
二维数组第一行首地址2014508904
二维数组第二行首地址2014508916
二维数组第一个元素首地址2014508904
二维数组第二个元素首地址2014508908
请按任意键继续. . .


总结1:二维数组名就是这个数组的首地址


总结2:对二维数组名进行sizeof时,可以获取整个二维数组占用的内存空间大小


5.3.3 二维数组应用案例


考试成绩统计:


案例描述:有三名同学(张三,李四,王五),在一次考试中的成绩分别如下表,请分别输出三名同学的总成绩



#include <iostream>
using namespace std;
int main()
{
  int scores[3][3] = 
  { 
    {100,100,100},
    {90,50,100},
    {60,70,80}
  };
  string names[3] = { "张三", "李四", "王五" };
  for (int i = 0; i < 3; i++)
  {
    int num = 0;
    for (int j = 0; j < 3; j++)
    {
      num += scores[i][j];
    }
    cout << names[i] << "的总分为:" << num << endl;
  }
  system("pause");
  return 0;
}


张三的总分为:300
李四的总分为:240
王五的总分为:210
请按任意键继续. . .


第六章 函数


6.1 概述


作用:将一段经常使用的代码封装起来,减少重复代码


一个较大的程序,一般分为若干个程序块,每个程序实现特定的功能。


6.2 函数的定义


函数的定义一般主要有5个步骤:


1、返回值类型


2、函数名


3、参数列表


4、函数体语句


5、return表达式


语法:


返回值类型 函数名 (参数列表)
{
    函数体语句
    return表达式
}


  • 返回值类型 :一个函数可以返回一个值。在函数定义中


  • 函数名:给函数起个名称


  • 参数列表:使用该函数时,传入的数据


  • 函数体语句:花括号内的代码,函数内需要执行的语句


  • return表达式: 和返回值类型挂钩,函数执行完后,返回相应的数据


例1:定义加法函数



int add(int num1, int num2)
{
  int sum = num1 + num2;
  return sum;
}


6.3 函数的调用


功能:使用定义好的函数


语法:函数名 (参数)


例1:调用add函数


#include <iostream>
using namespace std;
int add(int num1, int num2)   //形参
{
  int sum = num1 + num2;
  return sum;
}
int main()
{
  //main函数中调用add函数
  int c = add(10, 20);    //实参
  cout << c << endl;
  system("pause");
  return 0;
}


30
请按任意键继续. . .


6.4值传递


  • 所谓值传递,就是函数调用时实参将数值传递给了形参


  • 值传递时,如果形参发生改变,并不会影响实参


例1:实现两个值交换的函数


#include <iostream>
using namespace std;
//值传递
//定义函数,实现两个数字进行交换函数
//如果函数不需要返回值,声明可以写void类型
void swap(int num1, int num2)
{
  cout << "交换前:num1=" << num1 << ", num2=" << num2 << endl;
  int temp = num1;
  num1 = num2;
  num2 = temp; 
  cout << "交换后:num1=" << num1 << ", num2=" << num2 << endl;
  return;
}
int main()
{
  int a = 10;
  int b = 20;
  cout << "交换前:a=" << a << ", b=" << b << endl;
  swap(a, b);
  cout << "交换后:a=" << a << ", b=" << b << endl;
  system("pause");
  return 0;
}


交换前:a=10, b=20
交换前:num1=10, num2=20
交换后:num1=20, num2=10
交换后:a=10, b=20
请按任意键继续. . .


6.5 函数的常见样式


常见的函数样式有4种:


1.无参无返


2.有参无返


3.无参有返


4.有参有返


例1:第一种,无参无返


#include <iostream>
using namespace std;
void test01()
{
  cout << "Hello world!" << endl;
}
int main()
{
  test01();
  system("pause");
  return 0;
}


Hello world!
请按任意键继续. . .


例2:第二种,有参无返


#include <iostream>
using namespace std;
void test02(int a)
{
  cout << "a=" << a << endl;
}
int main()
{
  int a;
  cout << "请输入a:" << endl;
  cin >> a;
  test02(a);
  system("pause");
  return 0;
}


请输入a:
5
a=5
请按任意键继续. . .


例三:第三种,无参有返


#include <iostream>
using namespace std;
int test03()
{
  cout << "This is test03." << endl;
  return 1000;
}
int main()
{
  int num1 = test03();
  cout << "num1=" << num1 << endl;
  system("pause");
  return 0;
}


This is test03.
num1=1000
请按任意键继续. . .


例四:第四种,有参有返


#include <iostream>
using namespace std;
int test04(int a)
{
  cout << "This is test04." << endl;
  return a;
}
int main()
{
  int num2 = test04(1000);
  cout << "num2=" << num2 << endl;
  system("pause");
  return 0;
}


This is test04.
num2=1000
请按任意键继续. . .


6.6 函数的声明


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


  • 函数的声明可以多次,但是函数的定义只能有一次


#include <iostream>
using namespace std;
int max(int a, int b);   //函数声明 ,定义的函数就可以写在主函数后面了
int main()
{
  cout << max(10, 20) << endl;
  system("pause");
  return 0;
}
//函数的声明
//比较函数,实现两个整型数字的比较,返回较大的值
int max(int a, int b)
{
  return a > b ? a : b;
}


20
请按任意键继续. . .


6.7 函数的分文件编写


作用:让代码结构更加清晰


函数份文件编写一般有4个步骤


  1. 创建后缀名.h的头文件


  1. 创建后缀名cpp的源文件


  1. 在头文件中写函数的声明


  1. 在源文件中写函数的定义


例1:实现两个数的交换,这例使用分文件编写


1、 swap.h头文件


#include <iostream>
using namespace std;
//函数声明
void swap(int num1, int num2); 


2、swap.cpp源文件


#include "swap.h"
void swap(int num1, int num2)
{
  cout << "交换前:num1=" << num1 << ", num2=" << num2 << endl;
  int temp = num1;
  num1 = num2;
  num2 = temp;
  cout << "交换后:num1=" << num1 << ", num2=" << num2 << endl;
  return;
}


3、first_temp.cpp源文件(主文件)


#include <iostream>
using namespace std;
#include "swap.h"
int main()
{
  swap(10, 20);
  system("pause");
  return 0;
}




第七章 指针


7.1 指针的基本概念


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


  • 内存编码是从0开始记录的,一般用十六进制数字表示


  • 可以利用指针变量保存地址


7.2 指针变量的定义和使用


指针变量定义语法:数据类型 * 变量名



#include <iostream>
using namespace std;
int main()
{
  //1、定义指针
  int a = 10;
  //指针定义的语法:数据类型 * 指针变量
  int* p;
  //让指针记录变量a的地址
  p = &a;
  cout << "a的地址为:" << &a << endl;
  cout << "指针p为:" << p << endl;     //其实指针就是地址
  //2、使用指针
  //可以通过解引用的方式来找到指针指向的内存
  //指针前加 * 代表解引用,找到指针指向的内存数据
  *p = 1000;
  cout << "a=" << a << endl;
  cout << "*p=" << *p << endl;
  //不改变地址,只改变了地址存的数据
  cout << "a的地址为:" << &a << endl;
  cout << "指针p为:" << p << endl;     
  system("pause");
  return 0;
}


a的地址为:0000006FE5EFF9F4
指针p为:0000006FE5EFF9F4
a=1000
*p=1000
a的地址为:0000006FE5EFF9F4
指针p为:0000006FE5EFF9F4
请按任意键继续. . .


总结1: 我们可以通过 & 符号 获取变量的地址


总结2:利用指针可以记录地址


总结3:对指针变量解引用,可以操作指针指向的内存


7.3 指针所占内存空间


提问:指针也是种数据类型,那么这种数据类型占用多少内存空间?


  • 在32位操作系统下占用4个字节空间


  • 在64位操作系统下占用8个字节空间


#include <iostream>
using namespace std;
int main()
{
  int a = 10;
  //int* p;
  //p = &a;
  int* p = &a;
  cout << "sizeof(p) =" << sizeof(p) << endl;
  cout << "sizeof (int*) =" << sizeof (int*)  << endl;
  cout << "sizeof (double*) =" << sizeof(double*) << endl;
  cout << "sizeof (char*) =" << sizeof(char*) << endl;
  system("pause");
  return 0;
}


sizeof(p) =8
sizeof (int*) =8
sizeof (double*) =8
sizeof (char*) =8
请按任意键继续. . .


7.4 空指针和野指针


空指针


空指针:指针变量指向内存中编号为0的空间


用途:初始化指针变量


注意:空指针指向的内存是不可以访问的


#include <iostream>
using namespace std;
int main()
{
  //空指针
  //1、空指针用于给指针变量进行初始化
  int* p = NULL;
  //2、空指针是不可以进行访问的
  //0~255之间的内存编号是系统占用的,因此不可以访问
  //*p = 100;    //错误
  system("pause");
  return 0;
}


野指针


以下代码会报错


#include <iostream>
using namespace std;
int main()
{
  //野指针
  //在程序中,尽量避免出现野指针
  int* p = (int*)0x1100;
  cout << *p << endl;
  system("pause");
  return 0;
}


注意:空指针和野指针都不是我们申请的空间,因此不要访问。


7.5 const修饰指针


const修饰指针有三种情况:


  1. const修饰指针 —常量指针


  1. const修饰常量 —指针常量


  1. const即修饰指针,又修饰常量


第一种:常量指针,相当于int* p是常数


const int* p = &a


特点:指针的指向可以修改,但是指针指向的值不可以修改


*p = 20;   //错误
p = &b;    //正确



例1:


#include <iostream>
using namespace std;
int main()
{
  int a = 10;
  int b = 100;
  const int* p = &a;
  cout << "p指向a的地址时:" << endl;
  cout << "p:" << p << endl;
  cout << "*p:" << *p << endl;
  //*p = 20;    //错误
  p = &b;       //正确
  cout << "p指向b的地址时:" << endl;
  cout << "p:" << p << endl;
  cout << "*p:" << *p << "\n" << endl;
  cout << "a:" << a << endl;
  cout << "a的地址:" << &a << endl;
  cout << "b:" << b << endl;
  cout << "b的地址:" << &b << endl;
  system("pause");
  return 0;
}


p指向a的地址时:
p:007AFE44
*p:10
p指向b的地址时:
p:007AFE38
*p:100
a:10
a的地址:007AFE44
b:100
b的地址:007AFE38
请按任意键继续. . .


第二种:指针常量,相当于p(地址)是常数


int* const p = &a


特点:指针的指向不可以改,指针指向的值可以改


*p = 20;   //正确
p = &b;    //错误



例2:


#include <iostream>
using namespace std;
int main()
{
  int a = 10;
  int b = 10;
  int* const p = &a;
  *p = 20;        //正确
  //p = &b;       //错误
  system("pause");
  return 0;
}


第三种:即修饰指针又修饰常量


const int* const p = &a;


特点:指针的指向和指针指向的值都不可以修改


*p = 20;   //错误
p = &b;    //错误



7.6 指针和数组


作用:利用指针访问数组中元素


例:利用指针遍历数组


#include <iostream>
using namespace std;
int main()
{
  //指针和数组
  //利用指针访问数组中的元素
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  cout << "第一个元素为:" << arr[0] << endl;
  int* p = arr;   //arr就是数组的首地址
  cout << "利用指针来访问第一个元素:" << *p << endl;
  p++;   //向后偏移四个字节
  cout << "利用指针来访问第二个元素:" << *p << endl;
  cout << "利用指针遍历数组:" << endl;
  int* p2 = arr;
  for (int i = 0; i < 10; i++)
  {
    cout << *p2 << " ";
    p2++;
  }
  cout << endl;
  system("pause");
  return 0;
}


第一个元素为:1
利用指针来访问第一个元素:1
利用指针来访问第二个元素:2
利用指针遍历数组:
1 2 3 4 5 6 7 8 9 10
请按任意键继续. . .


7.7 指针和函数


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


p是存地址


*p是存数值


#include <iostream>
using namespace std;
void swap02(int* p1, int* p2)    //两个形参为地址
{
  int temp = *p1;              //里面交换地址存储的值
  *p1 = *p2;
  *p2 = temp;
}
int main()
{
  int a = 10;
  int b = 20;
  cout << "传递前:" << endl;
  cout << "a=" << a << endl;
  cout << "b=" << b << endl;
  //地址传递
  swap02(&a, &b);
  cout << "传递后:" << endl;
  cout << "a=" << a << endl;
  cout << "b=" << b << endl;
  system("pause");
  return 0;
}


传递前:
a=10
b=20
传递后:
a=20
b=10
请按任意键继续. . .


7.8 指针、数组、函数


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


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


#include <iostream>
using namespace std;
void bubbleSort(int* arr, int len)    //第一个形参:地址  第二个形参:长度
{
  for (int i = 0; i < len - 1; i++)
  {
    for (int j = 0; j < len - i - 1; j++)
    {
      //如果j>j+1的值,交换数字
      if (arr[j] > arr[j + 1])
      {
        int temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
}
//打印数组
void printArray(int* arr, int len)
{
  for (int i = 0; i < len; i++)
  {
    cout << arr[i] << " ";
  }
  cout << endl;
}
int main()
{
  //1、创建一个数组
  int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };
  int len = sizeof(arr) / sizeof(arr[0]);
  //2、创建函数,实现冒泡排序
  bubbleSort(arr, len);
  //3、打印排序后的数组
  printArray(arr, len);
  system("pause");
  return 0;
}


1 2 3 4 5 6 7 8 9 10
请按任意键继续. . .


第八章 结构体


8.1 结构体基本概念


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


8.2 结构体定义和使用


语法:


struct 结构体名
{ 
       结构体成员列表
}


通过结构体创建变量的方式有三种:


  • struct 结构体名 变量名


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


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


#include <iostream>
using namespace std;
#include <string>
//1、创建学生数据类型:学生包括(姓名,年龄,分数)
//自定义数据类型,一些类型集合组成的一个类型
//语法:struct 类型名称  {成员列表}
struct Student
{
  //成员列表
  //姓名
  string name;
  //年龄
  int age;
  //考试分数
  int score;
}s3;  //顺便创建结构体变量
int main()
{
  //2、通过学生类型创建具体学生
  // 2.1 struct Student s1;
  //struct关键字可以省略
  //Student s1;
  struct Student s1;
  //给s1属性赋值,通过.访问结构体变量中的属性
  s1.name = "张三";
  s1.age = 18;
  s1.score = 100;
  cout << "姓名:" << s1.name << ", 年龄:" << s1.age << ", 分数:" << s1.score << endl;
  // 2.2 struct Student s2 = {...}
  struct Student s2 = { "李四", 19, 80 };
  cout << "姓名:" << s2.name << ", 年龄:" << s2.age << ", 分数:" << s2.score << endl;
  // 2.3 在定义结构体时顺便创建结构体的变量
  s3.name = "王五";
  s3.age = 20;
  s3.score = 60;
  cout << "姓名:" << s3.name << ", 年龄:" << s3.age << ", 分数:" << s3.score << endl;
  system("pause");
  return 0;
}


姓名:张三, 年龄:18, 分数:100
姓名:李四, 年龄:19, 分数:80
姓名:王五, 年龄:20, 分数:60
请按任意键继续. . .


  • 总结1:定义结构体时的关键字是struct,不可省略


  • 总结2:创建结构体变量时,关键字struct可以省略


  • 总结3:结构体变量利用操作符 ‘’.‘’ 访问成员


8.3 结构体数组


作用:将自定义的结构体放入到数组中方便维护


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


#include <iostream>
using namespace std;
#include <string>
//结构体数组
//1、定义结构体
struct Student
{
  //姓名
  string name;
  //年龄
  int age;
  //分数
  int score;
};
int main()
{
  //2、创建结构体数组
  struct Student stuArray[3] =
  {
    {"张三", 18, 100},
    {"李四", 28, 99},
    {"王五",38, 66}
  };
  //3、给结构体数组中的元素赋值
  stuArray[2].name = "赵六";
  //4、遍历结构体数组
  for (int i = 0; i < 3; i++)
  {
    cout << "姓名:" << stuArray[i].name 
      << ", 年龄:" << stuArray[i].age 
      << ", 分数:" << stuArray[i].score << endl;
  }
  system("pause");
  return 0;
}


姓名:张三, 年龄:18, 分数:100
姓名:李四, 年龄:28, 分数:99
姓名:赵六, 年龄:38, 分数:66
请按任意键继续. . .


8.4 结构体指针


作用:通过指针访问结构体中的成员


  • 利用操作符->可以通过结构体指针访问结构体属性


#include <iostream>
using namespace std;
#include <string>
struct Student
{
  string name;  //姓名
  int age;      //年龄
  int score;    //分数
};
int main()
{
  //1、创建学生结构体变量
  Student s = { "张三", 18, 100 };
  //2、通过指针指向结构体变量
  Student* p = &s;
  cout << "姓名:" << p->name << ", 年龄:" << p->age << ", 分数:" << p->score << endl;
  system("pause");
  return 0;
}


姓名:张三, 年龄:18, 分数:100
请按任意键继续. . .


8.5 结构体嵌套结构体


作用:结构体中的成员可以是另一个个结构体


例如:每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体


#include <iostream>
using namespace std;
#include <string>
//学生结构体定义
struct student
{
  //成员列表
  string name;  //姓名
  int age;      //年龄
  int score;    //分数
};
//教师结构体定义
struct teacher
{
  //成员列表
  int id;                //职工编号
  string name;           //教师姓名
  int age;               //教师年龄
  struct student stu;    //子结构体 学生
};
int main() {
  struct teacher t1;
  t1.id = 10000;
  t1.name = "老王";
  t1.age = 40;
  t1.stu.name = "张三";
  t1.stu.age = 18;
  t1.stu.score = 100;
  cout << "教师 职工编号: " << t1.id << " 姓名: " << t1.name << " 年龄: " << t1.age << endl;
  cout << "辅导学员 姓名: " << t1.stu.name << " 年龄:" << t1.stu.age << " 考试分数: " << t1.stu.score << endl;
  system("pause");
  return 0;
}


教师 职工编号: 10000 姓名: 老王 年龄: 40
辅导学员 姓名: 张三 年龄:18 考试分数: 100
请按任意键继续. . .


8.6 结构体做函数参数


作用:将结构体作为参数向函数中传递


传递方式有两种:


  • 值传递


  • 地址传递


#include <iostream>
using namespace std;
#include <string>
struct student
{
  string name;  //姓名
  int age;      //年龄
  int score;    //分数
};
//值传递
void printStudent(student stu)
{
  stu.age = 28;
  cout << "子函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
}
//地址传递
void printStudent2(student* stu)
{
  stu->age = 28;
  cout << "子函数中 姓名:" << stu->name << " 年龄: " << stu->age << " 分数:" << stu->score << endl;
}
int main() {
  student stu = { "张三",18,100 };
  //值传递
  printStudent(stu);
  cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
  cout << endl;
  //地址传递
  printStudent2(&stu);
  cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
  system("pause");
  return 0;
}


子函数中 姓名:张三 年龄: 28 分数:100
主函数中 姓名:张三 年龄: 18 分数:100
子函数中 姓名:张三 年龄: 28 分数:100
主函数中 姓名:张三 年龄: 28 分数:100
请按任意键继续. . .


总结:如果不想修改主函数中的数据,用值传递,反之用地址传递


8.7 结构体中const使用场景


作用:用const来防止误操作


#include <iostream>
using namespace std;
#include <string>
struct student
{
  string name;  //姓名
  int age;      //年龄
  int score;    //分数
};
//const使用场景
void printStudent(const student* stu) //加const防止函数体中的误操作
{
  //stu->age = 100;         //不能修改,因为加了const
  cout << "姓名:" << stu->name << " 年龄:" << stu->age << " 分数:" << stu->score << endl;
}
int main() 
{
  student stu = { "张三",18,100 };
  printStudent(&stu);
  system("pause");
  return 0;
}


姓名:张三 年龄:18 分数:100
请按任意键继续. . .


8.8 结构体案例


8.8.1 案例1


案例描述


学校正在做毕设项目,每名老师带领5个学生,总共有3名老师,需求如下:


1、设计学生和老师的结构体,其中在老师的结构体中,有老师姓名和一个存放5名学生的数组作为成员


2、学生的成员有姓名、考试分数,创建数组存放3名老师,通过函数给每个老师及所带的学生赋值


3、最终打印出老师数据以及老师所带的学生数据。



#include <iostream>
using namespace std;
#include <string>
#include <ctime>
struct Student
{
  string name;         //学生姓名
  int score;           //分数
};
struct Teacher
{
  string name;         //老师姓名
  Student sArray[5];   //创建5名学生数组
};
//给老师和学生赋值的函数
void allocateSpace(Teacher tArray[], int len)
{
  string tName = "教师";
  string sName = "学生";
  string nameSeed = "ABCDE";
  //给老师赋值
  for (int i = 0; i < len; i++)
  {
    tArray[i].name = tName + nameSeed[i];   //老师A,老师B,老师C
    //给老师带的学生赋值
    for (int j = 0; j < 5; j++)
    {
      tArray[i].sArray[j].name = sName + nameSeed[j];   //学生A,学生B,学生C....
      tArray[i].sArray[j].score = rand() % 61 + 40;     //成绩随机生成,40~100
    }
  }
}
//打印输出信息
void printTeachers(Teacher tArray[], int len)
{
  for (int i = 0; i < len; i++)         //遍历老师
  {
    cout << tArray[i].name << endl;  //输出老师姓名
    for (int j = 0; j < 5; j++)      //遍历老师带的学生
    {
      cout << "\t姓名:" << tArray[i].sArray[j].name 
        << " 分数:" << tArray[i].sArray[j].score << endl;
    }
  }
}
int main() 
{
  srand((unsigned int)time(NULL)); //随机数种子 分数随机需要这个
  Teacher tArray[3];                //创建3名老师数组
  int len = sizeof(tArray) / sizeof(tArray[0]);
  allocateSpace(tArray, len); //创建数据
  printTeachers(tArray, len); //打印数据
  system("pause");
  return 0;
}


教师A
        姓名:学生A 分数:70
        姓名:学生B 分数:87
        姓名:学生C 分数:86
        姓名:学生D 分数:66
        姓名:学生E 分数:48
教师B
        姓名:学生A 分数:87
        姓名:学生B 分数:51
        姓名:学生C 分数:50
        姓名:学生D 分数:75
        姓名:学生E 分数:74
教师C
        姓名:学生A 分数:46
        姓名:学生B 分数:61
        姓名:学生C 分数:50
        姓名:学生D 分数:44
        姓名:学生E 分数:74
请按任意键继续. . .


8.8.2 案例2


案例描述:


1、设计一个英雄的结构体,包括成员姓名,年龄,性别;创建结构体数组,数组中存放5名英雄。


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


五名英雄信息如下:


  {"刘备",23,"男"},
  {"关羽",22,"男"},
  {"张飞",20,"男"},
  {"赵云",21,"男"},
  {"貂蝉",19,"女"},


例:


#include <iostream>
using namespace std;
#include <string>
#include <ctime>
//英雄结构体
struct hero
{
  string name;   //姓名
  int age;       //年龄
  string sex;    //性别
};
//冒泡排序,升序
void bubbleSort(hero arr[], int len)
{
  for (int i = 0; i < len - 1; i++)
  {
    for (int j = 0; j < len - 1 - i; j++)
    {
      if (arr[j].age > arr[j + 1].age)
      {
        hero temp = arr[j];   //hero相当于一个类型,想当于int
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
}
//打印数组
void printHeros(hero arr[], int len)
{
  for (int i = 0; i < len; i++)
  {
    cout << "姓名:" << arr[i].name << "  性别:" << arr[i].sex << "  年龄:" << arr[i].age << endl;
  }
}
int main() 
{
  //创建数组存放5名英雄
  struct hero arr[5] =
  {
    {"刘备",23,"男"},
    {"关羽",22,"男"},
    {"张飞",20,"男"},
    {"赵云",21,"男"},
    {"貂蝉",19,"女"},
  };
  //int len = sizeof(arr) / sizeof(hero); //获取数组元素个数
  int len = sizeof(arr) / sizeof(arr[0]); //获取数组元素个数
  bubbleSort(arr, len); //排序
  printHeros(arr, len); //打印
  system("pause");
  return 0;
}


姓名:貂蝉  性别:女  年龄:19
姓名:张飞  性别:男  年龄:20
姓名:赵云  性别:男  年龄:21
姓名:关羽  性别:男  年龄:22
姓名:刘备  性别:男  年龄:23
请按任意键继续. . .


8.8.3 案例3:通讯录管理系统


#include <iostream>
using namespace std;
#include <string>
# define MAX 1000
//设计联系人结构体
struct Person
{
  //姓名
  string m_Name;
  //性别
  int m_Sex;
  //年龄
  int m_Age;
  //电话
  string m_Phone;
  //住址
  string m_Addr;
};
//设计通讯录结构体
struct Addressbooks
{
  //通讯录中保存的联系人数组
  struct Person personArray[MAX];     //子结构体,结构体嵌套
  //通讯录中当前记录联系人个数
  int m_Size;
};
//1、添加联系人
void addPerson(Addressbooks* abs)    //形参为结构体指针
{
  //判断通讯录是否已满,如果满了就不再添加
  if (abs->m_Size == MAX)
  {
    cout << "通讯录已满,无法添加!" << endl;
    return;
  }
  else
  {
    //添加具体联系人
    //姓名
    string name;
    cout << "请输入姓名:" << endl;
    cin >> name;
    abs->personArray[abs->m_Size].m_Name = name;
    //性别
    cout << "请输入性别:" << endl;
    cout << "1---男" << endl;
    cout << "2---女" << endl;
    int sex = 0;
    while (true)
    {
      cin >> sex;
      if (sex == 1 || sex == 2)
      {
        abs->personArray[abs->m_Size].m_Sex = sex;
        break;
      }
      cout << "输入有误,请重新输入:" << endl;
    }
    //年龄
    cout << "请输入年龄:" << endl;
    int age = 0;
    cin >> age;
    abs->personArray[abs->m_Size].m_Age = age;
    //电话
    cout << "请输入联系电话:" << endl;
    string phone;
    cin >> phone;
    abs->personArray[abs->m_Size].m_Phone = phone;
    //住址
    cout << "请输入家庭地址:" << endl;
    string address;
    cin >> address;
    abs->personArray[abs->m_Size].m_Addr = address;
    //更新通讯录人数
    abs->m_Size++;
    cout << "添加成功!" << endl;
    system("pause");  //请按任意键继续
    system("cls");    //清屏操作
  }
}
//2、显示所有的联系人
void showPerson(Addressbooks * abs)
{
  //判断通讯录中人数是否为0,如果为0,提示为空;不为零,则显示信息
  if (abs->m_Size == 0)
  {
    cout << "当前记录为空!" << endl;
  }
  else
  {
    for (int i = 0; i < abs->m_Size; i++)
    {
      cout << "姓名:" << abs->personArray[i].m_Name << "\t";
      cout << "性别:" << (abs->personArray[i].m_Sex == 1 ? "男":"女")<<"\t";
      cout << "年龄:" << abs->personArray[i].m_Age << "\t";
      cout << "电话:" << abs->personArray[i].m_Phone << "\t";
      cout << "住址:" << abs->personArray[i].m_Addr << endl;
    }
  }
  system("pause");   //按任意键继续
  system("cls");     //清屏
}
//3、删除联系人:(1)封装检测联系人是否存在  (2)封装删除联系人函数  (3)检测删除联系人功能
//(1)检测联系人是否存在,存在返回位置
//参数一:通讯录   参数二:对比姓名
int isExist(Addressbooks* abs, string name)
{
  //找到用户输入的姓名了
  for (int i = 0; i < abs->m_Size; i++)
  {
    if (abs->personArray[i].m_Name == name)
    {
      return i;  //找到返回数组中下标
    }
  }
  //没有找到,返回-1
  return -1;
}
//(2)删除指定联系人
void deletePerson(Addressbooks* abs)
{
  cout << "请输入你要删除的联系人:" << endl;
  string name;
  cin >> name;
  //ret==-1  or ret != -1
  int ret = isExist(abs, name);
  if (ret != -1)
  {
    //查找到人,进行删除操作
    for (int i = ret; i < abs->m_Size; i++)
    {
      //数据前移
      abs->personArray[i] = abs->personArray[i + 1];
    }
    abs->m_Size--;    //更新人员总数
    cout << "删除成功!" << endl;
  }
  else
  {
    cout << "查无此人!" << endl;
  }
  system("pause");
  system("cls");
}
//4、查找联系人信息:(1)封装查找联系人函数 (2)测试查找指定联系人
void findPerson(Addressbooks* abs)
{
  cout << "请输入你要查找的联系人:" << endl;
  string name;
  cin >> name;
  //判断指定的联系人是否在在通讯录中
  int ret = isExist(abs, name);
  if (ret != -1)   //找到联系人
  {
    cout << "姓名:" << abs->personArray[ret].m_Name << "\t";
    cout << "性别:" << (abs->personArray[ret].m_Sex == 1 ? "男" : "女") << "\t";
    //cout << "性别:" << abs->personArray[ret].m_Sex << "\t";
    cout << "年龄:" << abs->personArray[ret].m_Age << "\t";
    cout << "电话:" << abs->personArray[ret].m_Phone << "\t";
    cout << "家庭住址:" << abs->personArray[ret].m_Addr << endl;
  }
  else
  {
    cout << "查无此人!" << endl;
  }
  system("pause");
  system("cls");
}
//5、修改联系人信息
void modifyPerson(Addressbooks* abs)
{
  cout << "请输入你要修改的联系人:" << endl;
  string name;
  cin >> name;
  int ret = isExist(abs, name);
  if (ret != -1)
  {
    //姓名
    string name;
    cout << "请输入姓名:" << endl;
    cin >> name;
    abs->personArray[ret].m_Name = name;
    //性别
    cout << "请输入性别:" << endl;
    cout << "1---男" << endl;
    cout << "2---女" << endl;
    int sex = 0;
    while (true)
    {
      cin >> sex;
      if (sex == 1 || sex == 2)
      {
        abs->personArray[ret].m_Sex = sex;
        break;
      }
      cout << "输入有误,请重新输入:" << endl;
    }
    //年龄
    cout << "请输入年龄:" << endl;
    int age = 0;
    cin >> age;
    abs->personArray[ret].m_Age = age;
    //电话
    cout << "请输入电话:" << endl;
    string phone;
    cin >> phone;
    abs->personArray[ret].m_Phone = phone;
    //住址
    cout << "请输入家庭住址:" << endl;
    string address;
    cin >> address;
    abs->personArray[ret].m_Addr = address;
    cout << "信息修改成功!" << endl;
  }
  else
  {
    cout << "查无此人!" << endl;
  }
  system("pause");
  system("cls");
}
//6、清空联系人:只需把通讯录中联系人数量置0,实现逻辑上的清空
void cleanPerson(Addressbooks* abs)
{
  abs->m_Size = 0;   //把通讯录中联系人数量置0,实现逻辑上的清空
  cout << "通讯录已清空" << endl;
  system("pause");
  system("cls");
}
//菜单界面
void showMenu()
{
  cout << "***********************" << endl;
  cout << "**** 1、添加联系人 ****" << endl;
  cout << "**** 2、显示联系人 ****" << endl;
  cout << "**** 3、删除联系人 ****" << endl;
  cout << "**** 4、查找联系人 ****" << endl;
  cout << "**** 5、修改联系人 ****" << endl;
  cout << "**** 6、清空联系人 ****" << endl;
  cout << "**** 0、退出通讯录 ****" << endl;
  cout << "***********************" << endl;
}
int main()
{
  //创建通讯录结构体变量
  Addressbooks abs;
  //初始化通讯录中当前人员个数
  abs.m_Size = 0;   //初始化0个人
  int select = 0;   //初始化选择
  while (true)
  {
    //1、菜单调用
    showMenu();
    cin >> select;
    switch (select)
    {
    case 1:      //1、添加联系人
      addPerson(&abs);   //利用地址传递,可以修饰实参
      break;
    case 2:      //2、显示联系人
      showPerson(&abs);
      break;
    case 3:      //3、删除联系人
    //{
    //  cout << "请输入与删除联系人姓名:" << endl;
    //  string name;
    //  cin >> name;;
    //  if (isExist(&abs, name) == -1)
    //  {
    //    cout << "查无此人!" << endl;
    //  }
    //  else
    //  {
    //    cout << "找到此人!" << endl;
    //  }
    //}
      deletePerson(&abs);
      break;
    case 4:      //4、查找联系人
      findPerson(&abs);
      break;
    case 5:      //5、修改联系人
      modifyPerson(&abs);
      break;
    case 6:      //6、清空联系人
      cleanPerson(&abs);
      break;
    case 0:      //0、退出通讯录 
      cout << "欢迎下次使用!" << endl;
      system("pause");
      return 0;
      break;
    }
  }
  system("pause");
  return 0;
}


目录
相关文章
|
2月前
|
编译器 C++
C++入门12——详解多态1
C++入门12——详解多态1
47 2
C++入门12——详解多态1
|
2月前
|
C++
C++入门13——详解多态2
C++入门13——详解多态2
89 1
|
2月前
|
存储 安全 编译器
【C++打怪之路Lv1】-- 入门二级
【C++打怪之路Lv1】-- 入门二级
30 0
|
2月前
|
自然语言处理 编译器 C语言
【C++打怪之路Lv1】-- C++开篇(入门)
【C++打怪之路Lv1】-- C++开篇(入门)
39 0
|
2月前
|
分布式计算 Java 编译器
【C++入门(下)】—— 我与C++的不解之缘(二)
【C++入门(下)】—— 我与C++的不解之缘(二)
|
2月前
|
编译器 Linux C语言
【C++入门(上)】—— 我与C++的不解之缘(一)
【C++入门(上)】—— 我与C++的不解之缘(一)
|
2月前
|
编译器 C++
C++入门11——详解C++继承(菱形继承与虚拟继承)-2
C++入门11——详解C++继承(菱形继承与虚拟继承)-2
41 0
|
2月前
|
程序员 C++
C++入门11——详解C++继承(菱形继承与虚拟继承)-1
C++入门11——详解C++继承(菱形继承与虚拟继承)-1
44 0
|
2月前
|
存储 算法 C++
C++入门10——stack与queue的使用
C++入门10——stack与queue的使用
48 0
|
2月前
|
存储 C++ 容器
C++入门9——list的使用
C++入门9——list的使用
22 0