C语言中的指针(上)

目录

一、基本概念

1.变量的存储空间

2.定义指针

3.引用与解引用

二、指针的算术运算、类型以及通用指针

1.指针的算数运算

2.指针类型以及通用型指针

三、指向指针的指针(pointers to pointers)

四、函数传值以及传引用

1.局部变量

2.从存储地址出修改局部变量

五、指针和数组以及数组作为函数参数

1.指针与数组

2.数组作为函数参数

六、指针和字符数组

1.创建一个字符数组

2.字符数组作为函数参数

3.字符数组的存储方式


一、基本概念

1.变量的存储空间

       通常我们所说的内存是计算机的随机内存即RAM,并且不同的数据类型分配到的存储空间的大小也各不相同;整数类型数据 int 分配到的存储空间大小为 4bytes,字符类型的数据 char 分配到的存储空间为 1bytes,浮点数 float 分配到的存储空间为 4bytes。

2.定义指针

      指针的本质就是一个整数类型的变量,用来存放被指向数据的地址,即 int *p = &a; 代表的是创建一个指针 p 用来存储变量 a 的地址,其中 & 代表的是取得数据 a 的地址。

#include<stdio.h>

int main()
{
    int a = 3; 
    int *p = &a;
    printf("%d\n", p); 

    return 0;

}

运行上面的代码得到的结果为:

即数据 a 的存储地址为 e21ff898。

3.引用与解引用

       在定义指针时使用到的 * 表示的是引用,即得到被指向数据的地址,而在指针的前面使用 * 表示的是解引用,用来表示被指向数据的值。

#include<stdio.h>

int main()
{
    int a = 3; 
    int *p = &a;
    printf("%d\n", p);
    printf("%d\n", *p);  //输出p代表的地址的值,即a的值,为3

    return 0;
}

运行上面的代码,前一行打印语句的输出为 a 的地址,由于第二行打印是对指针 p 进行反引用,所以第二行打印语句的输出为 a 的值 3。

二、指针的算术运算、类型以及通用指针

1.指针的算数运算

       指针代表的是被指向数据的地址,因此指针的值加一或者减一,并不会使得被指向数据的值产生相应的加一或者减一的效果,而且指针加一或者减一,则指向的地址进行反引用得到的数据将会是乱码,而不是一个确切的值。

#include<stdio.h>

int main()
{
    int a = 3; 
    int *p = &a;
    
    printf("Address of a is : %d.\n", p);
    printf("size of integer is: %d bytes.\n", sizeof(int));
    printf("value of (p + 1) is : %d.\n", p + 1); //如果p = 2004,则 p+1 = 2008;这是因为整型的地址占用为4个字节
    printf("value at address of p is : %d.\n", *p);
    printf("value at address of (p + 1) is : %d.\n", *(p + 1)); //得到的是一个垃圾值

    return 0;
}

运行上面的代码,得到的结果如下:

从上面的结果中可以看出,由于整型数据的存储大小为4个字节,因此对指针 p 进行加一的操作得到的数据是在原来的 p 的值上加了4,而不是单纯的加一操作。并且对 p+1 进行解引用得到的数值将会是一个垃圾值。

2.指针类型以及通用型指针

       指针是强类型的(这是因为指针不止用来存储地址,也可以用它来解引用那些地址所对应的内容),也就是说不同的数据类型需要相对应类型的指针来进行指向;比如一个整型变量,指针指向的是第一个字节的位置,则计算机读取时向后再数三个字节得到该变量的值,若是使用其它类型的指针,则无法正确完成指向;虽然 float 类型的数据也分配有四个字节,但它和整型的数据并不相同,因此利用整型的指针并没有办法正确存储 float 类型的数据。

#include<stdio.h>

int main()
{
    int a = 3; 
    int *p = &a;
    
    float *p0 = &a;
    printf("While int pointer is used, address of a is : %d, value of a is ; %d;\n", p, *p);//172 = 1010 1100
    printf("While float pointer is used, address of a is : %d, value of a is ; %d;\n\n", p0, *p0); //可以看出两种类型的指针对应的地址是一样的,但值不一样

    return 0;
}

运行上面的代码,得到的结果如下:

