C语言——深入理解指针(2)(数组与指针)

文章目录

  • 数组名的理解
  • 使用指针访问数组
  • 一维数组传参的本质
  • 冒泡排序
  • 二级指针
  • 指针数组
  • 指针数组模拟二维数组

数组名的理解

之前我们在使用指针访问数组内容时,有这样的代码:

int arr[10]={1,2,3,4,5,6,7,8,9,10};
int* p=&arr[0];

这里我们使用&arr[0]的方式拿到了数组第一个元素的地址,但是其实数组名本来就是地址,而且是数组首元素的地址。
我们来做个测试,看数组名到底是不是首元素的地址:
在这里插入图片描述
从打印出来的值来看,它们确实是一样的,所以数组名确实是首元素的地址。
那么数组名是首元素地址的话,我们去求地址长度,在32位平台下应该为4个字节(地址的长度与多少位的平台有关)
我们用sizeof计算下地址长度是多少:
在这里插入图片描述
这是为什么呢?
数组名就是数组首元素(第一个元素)的地址,但是有两个例外:

  • sizeof(数组名),sizeof中单独放数组名时,这里的数组名表示整个数组,不是首元素的地址,此时计算的是这整个数组的大小,单位是字节。
  • &数组名,这里的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)在这里插入图片描述
    从值的角度来看的话,取整个数组的地址与取首元素的地址打印出来的值一模一样。
    这是因为无论是取首元素地址,还是取整个数组的地址,它们的值都是从首元素的地址开始的。
    但是我们平时写代码的时候要知道,数组名前+取地址符号是取整个数组的地址。
    如果我们想看看它们的区别还是可以看到的,我们给首元素的地址、整个数组分别都+1:
    在这里插入图片描述
    在这里插入图片描述
    我们发现,前两个地址+1都只跳过了一个整形的大小,而第三个地址+1却跳过了一个数组的大小(40个字节)
    所以我们将三个地址打印出来只能看到打印出来的值是一样的,但是类型绝对是不同的,因为int*类型+1跳过的应该是一个整形,而不是40个字节。

除此之外,任何地方使用数组名,数组名都表示首元素的地址。


使用指针访问数组

有了前面知识的支持,再结合数组的特点,我们就可以很方便的使用指针访问数组了。
为什么在访问数组的时候可以使用指针呢?
1.因为数组在内存中是连续存放的,只要是连续存放的,只要找到第一个,就可以顺藤摸瓜找到其他的了。
2.指针±整数的运算,方便我们获得每一个元素的地址

接下来我们写个代码,实现用指针访问数组,给数组的每个元素输入值,再输出值。在这里插入图片描述
注意:
数组就是数组,是一块连续的空间(数组的大小与元素个数和元素类型都有关系)
而指针(变量)就是指针(变量),是一个变量(通常是4/8个字节)
那么它俩之间的联系是什么呢?
数组名是地址,是首元素的地址,可以使用指针来访问数组

拓展:
我们知道arr[i]*(arr+i)这两种写法是完全等价的,并且*(arr+i)里面的式子是加法,加法是支持交换律的。所以arr[i]==*(arr+i)==*(i+arr)
我们代入代码中看会不会错:
在这里插入图片描述
结果也是正确的。
既然这三个等价:arr[i]==*(arr+i)==*(i+arr)
*(arr+i)可以写成arr[i],那么*(i+arr)可不可以写成i[arr]呢?
我们带入代码试试:
在这里插入图片描述
我们发现即使是这样程序也没有问题。那么这说明了什么呢?
我们知道[]是个下标引用操作符,既然加号操作符+可以实现:1+2可以写成2+1;那么,arr[i]也就可以写成i[arr]
提示:这种方式虽然可行,但是不推荐。
因为这样写不利于阅读代码。


一维数组传参的本质

