【Linux系统】—— 编译器 gcc/g++ 的使用

【Linux系统】—— 编译器 gcc/g++ 的使用

  • 1 用 gcc 直接编译
  • 2 翻译环境
    • 2.1 预处理(进行宏替换)
    • 2.2 编译(生成汇编)
    • 2.3 汇编(生成机器可识别代码)
    • 2.4 链接
    • 2.5 记忆小技巧
    • 2.6 编译方式
    • 2.7 几个问题
      • 2.7.1 如何理解条件编译
      • 2.7.2 为什么编译器要先将代码翻译成汇编语言

1 用 gcc 直接编译

  我们平时学的 C/C++ 代码,都是文本文件,但是我们知道计算机只认识二进制,因此我们需要将C/C++代码翻译成二进制文件

  在 Windows 系统中,编辑代码和翻译过程我们都是用 VS 进行的,因为 VS 是集成的IDE环境,那么在 Linux 中我们又该如何完成代码的翻译工作呢?

  在 Linux 中,我们用到的编译器是 gcc/g++,其中gcc是对C语言进行编译,g++是对C++进行编译。因为 gcc 和 g++ 的指令操作等完全一样,本文主要是用 gcc 进行演示。
  
  我们创建一个 test.c 文件,写上代码:

#include<stdio.h>
 
int main()
{
     printf("hello world\n");
     printf("hello Linux\n");
     return 0;
}

  
  如何用 gcc 对代码进行编译呢?

指令如下:

  • 「gcc」 「要编译的文件」

  
  gcc 会默认生成一个叫 a.out 的可执行文件

在这里插入图片描述

  
  那如果我想指定生成文件的名字呢?

有两种方法

  1. 「gcc 」「要编译的文件」 「-o」 「目标文件」
  2. 「gcc 」 「-o」 「目标文件」「要编译的文件」
      
    在这里插入图片描述

  但是,仅仅学会指令是远远不够的,我们学习 gcc/g++ 更重要的是学习翻译过程背后的过程,我们知道,我们写的 C语言 代码最终要形成可执行程序,要经过预处理编译汇编链接这几个过程,下面我们通过 gcc,进一步认识这四个过程。
  
  

2 翻译环境

2.1 预处理(进行宏替换)

  预处理阶段主要处理那些源文件中 # 开始的编译指令。比如:# i n c l u d e include include,# d e f i n e define define,处理的规则如下:

  • 将所有的 # d e f i n e define define 删除展开所有的宏定义
  • 处理所有的条件编译指令,如:#if#ifdef#elif#else#endif
  • 处理 # i n c l u d e include include 预编译指令,将包含的头文件的内容插入到该预编译指令的位置。这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件。
  • 删除所有注释
  • 添加行号文件名标识,方便后续编译器生成调试信息等

  
  我们创建一个code1.c文件、写一段代码

在这里插入图片描述

  这一小段代码,头文件、宏定义、注释以及条件编译都有了,正好可以看看预处理的效果。
  

我们如何看到预处理后的结果呢?我们来学一个选项 「-E 」

  • 「-E 」:进行程序翻译,在预处理做完时停下来
      

指令如下:

  • 「gcc 」「-E 」「要编译的文件」 「-o」 「目标文件」

  :预处理后的文件后缀为.i

在这里插入图片描述

  
  我们用 vim 打开 code.i 来看看

在这里插入图片描述

  

  1. 我们发现注释不见了
  2. 我们定义的宏M和N,预处理后也消失不见了,M直接别替换成100,这叫做宏替换
  3. 并且printf("hello N\n")printf("no N\n")只剩下了printf("hello N\n") 。这是因为条件编译,我们定义了N(定义了就行,可以不写值),所以预处理后保留了printf("hello N\n")
  4. 为什么我们的文件变大了呢?根本原因就是头文件展开。 在编译的时候,只要预处理完了,头文件就可以不需要了。头文件展开的意思就是把你要包含的头文件全部拷贝至你的目标文件里,形成 .i 文件。这不过这个 .i 文件我们现在将其打印出来并且写到文件里了,如果不写的话它就是内存级的,在编译器内部。同时 <stdio.h> 头文件中也包含其他的头文件,因此它会类似递归式的拷贝

  因此一个你可能只写了几百行的代码,预处理后可能有上千行。

  我们 C语言 用到的众多头文件,在系统中默认都是安装了的,一般是存在 /usr/include 路径下