可以从结果中看出,对于整数类型的数据,使用浮点数类型的指针会得到错误的指向结果。

       void 类型的指针,也被称为通用型指针,由于通用指针没有使用到任何类型的定义,因此不能对其进行反解。

#include<stdio.h>

int main()
{
    int a = 3; 
    int *p = &a;
    
    void *p0 = p; //通用指针没有使用到任何类型的定义,因此不能对其进行反解
    printf("While int pointer is used, address of a is : %d, value of a is ; %d;\n", p, *p);//172 = 1010 1100
    printf("While void pointer is used, address of a is : %d, value of a is ; %d;\n\n", p0, *p0); //可以看出两种类型的指针对应的地址是一样的,但值不一样

    return 0;
}

运行上面的代码,则会发现程序报错:

通用型指针,不会指向任何类型的地址,故无法进行解引用。

三、指向指针的指针(pointers to pointers)

       指针是用来表示被指向数据的地址的,故指针的本质是一个整型的变量,所以指向指针的指针的数据类型也是整型。

        当定义了一个指针 int *p,则可以用 int **q 来存储指针 p 的地址,也可以使用 int ***r来存储指针 q 的地址,以此类推即可。

#include<stdio.h>

int main()
{

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

    printf("Address of data a is : %d.\n", p);
    int **P = &p;
    int ***q = &P;
    printf("Address of pointer p is : %d.\n", P);
    printf("Value of p(Address of a) is : %d.\n", *P);
    printf("Value of a is : %d.\n", *(*P));
    printf("Address of P is : %d.\n", q);
    printf("Value of P(address of p) is : %d.\n", *q);
    printf("Value of p(address of a) is : %d.\n", *(*q));
    printf("Value of data a is : %d.\n", ***q);
    ***q = 10;
    printf("a = %d\n", a);
    **q = *p +2;
    printf("%d\n", **q);
    
    return 0;
}

运行上述代码得到的结果为:

在上面的代码中使用 p 来作为指针指向数据 a 的地址,P 作为指针来指向指针 p 的地址,q 作为指针来指向指针 P 的地址;通过解引用可以利用指针来改变被指向数据的值。

四、函数传值以及传引用

1.局部变量

       当我在一个函数中声明一个变量,那么该变量称为局部变量,也就是说只能在该函数中对该变量进行修改以及处理。

#include<stdio.h>

int Increment(int a)
{
    a = a + 1;  
}

int main()
{
    int a = 3;

    Increment(a);
    printf("a = %d.\n", a);
    return 0;
}

运行上面的代码,若不考虑自定义函数 Increment() 中的局部变量的影响,则可以推测输出的 a 的值应该为 4。但通过运行代码得到的结果如下:

这说明在自定义函数中 a 是一个局部变量,和主函数中的 a 并不是同一个变量,也就是说在自定义函数中的变量存储的地址和主函数中的变量存储的地址是不一样的,所以我们需要从指针的层面对它们进行修改。

2.从存储地址出修改局部变量

由于局部变量和主函数中的变量的存储地址不相同,因此可以使用指针从变量的地址处进行处理。

#include<stdio.h>

void Increment(int *p)
    {
        *p = (*p) + 1;
    }


int main()
{
    int a = 3;
    int *p = &a;

    Increment(&a);
    printf("a = %d.\n", a);
    return 0;
}

运行上面的代码,可以实现利用自定义函数对主函数中的变量进行修改。

        在自定义函数中的参数被称为形参,主函数中的参数称为实参,自定义函数的调用过程中实现了将实参转化到形参中进行处理的目的,这就是函数的调用。利用指针以及解引用进行处理的时候能够实现从参数的存储地址处修改参数而不是从参数的值处修改参数,从而达到处理数据的目的,这种方法被称为传引用。

五、指针和数组以及数组作为函数参数

1.指针与数组

       定义一个数组后,使用指针指向该数组时,指针存储的是数组中的第一个元素的地址。数组名本身也可以用来代表一个地址,在使用指针时甚至可以不用取地址符,即可以写为 int *p = &A[i]或者 int *p = A + i。

#include<stdio.h>