数组我们学过,数组是可以传递给函数的,现在我们讨论一下数组传参的本质。
首先从第一个问题开始:
写个函数实现数组元素的打印,我们之前都是在函数外部计算数组元素的个数:
在这里插入图片描述
那我们可以只把数组传给函数,少传一个参数。然后在函数内部求数组的元素个数再打印数组嘛?在这里插入图片描述
此时我们这样写却出现错误,数组里的元素只打印了一个,这是为什么呢?我们进行调试:

  • 按F11开始调试,创建数组执行完后打开监视,查看创建的数组有没有问题:
    在这里插入图片描述
  • 发现创建数组没有问题后按F11进入函数内,在监视里输入arr,10查看数组传参有没有问题:在这里插入图片描述
    此时数组的传参也没有问题,我们继续调试。
  • 当我们继续往下执行的时候却发现原本期望的值是10,这里sz却显示的是1在这里插入图片描述
    如果sz是1的话,在下面循环中只能循环一次,所以也就只能打印第一个元素的。
    此时就找到了问题所在,是sz出问题了。

所以这为什么会算错呢?
我们之前讲过,数组传参有两个例外:sizeof(数组名)&数组名
只有这两种例外表示的是整个数组,而现在这段代码中的Print(arr)并不算这两种情况,所以此时传的是首元素的地址。

那我们将首元素的地址传过去,Print()函数接收不应该用指针嘛?在这里插入图片描述
这个函数接收的正确写法就应该是int* p这样的指针来接收。

那为什么我们之前用int arr[10]这样数组的形式去接收呢?
因为数组传参的时候,形参的部分是可以写成数组的形式的。对于我们之前初学来说,传的是数组,就用数组来接收,这样讲法对于我们初学接受度很好。
形参的部分虽然可以写成数组的形式,但是本质上还是指针变量(地址)。就相当于这个地方是int* arr在这里插入图片描述
既然Print()不属于那两种例外,所以传的就是个地址,形参也就是个指针变量。
那么下面的sizeof(arr)就不是求一个数组的大小了,而是求一个指针变量的大小:在这里插入图片描述
x86的环境下,无论什么类型的指针,都是4个字节。

所以数组传参的时候,形参是可以写成数组的形式的,但是本质上还是一个指针变量(地址),下面要求大小的时候sizeof(arr)求的就不是一整个数组的大小,而是首元素地址的大小。
所以int sz = sizeof(arr) / sizeof(arr[0])是得不到元素个数的

还有一点要说明:
我们说数组传参的时候传的是首元素的地址(假设是0x0012ff40),所以传给函数的地址也是0x0012ff40
所以我们在这个函数里使用的都是0x0012ff40这个地址在这里插入图片描述
既然实参使用的是0x0012ff40,形参也是使用0x0012ff40,那么实参跟形参使用的数组不就是一样的嘛?
所以我们得到以下结论:

  • 数组传参的本质是传递了数组首元素的地址,所以形参使用的数组跟实参使用的数组一定是同一个数组。
  • 既然形参使用的数组跟实参使用的数组是同一个数组,所以形参的数组是不会单独再创建数组空间的,形参的数组是可以省略掉数组大小的:在这里插入图片描述
    在这里插入图片描述
    注意:无论形参部分写不写10,都不影响下面int sz = sizeof(arr) / sizeof(arr[0])这个表达式(正确写法时这个表达式一定要放在函数外面!)

接下来我们将这段错误代码改过来:
1.既然数组传的是地址,函数的形参就写成指针
2.求数组元素的表达式放在函数外面
正确代码:
在这里插入图片描述


冒泡排序

冒泡排序解决的是排序的问题。
冒泡排序的核心思想就是:两两相邻的元素进行比较。
假设我们这里有一串降序的数字:9 8 7 6 5 4 3 2 1 0
我们要排成升序:0 1 2 3 4 5 6 7 8 9 ,此时该怎么用冒泡排序排成升序呢?
在这里插入图片描述
在这里插入图片描述
就这样一对一对的比较下去,最后9会到最后:
在这里插入图片描述
因为9是最大的一个元素,所以它无论与谁进行比较,都来到最后一位。
这样将9放在最后,我们叫做一趟冒泡排序
所以剩下该解决9前面的数字
在这里插入图片描述
所以,一趟冒泡排序解决一个数字。第一趟解决了最大的,第二趟解决了次大的…
那么这个地方有10个元素,要有几趟冒泡排序呢?
9趟。因为前9个数字在进行冒泡排序后,最后一个数字应该已经在它们应该在的位置上了。
所以是n个元素的时候,我们需要进行n-1趟冒泡排序。