在这里插入图片描述

  
  如:我们包含的头文件 <stdio.h> 一般是存在/usr/include/stdio.h 路径下

在这里插入图片描述

  
  可以用 vim 打开来看看

在这里插入图片描述

  里面的代码近 900 行,但是它有条件编译,同时 <stdio.h> 中本身也包含了其他的头文件。


  这里,我问大家一个问题,预处理后的 code1.i 还是 C语言 吗?
  答案:还是C语言
  不过他是一个已经预处理过,是一个干净的C语言了。
  

2.2 编译(生成汇编)

  编辑将C语音翻译成汇编语言
  编译过后,生成的汇编文件后缀为 .s

需要用到命令行选项 「-S 」

  • 「-S 」:从现在开始进行程序翻译,在编译步骤做完时停下来 指令如下:
  • 「gcc 」「-S 」「要编译的文件」 「-o」 「目标文件」

  我们可以从 .c 到 .s 也可以从 .i 到 .s,因为之前已经做过 .c 到 .i 了,就不再重复做预处理步骤, 直接 .i.s

在这里插入图片描述

  
  我们用 vim 打开 code1.s

在这里插入图片描述

  
  

2.3 汇编(生成机器可识别代码)

  汇编是指通过汇编器将汇编代码转变成机器可执行的指令,每一个汇编语句几乎都对应一条机器指令。就是按照汇编指令和机器指令的对照表一一的进行翻译,也不做指令优化。

先直接上指令

  • 「gcc 」「-c 」「要编译的文件」 「-o」 「目标文件」
      

如:

  • gcc -c code1.s -o code1.o
      
  • 「-c 」:从现在开始进行程序翻译,在完成汇编后停下来

  以 .o 为后缀的文件全称叫:可重定位目标文件,也就是我们所说的目标文件。目标文件在 Windows 系统下是以 .obj 结尾的

  目标文件是二进制文件,因此我们打开它是啥都看不懂的

在这里插入图片描述

  虽说 code1.o 已经是二进制文件,但是它还是无法被执行的。因为目标文件仅仅是将我们自己写的代码编成二进制了,可我们的程序中还包含着许多库方法,如printf、scanf、STL容器,此时我们的程序还没有和库方法关联起来,比如我们用了 printf 方法,可我们根本没有 printf 方法的实现,所以我们的目标文件是跑不动的。

  所以我们的程序还要经过最后一步:链接,才能形成可执行文件

  
  

2.4 链接

  链接过程没有命令行选项

指令如下:

  • gcc code1.o -o code1

  这里我们并没有指定去链接哪个库,因为我们现在的代码里没有使用任何的第三方库,我们用的都是C语言标准库的方法,gcc会帮我们去系统里找我这个程序用了 C语言 的哪个标准库。但如果我们要依赖某个第三方库,就需要指定去链接了,这点我们以后再介绍。
  生成可执行序后,程序就可以运行了

在这里插入图片描述

  

2.5 记忆小技巧

  好像预处理、编译、汇编这三步的命令行选项很难记?有什么记忆方法吗?

  他们分别是 「-E 」「-S 」「-c 」
  合起来就是键盘左上角的「esc」键,我只需要记住前两个是大写的就行了。

  而预处理、编译、汇编这三步生成的文件后缀又怎么记呢?
  他们分别是『.i』『.s』『.o』
  连起来就是iso,我们可以记ios,再将后面两个反过来
  
  

2.6 编译方式

  一般我们在编译文件时,不会像上面一样 .i.s.o全部生成一遍,上述这样做只是为了然我们了解整个翻译的过程。

  我们编译文件的习惯是将所有的文件生成 .o 文件,再将所有相关的 .o 文件一起打个包生成可执行文件