int main()
{
    int b[] = {0, 1, 2, 3, 4};

    int *P = &b;       //得到的是数组中的第一个元素的地址,在此处甚至可以不用对数组b取地址
    int *P0 = &b[0];   //得到第一个元素的地址,此处也可以写成: int *P0 = b + 1;后面的写法类推
    int *P1 = &b[1];   //得到第二个元素的地址,与第一个元素的地址相差4个字节
    int *P2 = &b[2];   //与前一个元素的地址相差4个字节
    int *P3 = &b[3];   //与前一个元素的地址相差4个字节
    int *P4 = &b[4];   //与前一个元素的地址相差4个字节

    printf("Address of P is : %d.\n", P);
    printf("Address of P0 is : %d.\n", P0);
    printf("Address of P1 is : %d.\n", P1);
    printf("Address of P2 is : %d.\n", P2);
    printf("Address of P3 is : %d.\n", P3);
    printf("Address of P4 is : %d.\n", P4);


    //利用该循环使用两种不同的方法输出数组及地址
    for(int j = 0; j < 5; j++)
    {
        printf("%d:\n", j + 1);
        printf("Address  = %d\n", &b[j]);  //直接取数组元素地址即可
        printf("Value = %d\n", b[j]);      //打印数组元素
        printf("Address = %d\n", b + j);   //数组名可以直接代表元素地址
        printf("Value = %d\n", *(b + j));  //对数组名解引用得到数组元素的值
    }

    P0 = P0 + 1;
    printf("%d\n", *P0);  //输出的值为b[1]的值,即输出1
 
    return 0;
}

运行上面的代码得到的输出为:

       从运行结果中可以看出,数组名可以直接作为地址进行指针指向,且 *p = A + i 和 *p = A[i] 的运行效果是一样的。

2.数组作为函数参数

       当数组作为一个参数时,编译器不会分配整个数组长度的空间用来进行存储,而是只分配出一个同名的指针的存储空间,即将 A 转化成为了 *A,并没有拷贝变量的值,而是直接拷贝了变量的地址,也就是说函数在传递变量的过程就是一个引用的过程。并且不同的操作系统中指针分配到的存储空间是不一样的,64位操作系统中占用了8个字节,32位操作系统中占用了4个字节。

尝试编写函数来计算数组的大小:

int SumofElements(int A[]) 
{
    int i, sum = 0;
    int size = sizeof(A)/sizeof(A[0]); //数组整体字节数目比上一个元素的字节数目
    printf("SOE - Size of A = %d, size of A[0] = %d.\n",sizeof(A), sizeof(A[0]));
    for(i = 0; i < size; i++)
    {
        sum += A[i];
    }
    return sum;
}

       上面这个函数尝试以数组作为函数形参,并在函数中使用 for 循环来计算数组中的各个元素之和,但运行该自定义函数后发现计算结果是错误的。

#include<stdio.h>

int SumofElements(int A[]) 
{
    int i, sum = 0;
    int size = sizeof(A)/sizeof(A[0]); //数组整体字节数目比上一个元素的字节数目
    printf("SOE - Size of A = %d, size of A[0] = %d.\n",sizeof(A), sizeof(A[0]));
    for(i = 0; i < size; i++)
    {
        sum += A[i];
    }
    return sum;
}

int main()
{
     //数组作为函数参数
    int A[] = {1, 2, 3, 4, 5};
    int size = sizeof(A)/sizeof(A[0]); //数组整体字节数目比上一个元素的字节数目
    int total = SumofElements(A);
    printf("Main - Size of A = %d, size of A[0] = %d.\n",sizeof(A), sizeof(A[0]));
    printf("Sum of elements = %d.\n", total);
    return 0;
}

       从运行的结果中可以看出,该函数在计算数组中的元素之和时发生了错误,这是因为在作为函数参数时数组名被默认为是一个指针,而不是整个数组。

对自定义函数进行改写:

#include<stdio.h>

int SumofElements(int A[], int size) 
{
    int i, sum = 0;
    for(i = 0; i < size; i++)
    {
        sum += A[i];
    }
    return sum;
}

int main()
{
    int A[] = {1, 2, 3, 4, 5};
    int size = sizeof(A)/sizeof(A[0]); //数组整体字节数目比上一个元素的字节数目
    int total = SumofElements(A, size);
    printf("Main - Size of A = %d, size of A[0] = %d.\n",sizeof(A), sizeof(A[0]));
    printf("Sum of elements = %d.\n", total);

    return 0;
}

运行得到的结果为:

可以看出该计算结果是正确的。