我们开始写代码进行实现:

  • 先将元素和排序的函数创建出来在这里插入图片描述

  • 当我们把排序函数名字写好之后就是传参了,因为我们要排的是这个数组,所以数组需要传进函数。
    并且冒泡排序的趟数得依据元素的个数,而函数内部不能求元素个数,所以得在主函数里面求元素的个数在这里插入图片描述

  • 接下里写冒泡排序里的内容

    • 写形参:指针接收数组(用数组形式也行),int sz接收元素个数。
      因为这个函数只用排好序就行了,所以返回类型写个void就可以了。在这里插入图片描述

    • 因为冒泡排序是一趟解决一个元素,所以首先要考虑趟数在这里插入图片描述
      上面我们说过,当有n个元素的时候,我们需要进行n-1趟冒泡排序,所以i<sz-1

    • 趟数确定后就思考一趟的排序过程:
      一趟排序的过程就是两个相邻元素之间相比较,我们创建一个变量j视为元素下标,使得相邻两元素之间相比较。在这里插入图片描述

    • 接下来我们分析:一趟冒泡排序要进行多少对比较。
      以上面的例子来说,当我们进行第一趟冒泡排序的时候,待排序的元素有10个,需要进行9对比较在这里插入图片描述
      所以代码循环次数可以写成这样,控制9次相邻元素进行比较
      在这里插入图片描述
      但是我们发现:当我们进行第二趟冒泡排序的时候,待排序的元素只有9个,需要进行的是8对比较在这里插入图片描述
      所以比较次数也与趟数有关:
      当第一趟冒泡排序时有10个待排元素,我们要进行9对比较;
      当第二趟冒泡排序时有9个待排元素,我们要进行8对比较;
      即第三趟冒泡排序时有8个待排元素,我们要进行7对比较…
      所以我们将循环次数改为:j<sz-1-i(因为i控制了趟数)
      在这里插入图片描述
      此时当第一趟冒泡排序的时候,就可以进行9对比较;第二趟冒泡排序的时候,就可以进行8对比较了…

  • 在冒泡排序函数执行完之后,我们写个函数将这个被排完序的数组打印出来:
    在这里插入图片描述

完整的代码为:

void bubble_sort(int arr[], int sz)
{//趟数int i = 0;for (i = 0; i < sz - 1; i++){//一趟排序的过程int j = 0;for (j = 0; j <sz-1-i ; j++){if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}void print_arr(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ",arr[i]);}
}int main()
{int arr[] = {9,8,7,6,5,4,3,2,1,0};//排序int sz = sizeof(arr) / sizeof(arr[0]);//元素个数bubble_sort(arr,sz);//打印print_arr(arr,sz);return 0;
}

打印出的结果:
在这里插入图片描述
注意:这段代码是可以优化的。
当需要排序的数组本身是接近有序的情况时:9 0 1 2 3 4 5 6 7 8,此时只需要进行一趟冒泡排序就可以变成:0 1 2 3 4 5 6 7 8 9 在这里插入图片描述
那我们该怎么进行优化呢?

  • 我们定义一个变量flag,在进行每趟冒泡排序之前都假设这趟元素已经有序:在这里插入图片描述

  • 如果这趟数组不是有序的,将flag改为0:
    例如9 0 1 2 3 4 5 6 7 8这个数组第一趟冒泡排序时9与0交换了,所以这趟并不是有序的,就将flag改为0,进行下一趟的比较。
    在这里插入图片描述

  • 下一趟全部比较完后发现并没有进入到if语句中(0 1 2 3 4 5 6 7 8 98次比较全部不符合if中的表达式,没进入if语句中),所以flag还是为1,此时就可以跳出循环,不再进行第3趟、第4趟的比较排序了。
    在这里插入图片描述
    注意:这个break跳的是这个循环,break是在这个循环里的
    在这里插入图片描述