在这里插入图片描述

  
为什么喜欢这么做呢?
主要原因是:

  1. 编译器在编译时,不仅仅要形成可执行程序,还可能要形成库(所谓的库其实就是把 .o 文件了个包),如果要形成库的话就不需要编译性成可执行程序
  2. 我们目前使用的 VS 最终就形成一个可执行程序,但往往实践中可能形成 10 个、100 个可执行程序,可能你有 1000 个源文件,其中 100 个形成程序A、50 个形成程序B、60 个形成程序C……我们需要将所有的 .o 做自由组合,形成多个可执行。在编译角度,我们可先将你们全部变成 .o,最后如何形成可执行,再自己做组合
      

为什么要有链接步骤呢?

  这是因为我们要站在巨人的肩膀上
  例如我们要用到的输入输出函数,要是自己来写的话那太费劲了,每做一个项目都要自己先敲一个函数出来,而且写出来也不够好,容易出问题。因此C语言将最基本的功能给我们全部开发好,再打成包,这个包就是库
  解下来我们写代码时,我们只需要将自己的代码编译好,和C语言标准库链接形成可执行就行
  


有小伙伴可能会问:预处理时不是已经展开头文件了吗?为什么还要链接呢?

  预处理展开的仅仅只是声明,因为头文件时公开的。
  其实我们包的头文件源代码都是公开的,只有声明没有实现,实现在对应的同名 .c 文件里。.c 文件 C语言 没有给你暴露出来,直接编成库了。
  要最终形成可执行,重要的是方法,而链接就是将方法找到


  当然,上述讲的只是一般情况,你要是不喜欢也可以一次就形成可执行文件
  
  

2.7 几个问题

2.7.1 如何理解条件编译

  我们创建 code.c 文件,写下如下代码

在这里插入图片描述

  
  根据我们前面的知识,我们知道此时我们并没有定义M,执行的应是printf("社区版/免费版 version1\n")语句
  我们执行一下看看

在这里插入图片描述

  


  gcc 编译时支持我们用 「-D 」 来进行命令行级别对指定源代码进行动态添加宏

如:
定义加写值

  • gccgcc code.c -o code.exe -DM=1
      

只定义不写值

  • gccgcc code.c -o code.exe -DM

  

在这里插入图片描述

  gcc不用「-D 」选项定义宏它又会变成免费版

在这里插入图片描述

  
  gcc这合理吗?其实是合理的
  gcc编译器进行编译时第一步就是预处理,预处理的本质其实就是 让编译器编辑(修改)我们的代码! 既然预处理时,编译器能去注释,能进行宏替换,那么编译器将命令行中的 -DM 解释成 #define M ,并将其当做字符串插入到我的代码当中不过分吧。
   「-D 」相当于在命令行给代码定义宏
  


  相信对条件编译大家都能理解,大家不理解的是条件编译的用途。下面我们简单来了解一下条件编译的应用场景

  • 对一款软件通过专业读、收费标准等进行区分,使用条件编译,进行代码的动态裁剪:
    我们平时看到的某些软件,像VS、Xshell等,往往都分为专业版和社区版(收费版和免费版)。他们两者的区别主要是在功能方面,比如收费版支持100个功能,而免费版只支持50个功能。
    这些软件也都是程序员开发的,那么程序员在维护这款软件需要维护几份源代码呢?毕竟这款软件有两个版本。
    事实上,如果将同一款软件的免费版和收费版当成两个项目来看,那么公司就需要有两套班子,但其实他们功能上无非就是收费版上做一下功能的裁剪就是免费版。
    所以在公司内部我们只需要维护一份源代码即可,最终在发布的时候只需要告诉别人编译这个代码时,编译成免费的还是收费的。怎么才能做到这点呢?我们可以将软件中的功能拆分一下:公共都有的放在一个模块里,需要收费的放在一个模块里,最后用条件编译将其维护起来。
    这样一份代码通过条件编译就能对其进行裁剪,从而实现对内只需维护一份源代码,对外实现多份版本的目的。

  • Linux 内核源代码也是采用条件编译进行点裁剪
    我们的 Linux 内核,编译好了其实体积还是很大的,但有些功能在很多的小型设备上:嵌入式设备、智能家电等,上面根本就不需要Linux支持那么多功能,这时就可以用条件编译实现代码的动态裁剪

  当然,条件编译的功能远远不仅于此,但大多应用场景离我们现在的水平太远,感兴趣的小伙伴可以自行深入了解。

  
  