六、指针和字符数组

1.创建一个字符数组

       在 C 语言中,创建一个字符数组需要的长度一般要比存储在该数组中的元素的个数多一,比如创建一个字符数组其中包含 john 这个字符串,那么可以将该字符数组的长度设置为5或者大于5即可,这是因为在字符数组中存储字符串之后,计算机并不知道字符串中的最后一个字母在哪一位上,故需要在最后一个元素的后面加上一个 NULL('\0')元素,用来指明字符串的结束,也就是说字符数组是以 '\0' 结尾的。

#include<stdio.h>

int main()
{
      char C[4];
      C[0] = 'j';
      C[1] = 'o';
      C[2] = 'h';
      C[3] = 'n';
      
      printf("%s", C);
      return 0;
}

运行上面的代码得到的结果为:

       可以看出,由于没有将字符数组的长度设置为大于字符串长度的值,打印出来的字符串没有一个合适的结尾。因此对代码进行修改:

#include<stdio.h>

int main()
{
      char C[4];
      C[0] = 'j';
      C[1] = 'o';
      C[2] = ‘h';
      C[3] = 'n';
      C[4] = '\0';
      
      printf("%s", C);
      return 0;
}

得到正确的结果为:

       但是无论字符数组的长度设置为多大, 函数 sizeof() 都不会考虑字符串末尾添加的 NULL 元素,也就是说使用该函数得到的数组的长度均为其中的字符串的长度。

       如果不想在定义字符数组的时候添加末尾的 NULL 元素,可以在定义字符数组的时候直接编写好其中需要增加的字符串,这样得到的字符数组进行打印不会出现错误的值。

#include<stdio.h>

int main()
{
    char C[] = "john";
    printf("%s", C);
    return 0; 
}

2.字符数组作为函数参数

       当字符数组作为函数参数时,效果和一般的数组是一样的,也就是说字符数组在函数中也是被传引用,函数中传递的只是该数组的基地址(首个元素的地址),并不会将所有元素的地址在函数中进行传递。

#include<stdio.h>

int print(char *C)
{
    int i = 0;
    while(C[i] != '\0')    //此处注意是单引号
        {
             printf("%c", C[i]); 
             i++;
        }
    printf("\n");
}

int main()
{   
    char C[20] = "HELLO"
    char* A;
    A = C;
    print(A); 
    return 0;
}

 运行上面的代码得到的结果为:

 也可以将上面代码中的自定义函数进行修改,将其中的打印方式修改如下:

printf("%c", *(C + i));

效果和前面的是一样的,因为上面的修改是对数组指针进行了解引用。

还可以对自定义函数进行如下的修改:

int print(char *C)
{
    while(*C != '\0')
        { 
            printf("%c", *C);
            C++;
        }
    printf("\n");
}

得到的结果和前面仍然是一样的。

3.字符数组的存储方式

#include<stdio.h>

int print(char *C)
{
    while(*C != '\0')
        {
            printf("%c", *C);
            C++;
        }
    printf("\n");
}


int main()
{
    char C[20] = "HELLO";

    print(C);
    return 0;
}

上面的这部分代码和之前的一样,运行的时候得到的结果如下:
 而且这部分代码可以在自定义函数中对字符串进行修改:

#include<stdio.h>

int print(char *C)
{
    C[0] = 'A';
    while(*C != '\0')
        {
            printf("%c", *C);
            C++;
        }
    printf("\n");
}


int main()
{
    char C[20] = "HELLO";

    //char *C = "HELLO";
    print(C);
    return 0;
}

 得到的运行结果为:

从结果中可以看出,在自定义函数中实现了对字符串的修改。

主函数中的字符串也可以使用其他的定义方式:

#include<stdio.h>

int print(char *C)
{
    while(*C != '\0')
        {
            printf("%c", *C);
            C++;
        }
    printf("\n");
}


int main()
{

    char *C = "HELLO";
    print(C);
    return 0;
}

运行得到的结果为:

 尝试在自定义函数中对字符串进行修改:

#include<stdio.h>

int print(char *C)
{
    C[0] = 'A';
    while(*C != '\0')
        {
            printf("%c", *C);
            C++;
        }
    printf("\n");
}


int main()
{

    char *C = "HELLO";
    print(C);
    return 0;
}