所以,当任何一对元素交换了,就说明这一趟的元素不是有序的,就得进行下一趟的元素比较、交换。
若是下次没有元素的交换,就说明这一趟的元素就是有序的,不用再进行下一趟了,所以直接跳出循环。


二级指针

我们写段常见的代码:
在这里插入图片描述
这就是我们之前用的一级指针。
那么什么是二级指针呢?
我们根据上面这段代码画出图:
在这里插入图片描述
既然p也有地址,那么我们就可以通过&p拿到p的地址,然后放进变量pp里。此时pp就存放着一个一级指针变量的地址,我们叫pp二级指针
在这里插入图片描述在这里插入图片描述

那么pp的类型该怎么写呢?
pp的类型为int**,完整写法:int** pp=&p;
对于这个类型int**我们该怎么去理解呢?
首先我们要知道,int**是二级指针的类型。在这里插入图片描述
所以一级指针与二级指针的类型理解思路是一样的,分两部分理解:

  • 最后一个*说明该变量是指针
  • 前面一部分说明该变量指向的对象类型

那么,此时p+1pp+1各自跳过几个字节呢?
我们知道,指针±整数与指针的类型有关。因为p是整形指针,指向的对象为整形,所以p+1跳过4个字节。
那么pp+1呢?
因为pp指向的是int*类型的变量,也就是指针变量。
所以我们就要看指针变量的大小为多少,就跳过几个字节。有可能是4个字节,也有可能是8个字节。
在这里插入图片描述
如果我们想取出pp的地址可以吗?
当然是可以的,此时得写成:int*** ppp=&pp;
同样的:int**说明ppp指向的对象(pp)是int**类型的,最后一个*说明ppp是指针变量。此时ppp就是一个三级指针。在这里插入图片描述
可以一直往下推,但是不建议。

那么二级指针到底是怎么样用的呢?
如果我们要通过pp找到p有什么办法呢?
解引用ppp的地址打印出来:
在这里插入图片描述

*pp——访问pp里存的地址,找到这个地址后拿该地址里的数据(对pp里的地址进行解引用)

我们也将a的地址打印出来,看看*pp的值是不是a的地址
在这里插入图片描述
发现值确实一样。
我们通过对二级指针解引用,可以找到一级指针内存的数据,再进行解引用,就可以找到10了.

*pp==p==&a;
//通过对pp里的地址解引用找到p(a的地址)
//对*pp再次解引用:
**pp==*p=10

在这里插入图片描述
所以,对二级指针变量两次解引用可以间接的找到10.


指针数组

指针数组是指针还是数组呢?
答案是数组。
我们类比一下:整型数组,是存放整型的数组;字符数组,是存放字符的数组。在这里插入图片描述

所以指针数组,是存放指针的数组。
在这里插入图片描述
指针数组的每个元素都是地址,可以指向⼀块区域

那么指针数组有什么用呢?
我们可以用指针数组模拟二维数组。


指针数组模拟二维数组

举例:
在这里插入图片描述
当我们写下这样的代码的时候,我们知道,这三个数组各自是一块内存空间,在内存里也并不是连续存放的,可能离得很远。

如果我们想把这三块空间弄成二维数组:将这三个数组分别当成二维数组的第一行、第二行、第三行。

我们该怎么办呢?
因为数组名是首元素的地址,我们将这三个数组首元素的地址放入到一个指针数组arr中,通过访问这个指针数组,再访问到这三个数组。
这样就可以模拟出一个二维数组了:
在这里插入图片描述
当我们写上arr[0]的时候,就是访问arr数组中arr1这个元素,而这个元素是arr1数组首元素的地址,所以我们就可以在这个地址的基础上进行+整数,进行arr1数组元素的遍历。
同理,当我们写上arr[1]的时候,就是访问arr数组中arr2这个元素,而这个元素是arr2数组首元素的地址,所以我们也就可以找到arr2数组中的每个元素了…

//可以看作访问第一行所有元素
arr[0][j];  j:0~4//访问第二行所有元素:
arr[1][j];  j:0~4//访问第三行所有元素:
arr[2][j];  j:0~4