2.7.2 为什么编译器要先将代码翻译成汇编语言

  C语言翻译成二进制指令相信大家都能理解,因为机器只认识二进制。但为什么编译器要先将C语言翻译成汇编语言,再将汇编语言翻译成二进制呢?


为什么计算机只认识二进制

  简单来说是因为 0 和 1 是最简单的硬件电路,简单就意味着可靠,计算机通过与非门各种各样的门电路组合成各种复杂电路。
  


这里讲一下计算机的发展史
  
  计算机都是要进行输入输出的:我们将数据喂给它,它处理完后将结果返回。我们编程的本质就在在控制计算机,我们编译代码其实就是在要求计算机帮我们做这做那
  早期的计算机都是非常大的,而且其运算力非常差。早期我们没有编程,控制计算机用的是计算机上的开关,早期的计算机科学家都是在计算机前掰来掰去的,其实就是在通过开关来给计算机输入 0 和 1

  后来人们觉得开关的方式不太好,到了五六十年代,人们开始用打孔编程。

在这里插入图片描述

打孔纸带

  打了孔的地方,光能透过去,我们认为是1,否则为0。《三体》中,叶文洁向外星人发送信号时,手上捏着一条纸带,就是这个东西
  
  但打孔编程本质依然是二进制编程,二进制编程可是很恶心的。而且打孔打错了,纸就报废了,要重新打孔,浪费纸张不说还效率低下。后来人们发明了一种编程语言:汇编语言
  用汇编语言控制计算机效率无疑比直接二进制编程高很多。
  从我们的汇编语言开始,就需要一个东西:编译器。因为汇编语言本质上也是文本,所以我们需要一种编译器将汇编语言编译成对应的二进制
  


这里有个问题:第一个汇编语言编译器是用什么写的呢?
  这个编译器要编译汇编语言,那编译器自己应该用什么语言来写呢?
  用汇编吗?你用还没法翻译成二进制的汇编,来将汇编翻译成二进制,这不鸡蛋和鸡吗?

  因此第一版编译汇编的编译器,是用二进制写的。先用二进制写一个二进制版的汇编编译器。有了第一个编译器,此时就可以编译汇编语言了,此时我们就可以用汇编语言写一份汇编版本的编译器,第一版的编译器就可以不要了,此后我们就可以用自己语言写的编译器编译自己语言。这个过程叫做编译器的自举过程
  不仅如此,语言也是可以自举的。比如C++推出C++11,但此时的编译器只支持C++98,这时就可用98写个能编11的编译器,再用C++11进行重写

  最早期的,比较好的操作系统叫 Unix,它第一版本就是由肯·汤普逊用汇编语言写出来的,后来丹尼斯里奇发明了 C语言,肯·汤普逊和丹尼斯里奇即一起用C语言把 Unix 进行重构,发布的 C语言 版本的 Unix。我什么肯·汤普逊最开始用汇编语言写,因为最开始只有汇编,后来 C语言 出来了,C语言 对应的编译器也诞生了,为了代码本身的可维护性,他就把 Unix 操作系统调整为 C语言 了。
  


  再后来,人们觉得汇编语言也太麻烦,所以基于汇编语言产生了许多分支,编译型语言在那个阶段就开始爆发了。最典型的就是 70 年代产生的 C语言,再到后来的 C++/java/go
  

在这里插入图片描述

  
  现在有了 C语言,C语言 最终肯定也要翻译成二进制。现在的问题是,我们是直接将C语言翻译成二进制还是先翻译成汇编语言再翻译成二进制。
  我们肯定会选择方案二。为什么呢?

  首先将C语言翻译成汇编语言,毕竟还是从文本到文本,它的翻译难度相对较低;其次,在C语言产生之前,汇编语言已经发展了很多年了,我们只需要将C翻译成汇编,而将汇编翻译成二进制这项工作已经发展的很成熟,可以不用做了,我们可以站在巨人的肩膀上
  如果直接将 C 翻译成二进制,那么翻译的成本会特别高,而且 C++ 等后来者是基于C语言发明出来的,你让我 C++ 怎么办,难道我 C++ 也要直接翻译成二进制吗?
  我们要学会站在巨人的肩膀上,计算机每一阶段的发展都经过了十几年,我们要将每一阶段的发展好好用上。

  而编译是逆历史的过程:C语言 -> 汇编 -> 二进制
  