运行上述代码会发现程序无法输出:

也就是说使用下面的定义字符串的方式时,无法在自定义函数中对字符串进行修改。

这是因为,当使用上面的方式定义字符串时,是直接将整个数组存储在一起,因此可以对其中的一两个元素进行修改;但当使用下面的方式定义字符串时,时将字符串的地址作为变量进行传输,没办法在自定义函数中对其中的某个元素进行修改。

到这里算是总结完指针中的部分内容了,还有一大堆需要学习的东西,真的是非常的棘手。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/170253.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ctfshow】web入门-信息搜集-web21~28

SSS web21_爆破什么的&#xff0c;都是基操web22_域名也可以爆破的&#xff0c;试试爆破这个ctf.show的子域名web23_还爆破&#xff1f;这么多代码&#xff0c;告辞&#xff01;web24_爆个&#x1f528;web25_爆个&#x1f528;&#xff0c;不爆了web26_这个可以爆web27_CTFsho…

软件测试之测试用例的设计

1. 测试用例的概念 软件测试人员向被测试系统提供的一组数据的集合&#xff0c;包括 测试环境、测试步骤、测试数据、预期结果 2. 为什么在测试前要设计测试用例 测试用例是执行测试的依据 在回归测试的时候可以进行复用 是自动化测试编写测试脚本的依据 衡量需求的覆盖率…

C#开发的OpenRA游戏之属性QuantizeFacingsFromSequence(7)

C#开发的OpenRA游戏之属性QuantizeFacingsFromSequence(7) 前面分析了身体的方向,在这里继续QuantizeFacingsFromSequence属性,这个属性就是通过序列定义文件里获取身体的方向。 根据前面分析可知,同样有一个信息类QuantizeFacingsFromSequenceInfo: [Desc("Deriv…

基于安卓android微信小程序美容理发店预约系统app

项目介绍 为美容院设计一个系统以减少员工的工作量就成为了想法的初始状态。紧接着对美容院进行进一步的调查发现我的想法已然落后。基本上每个美容院都以有了自己的信息系统&#xff0c;并且做的已经较完善了。 在这时我突然想到&#xff0c;现在关注美容养生的人越来越多&am…

Windows 安装 Docker Compose

目录 前言什么是 Docker Compose &#xff1f;安装 Docker Compose配置环境变量结语开源项目 前言 在当今软件开发和部署领域&#xff0c;容器化技术的应用已成为提高效率和系统可移植性的关键手段。Docker&#xff0c;作为领先的容器化平台&#xff0c;为开发人员提供了轻松构…

MobaXterm如何连接CentOS7的Linux虚拟机?Redis可视化客户端工具如何连接Linux版Redis?

一、打开Lunix虚拟机,进入虚拟机中,在终端中输入ifconfig,得到以下信息&#xff0c;红框中为ip地址 二、打开MobaXterm&#xff0c;点击session 选择SSH&#xff0c;在Remote host中输入linux得到的IP地址&#xff0c;Specify username中可起一个任意的连接名称。 输入密码 四、…

RoCE、IB和TCP等网络的基本知识及差异对比

目前有三种RDMA网络&#xff0c;分别是Infiniband、RoCE(RDMA over Converged Ethernet)、iWARP。 其中&#xff0c;Infiniband是一种专为RDMA设计的网络&#xff0c;从硬件级别保证可靠传输 &#xff0c;技术先进&#xff0c;但是成本高昂。 而RoCE 和 iWARP都是基于以太网的…

leetcode数据结构与算法刷题(三)

目录 第一题 交叉链表 思想&#xff1a; 注意点 第一步先求两个链表的长度 第二步 让长的先走&#xff0c;当长短一样时一起走。 犯错点 第二题 判断是有环 思想&#xff1a; 注意 错误分享 第三题&#xff08;重点面试题&#xff09; 思路&#xff1a; 这题面试问题&a…

InnoDB 的一次更新事务是怎么实现的?

大体流程&#xff1a; 步骤: 1.加载数据到缓存中&#xff08;Buffer Pool&#xff09;&#xff1a; 在进行数据更新时&#xff0c;InnoDB首先会在缓冲池&#xff08;Buffer Pool&#xff09;中查找该记录是否已经在内存中。如果记录不在内存中&#xff0c;会将需要更新的数据…