这样就实现了指针数组模拟二维数组

因为arr1共有5个元素,首元素地址+0为元素1的地址,首元素+1为元素2的地址…首元素+4就为元素5的地址了,所以整数j的取值范围就为0~4

我们继续写代码:
在这里插入图片描述
实现了每个元素的打印。

注意:这种写法并不是真的二维数组,真的二维数组在内存中是连续存放的,而这种写法只是通过地址将三个分散的数组看为三行,再进行打印,这里的arr并不是真的二维数组。

那么既然arr并不是真的二维数组,那么代码中的打印为什么要写成二维数组的形式呢?
在这里插入图片描述
因为:在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Windows系统中安装Open WebUI并连接Ollama

Open WebUI是一个开源的大语言模型&#xff08;LLM&#xff09;交互界面&#xff0c;支持本地部署与离线运行。通过它&#xff0c;用户可以在类似ChatGPT的网页界面中&#xff0c;直接操作本地运行的Ollama等大语言模型工具。 安装前的核心要求&#xff1a; Python 3.11&#…

Day4:强化学习之Qlearning走迷宫

一、迷宫游戏 1.环境已知 迷宫环境是定义好的&#xff0c;障碍物位置和空位置是已知的&#xff1b; # 定义迷宫 grid [[0, 0, 0, 1, 0],[0, 1, 0, 1, 0],[0, 1, 0, 0, 0],[0, 0, 0, 1, 0],[0, 1, 1, 1, 0] ] 2.奖励方式已知 如果碰到障碍物则得-1&#xff0c;如果到终点则…

家里WiFi信号穿墙后信号太差怎么处理?

一、首先在调制解调器&#xff08;俗称&#xff1a;猫&#xff09;测试网速&#xff0c;网速达不到联系运营商&#xff1b; 二、网线影响不大&#xff0c;5类网线跑500M完全没问题&#xff1b; 三、可以在卧室增加辅助路由器&#xff08;例如小米AX系列&#xff09;90~200元区…

视点开场动画实现(九)

这个相对比较简单&#xff1a; void COSGObject::FlyTo(double lon, double lat, double hei) {theApp.bNeedModify TRUE;while(!theApp.bCanModify)Sleep(1);em->setViewpoint(osgEarth::Viewpoint("0",lon, lat, 0, 0, -45, hei), 2);theApp.bNeedModify FAL…

保姆级GitHub大文件(100mb-2gb)上传教程

GLF&#xff08;Git Large File Storage&#xff09;安装使用 使用GitHub desktop上传大于100mb的文件时报错 The following files are over 100MB. lf you commit these files, you will no longer beable to push this repository to GitHub.com.term.rarWe recommend you a…

HTML之JavaScript DOM(document)编程处理事件

HTML之JavaScript DOM&#xff08;document&#xff09;编程处理事件 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"…

Redis7——基础篇(四)

前言&#xff1a;此篇文章系本人学习过程中记录下来的笔记&#xff0c;里面难免会有不少欠缺的地方&#xff0c;诚心期待大家多多给予指教。 基础篇&#xff1a; Redis&#xff08;一&#xff09;Redis&#xff08;二&#xff09;Redis&#xff08;三&#xff09; 接上期内容&…

Sprinig源码解析

前言 Spring 框架是 Java 企业级开发的基石&#xff0c;其源码设计体现了模块化、扩展性和灵活性。以下从 IoC 容器、AOP 实现、核心模块和关键设计模式四个角度对 Spring 源码进行深度解析&#xff0c;帮助理解其底层机制。即使Spring会使用的人见得就能使用。 一、IoC 容器源…

如何简单的去使用jconsloe 查看线程 (多线程编程篇1)

目录 前言 1.进程和线程 进程 PCB 的作用 并发编程和并行编程 线程 为什么选择多线程编程 2.在IDEA中如何简单创建一个线程 1. 通过继承Thread类 2. 通过实现 Runnable 接口 3. 使用 Lambda 表达式 3.如何简单使用jconsloe去查看创建好的线程 前言 2025来了,这是第…