在这里插入图片描述

  
  
  
  


  好啦,本期关于编译器 gcc/g++ 就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在 Linux 的学习路上一起进步!

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

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

相关文章

LARGE LANGUAGE MODELS ARE HUMAN-LEVEL PROMPT ENGINEERS

题目 大型语言模型是人类级别的提示工程师 论文地址&#xff1a;https://arxiv.org/abs/2211.01910 项目地址&#xff1a;https://github.com/keirp/automatic_prompt_engineer 摘要 通过对自然语言指令进行调节&#xff0c;大语言模型 (LLM) 显示了作为通用计算机的令人印象深…

计算机的错误计算(二百一十八)

摘要 大模型能确定 sin(2.6^100) 的符号吗&#xff1f;实验表明&#xff0c;大模型给的结论是正确的&#xff0c;但其证明过程是错误百出。大模型的推理实在是不敢恭维。 就同样题目&#xff0c;测试一下另外一个大模型。 例1. 能确定 sin(2.6^100) 的符号吗&#xff1f; 下…

51c~SLAM~合集1

我自己的原文哦~ https://blog.51cto.com/whaosoft/12327374 #GSLAM 自动驾驶相关~~~ 一个通用的SLAM架构和基准 GSLAM&#xff1a;A General SLAM Framework and Benchmark 开源代码&#xff1a;https://github.com/zdzhaoyong/GSLAM SLAM技术最近取得了许多成功&am…

【2024年终总结】我与CSDN的一年

&#x1f449;作者主页&#xff1a;心疼你的一切 &#x1f449;作者简介&#xff1a;大家好,我是心疼你的一切。Unity3D领域新星创作者&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6; &#x1f449;记得点赞 &#x1f44d; 收藏 ⭐爱你们&#xff0c;么么哒 文章目录 …

Day 14 卡玛笔记

这是基于代码随想录的每日打卡 226. 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;r…

51c大模型~合集105

我自己的原文哦~ https://blog.51cto.com/whaosoft/13101924 #刚刚&#xff0c;ChatGPT开始有了执行力&#xff01; 现在 AI 智能体可以 24*7 小时为你打工。 2025 刚过去了半个月&#xff0c;OpenAI 在智能体领域「开大」了。 今天&#xff0c;OpenAI 正在为 ChatGPT 推出…

《Effective Java》学习笔记——第2部分 对象通用方法最佳实践

文章目录 第2部分 所有对象通用方法一、前言二、最佳实践内容1. equals()方法2. hashCode()方法3. toString() 方法4. clone() 方法5. finalize() 方法6. compareTo()方法&#xff08;实现 Comparable 接口&#xff09; 三、小结 第2部分 所有对象通用方法 一、前言 《Effect…

国家统计局湖北调查总队副总队长张小青一行调研珈和科技农业遥感调查智能化算法

1月15日上午&#xff0c;国家统计局湖北调查总队党组成员、副总队长张小青一行莅临珈和科技开展调研。调研期间&#xff0c;张小青一行实地了解了珈和科技在自动化作物分布提取技术领域的最新成果&#xff0c;深入探讨了作物自动化处理模型在农业调查上应用的创新价值及优化方向…

2025-1-21 Newstar CTF web week1 wp

文章目录 week1headach3会赢吗智械危机 week1 headach3 根据提示&#xff0c;在页面的请求头里找到flag flag{You_Ar3_R3Ally_A_9ooD_d0ctor} 会赢吗 打开控制台&#xff0c;拿到第一部分flag 将地址栏改为提示&#xff0c;去到下一关 控制台调用函数&#xff0c;得到flag …

CPU狂飙900%如何分析?怎么定位?怎么溯源处理