java学习part06数组工具类

1比较内容 2输出信息 3值填充 4快速排序 5二分查找 负数没找到&#xff0c;其他表示下标

Redis常用的八种场景

作为一名 Java后端人员&#xff0c;对 Redis肯定并不陌生&#xff0c;Redis作为一种内存数据库&#xff0c;以其速度之快在编程的舞台上纵横多年&#xff0c;那么&#xff0c;Redis到底适合哪些业务场景&#xff1f;今天就来聊一聊。 1. 缓存/数据库 缓存&#xff08;Cache&am…

ESP32 http 请求

目录 参考教程1.使用的http连接2.使用Vscode-IDF创建http_request例程3.修改http_request_example_main.c函数4.已经获取到响应的数据 参考教程 ESP-IDF HTTP获取网络时间 1.使用的http连接 http://api.m.taobao.com/rest/api3.do?apimtop.common.getTimestamp请求可以得到…

校园报修抢修小程序系统开发 物业小区报修预约上门维修工单系统

开发的功能模块有&#xff1a; 1.报修工单提交&#xff1a;学生、教职员工等可以使用小程序提交报修请求。这通常包括选择报修的问题类型&#xff08;如水漏、电器故障、照明问题等&#xff09;&#xff0c;地点&#xff0c;报修联系人&#xff0c;联系电话等&#xff0c;并提供…

C语言——I /深入理解指针(一)

一、内存和地址 1byte&#xff08;字节&#xff09; 8bit&#xff08;比特位&#xff09; 1KB 1024byte 1MB 1024KB 1GB 1024MB 1TB 1024GB 1PB 1024TB一个比特位可以存放二进制的0/1的一位 ⽣活中我们把⻔牌号也叫地址&#xff0c;在计算机中我们把内存单元的编号也称为…

Java学习day14:权限修饰符,集合(知识点+例题详解)

声明&#xff1a;该专栏本人重新过一遍java知识点时候的笔记汇总&#xff0c;主要是每天的知识点题解&#xff0c;算是让自己巩固复习&#xff0c;也希望能给初学的朋友们一点帮助&#xff0c;大佬们不喜勿喷(抱拳了老铁&#xff01;) 往期回顾 Java学习day13&#xff1a;泛型&…

kettle创建数据库资源库kettle repository manager

数据库资源库是将作业和转换相关的信息存储在数据库中&#xff0c;执行的时候直接去数据库读取信息&#xff0c;很容易跨平台使用。 创建数据库资源库&#xff0c;如图 1.点击Connect 2.点击Repository Manager 3.点击Other Repository 4.点击Database Repository 在选择Ot…

Selenium IDE录制脚本

文章目录 1.环境搭建1.1 Chrome浏览器安装1.2 Chrome驱动安装1.3 Selenium IDE插件的安装 2.Selenium IDE插件介绍2.1 初始化界面2.2 菜单栏2.3 工具栏2.4 地址栏2.5 测试用例窗口2.6 测试脚本窗口2.7 日志和引用窗口 3.元素定位3.1 通过id进行元素定位3.2 通过name进行元素定位…

听GPT 讲Rust源代码--src/bootstrap

图片来自 使用rust的image库进行图片压缩[1] File: rust/src/bootstrap/build.rs 在Rust源代码中&#xff0c;rust/src/bootstrap/build.rs这个文件是一个构建脚本。构建脚本是一个在编译Rust编译器本身时运行的程序&#xff0c;它用于初始化和配置Rust编译器的构建过程。build…

数据结构【栈】

文章目录 数据结构 栈栈的概念与结构栈接口实现 数据结构 栈 栈的概念与结构 栈是是一种特殊的线性表&#xff0c;栈的规定是只在一端插入删除数据&#xff0c;插入删除的一端叫做栈顶&#xff0c;另一端叫栈底。根据上面的特性&#xff0c;栈的数据是后入先出 栈接口实现 栈接…

Java-方法的重写

【1】重写&#xff1a; 发生在子类和父类中&#xff0c;当子类对父类提供的方法不满意的时候&#xff0c;要对父类的方法进行重写。 【2】重写有严格的格式要求&#xff1a; 子类的方法名字和父类必须一致&#xff0c;参数列表&#xff08;个数&#xff0c;类型&#xff0c…