【ISO 14229-1:2023 UDS诊断(ECU复位0x11服务)测试用例CAPL代码全解析④】

ISO 14229-1:2023 UDS诊断【ECU复位0x11服务】_TestCase04 作者&#xff1a;车端域控测试工程师 更新日期&#xff1a;2025年02月17日 关键词&#xff1a;UDS诊断协议、ECU复位服务、0x11服务、ISO 14229-1:2023 TC11-004测试用例 用例ID测试场景验证要点参考条款预期结果TC…

3.10 实战Hugging Face Transformers:从文本分类到模型部署全流程

实战Hugging Face Transformers:从文本分类到模型部署全流程 一、文本分类实战:IMDB电影评论情感分析 1.1 数据准备与预处理 from datasets import load_dataset from transformers import AutoTokenizer # 加载IMDB数据集 dataset = load_dataset("imdb") …

【人工智能】释放数据潜能:使用Featuretools进行自动化特征工程

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 特征工程是机器学习流程中至关重要的一步,它直接影响模型的性能。然而,手动特征工程既耗时又需要领域专业知识。Featuretools是一个强大的…

MybaitsPlus学习笔记(二)基本CURD

目录 一、BaseMapper 二、常用实例 1、插入 2、删除 3、修改 4、查询 三、IService 四、 IService中的一些方法测试 一、BaseMapper MyBatis-Plus中的基本CRUD在内置的BaseMapper中都已得到了实现&#xff0c;我们可以直接使用&#xff0c;接口如 下&#xff1a; publ…

设计模式之适配模式是什么?以及在Spring AOP中的拦截器链的使用源码解析。

前言 本文涉及到适配模式的基本用法&#xff0c;以及在Spring AOP中如何使用&#xff0c;首先需要了解适配模式的工作原理&#xff0c;然后结合Spring AOP的具体实现来详细详细解析源码。 首先&#xff0c;适配模式&#xff0c;也就是Adapter Pattern&#xff0c;属于结构型设计…

【C++】36.C++IO流

文章目录 1. C语言的输入与输出2. 流是什么3. CIO流3.1 C标准IO流3.2 C文件IO流 4. stringstream的简单介绍 1. C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键盘)读取数据&#xff0c;并将值存放在变量中。pri…

JavaScript表单介绍

一、表单的基本概念 在网页开发里&#xff0c;表单是实现用户与网页交互的关键组件&#xff0c;用于收集用户输入的数据&#xff0c;JavaScript 则能为表单增添强大的交互性和功能性。表单在 HTML 里通过 <form> 标签创建&#xff0c;包含多种表单元素&#xff0c;如文本…

哈希表(C语言版)

文章目录 哈希表原理实现(无自动扩容功能)代码运行结果 分析应用 哈希表 如何统计一段文本中&#xff0c;小写字母出现的次数? 显然&#xff0c;我们可以用数组 int table[26] 来存储每个小写字母出现的次数&#xff0c;而且这样处理&#xff0c;效率奇高。假如我们想知道字…

昆虫-目标检测数据集(包括VOC格式、YOLO格式)

昆虫-目标检测数据集&#xff08;包括VOC格式、YOLO格式&#xff09; 数据集&#xff1a; 链接: https://pan.baidu.com/s/1tYb8s-AVJgSp7SGvqdWF9A?pwdt76a 提取码: t76a 数据集信息介绍&#xff1a; 共有 6009 张图像和一一对应的标注文件 标注文件格式提供了两种&#x…

C++(23):unreachable

C++23在头文件 "><utility>定义了std::unreachable(),用于指示编译器,该段代码不应该被允许,因此编译器可以对该位置进行优化,如果一旦允许了该位置的代码,行为未定义: #include <utility> #include <iostream>using namespace std;int func(…

备战蓝桥杯 Day1 回顾语言基础

开启蓝桥杯刷题之路 Day1 回顾语言基础 1.配置dev 工具->编译选项->勾选编译时加入以下命令->设定编译器配置(release和debug)都要-> -stdc11 ->代码生成/优化->代码生成/优化->语言标准(-std)->ISO C11 ->代码警告->显示最多警告信息(-Wall)…