当你的服务器CPU飙升到900%&#xff0c;系统卡顿、响应迟缓、业务受阻&#xff0c;这种令人焦虑的场景是否让你束手无策&#xff1f;别慌&#xff0c;这并不是世界末日&#xff0c;只要掌握正确的分析与定位方法&#xff0c;就能快速找到问题根源&#xff0c;并有效解决。 CPU…

leetcode919. 完全二叉树插入器,队列只保存右子树为空的节点

leetcode919. 完全二叉树插入器 完全二叉树 是每一层&#xff08;除最后一层外&#xff09;都是完全填充&#xff08;即&#xff0c;节点数达到最大&#xff09;的&#xff0c;并且所有的节点都尽可能地集中在左侧。 设计一种算法&#xff0c;将一个新节点插入到一棵完全二叉树…

Mysql安装,mysql-installer-community-8.0.41.0

“windowR"键弹出运行框&#xff0c;输入”cmd"进入window命令提示符&#xff0c;输入“mysql -uroot -p"按下回车&#xff0c;再输入密码&#xff0c;按下回车&#xff0c;出现下面界面则是配置成功。 默认会在 C:\Program Files\MySQL\MySQL Server 8.0\bin …

Linux内核编程(二十一)USB驱动开发-键盘驱动

一、驱动类型 USB 驱动开发主要分为两种&#xff1a;主机侧的驱动程序和设备侧的驱动程序。一般我们编写的都是主机侧的USB驱动程序。 主机侧驱动程序用于控制插入到主机中的 USB 设备&#xff0c;而设备侧驱动程序则负责控制 USB 设备如何与主机通信。由于设备侧驱动程序通常与…

1.21学习记录

misc 2023isctf 你说爱我尊嘟假嘟 这题有点脑洞&#xff0c;需要把你说爱我换成Ook.将尊嘟换为Ook&#xff01;假嘟换成Ook&#xff1f;&#xff08;根据语气进行猜测吧&#xff09;用在线工具解密最后用base64解密即可 2023isctf 杰伦可是流量明星 解压后是一个MP3文件&am…

BaseCTF_Misc_week3

目录 broken.mp4 白丝上的flag 这是一个压缩包 纯鹿人 外星信号 我要吃火腿 Base Revenge broken.mp4 附件两个MP4文件&#xff0c;第一个可以播放&#xff0c;内容是视频受损的修复啥的。第二个破损了&#xff0c;那么就根据第一个视频的网页名称搜索找到相应的网页&…

Flutter项目和鸿蒙平台的通信

Flutter项目和鸿蒙平台的通信 前言Flutter和Harmonyos通信MethodChannelBasicMessageChannelEventChannel 前言 大家在使用Flutter开发项目的时候&#xff0c; Flutter提供了Platfrom Channel API来和个个平台进行交互。 Flutter官方目前提供了一下三种方式来和个个平台交互&…

@TransactionEventListener的关键源码整理

前言&#xff1a;本篇文章不属于保姆级的&#xff0c;主要是方便自己回忆用的&#xff0c;所以需要阅读者具有一定的Spring源码基础。 总结&#xff1a; TransactionEventListener本质上还是EventListener&#xff0c;事件的发布还是Spring通用的那一套事件发布机制。EventLis…

StarRocks强大的实时数据分析

代码仓库&#xff1a;https://github.com/StarRocks/starrocks?tabreadme-ov-file StarRocks | A High-Performance Analytical Database 快速开始&#xff1a;StarRocks | StarRocks StarRocks 是一款高性能分析型数据仓库&#xff0c;使用向量化、MPP 架构、CBO、智能物化…

SpringBoot实现定时任务,使用自带的定时任务以及调度框架quartz的配置使用

SpringBoot实现定时任务&#xff0c;使用自带的定时任务以及调度框架quartz的配置使用 文章目录 SpringBoot实现定时任务&#xff0c;使用自带的定时任务以及调度框架quartz的配置使用一. 使用SpringBoot自带的定时任务&#xff08;适用于小型应用&#xff09;二. 使用调度框架…

蓝桥与力扣刷题(73 矩阵置零)

题目&#xff1a;给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]示例 2&…