[C/C++]指针详讲-让你不在害怕指针

  •  个人主页:北·海
  •  🎐CSDN新晋作者
  •  🎉欢迎 👍点赞✍评论⭐收藏
  • ✨收录专栏:C/C++
  • 🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!🤗

目录

前言

 一.&与*的作用与结合方向

二.指针和数组的关系

1.利用指针访问数组里的值

2.利用指针将数组作为实参传递给函数

 三.字符指针与字符数组

四.指针在内存分配中的应用

1.用C语言中的malloc在堆区分配动态内存

1.用C++中的new在堆区分配动态内存

五.使用指针为什么能提高程序的性能

六.指针与const搭配的四种情况

七.引用是实现原理

八.多级指针

九. 指针和函数的关系

1.通过指针使函数返回多个值

2.函数指针

3.函数的返回值类型为指针类型

十.指针和结构体的关系

 


前言

指针在编程语言中扮演着重要的角色,特别是在C语言中。指针提供了直接访问和操作内存地址的能力,使得编程更加灵活、高效,并且可以处理各种复杂的数据结构和算法。

以下是指针的几个重要方面和作用:

  1. 内存管理:指针允许程序直接与内存交互。通过使用指针,可以动态地分配和释放内存,避免了静态内存分配所带来的限制。这在处理动态数据结构(如链表、树、图等)和大规模数据中非常有用。

  2. 传递参数和引用:通过指针,可以在函数之间传递参数和引用。传递指针作为函数参数,可以避免在函数调用时产生副本,节省了内存和时间开销。此外,指针还可以用于函数返回多个值或修改调用者的变量。

  3. 动态数据结构:动态数据结构如链表、树、堆等通常需要使用指针进行内存分配和组织。指针可以在运行时创建、删除、连接和重新组织数据结构,使得数据结构的管理更加灵活和高效。

  4. 数组和字符串操作:在C语言中,数组实际上是通过指针来访问和操作的。指针使得数组可以直接访问和修改其元素,还可以进行指针算术操作,实现数组的遍历和操作。字符串在C语言中本质上是以空字符结尾的字符数组,指针的使用是对字符串进行处理的关键。

  5. 性能优化:指针的使用可以提高程序的性能。通过使用指针来访问和操作数据,可以减少副本的生成和数据的复制,提高程序的执行效率。


 一.&与*的作用与结合方向

作用: &在等号的右边为取地址符号,在等号的左边为引用符号

         *可以用做为乘号,也可用作为对指针变量解引的符号,取该地址存放的数据

结合方向:

“&”和“*”都是右结合的。假设有变量 x = 1,则*&x 的含义是,先获取变量 x 的地址,再获取地址中的内容。因为“&”和“*”互为逆运算,所以 x = *&x。

例如:输入 x、y 两个整数,然后将其中的值大的赋值给 x,小的赋值给 y。即:假设输入 x = 8,y = 9。就将 9 赋值给 x,8 赋值给 y。

void main(){//声明两个普通变量int x, y;//声明两个指针变量int *px, *py;//声明一个临时变量,用于交换int t;//输入两个值,赋值给 x、yscanf("%d", &x);scanf("%d", &y);//给指针变量 px、py 赋初值(关联变量 x、y)px = &x;py = &y;//利用指针来对比 x、y 的值,如果 x 的值比 y 的值小,就交换if(*px < *py){//交换步骤,其中*px == x、*py == yt = *px;*px = *py;*py = t;}printf("x =  %d, y = %d", *px, *py);
}

二.指针和数组的关系

1.利用指针访问数组里的值

	//利用指针访问数组里面的值int nums[] = {1,2,3,4};//方法一:下标法cout << "第一个数 :" << nums[0] << endl;//方法二:指针法cout << "第一个数 :" << *(nums + 0) << endl;//数组名就是数组元素的首地址

2.利用指针将数组作为实参传递给函数

void Test1(int nums[],int n) {for (int i = 0; i < n; i++) {cout << nums[i] << " ";}
}int main() {//利用指针访问数组里面的值int nums[] = {1,2,3,4};int* p = nums;//利用指针将数组作为实参传递给函数Test1(nums, 4);//数组名就是数组元素的首地址//方法二Test1(p, 4);//p指向数组,再将指向数组的指针传给被调函数
}

补充对指针加一 : 例如p++,不会将地址的值加一,而是将数组下移一位

 三.字符指针与字符数组

C语言中,没有字符串类型的变量,通常用字符数组或者字符指针存放字符串

1.字符数组的声明

	char str[] = "C++";char str1[] = { 'C','+','+' ,'\0'};字符数组的声明方式,在使用第二种声明方式的时候,必须在最后加上\0,此符号代表在这个地方该数组就结束了,如果不加该符号,会访问出界的

  字符数组的访问

	char str[] = "C++";char str1[] = { 'C','+','+' ,'\0'};printf("%s\n", str1);//%s格式化,表示直接输出整个数组printf("%c\n", str[0]);//利用数组法取str第一个字符printf("%c\n", *(str1 + 1));//利用指针法取str1的第2个字符

由上面可以看出,可以通过%c一个字符一个字符的输出,那么也可也利用循环输出每个字符

	for (int i = 0; i < strlen(str); i++) {printf("%c", str[i]);}

还可以用过strlen(str)或者sizeof(str)/sizeof(char)来获取该数组的长度

2.字符指针的声明

char *word = "have a good night";

  字符指针的访问

	const char* word = "have a good night";printf("%s\n", word);printf("%c\n", word[0]);for (int i = 0; i < strlen(word); i++) {printf("%c", word[i]);}

    对字符指针地址的加减

	const char* word = "have a good night";word++;printf("%s\n", word);//此时就会将指针下移到第一个a的地方,从a的地方进行输出,输出为:ave a good nightword--;printf("%s\n", word);//输出为:have a good nightconst char str[] = "C++";str++;//报错,在字符数组中不能进行加减操作,表达式必须是可修改的左值printf("%s", str);

四.指针在内存分配中的应用

1.用C语言中的malloc在堆区分配动态内存

1.利用malloc创建一维数组

#include <iostream>
#include <stdlib.h>
using namespace std;
int main() {int n;int* p = nullptr;cout << "请输入要存放的数据个数:";cin >> n;//在堆区分配内存p = (int *)malloc(n * sizeof(int));//输入for (int i = 0; i < n; i++) {cin >> *(p+i);}//输出for (int i = 0; i < n; i++) {cout << *(p+i) << " ";}free(p);
}

用malloc进行分配,注意malloc的返回值类型位void*类型,需要进行强制类型转换,由于在堆区分配的动态内存,所以在使用完之后,为了防止内存泄漏,需要用free进行释放

2.利用malloc进行开辟二位数组,与释放二位数组

#include <iostream>
#include <stdlib.h>
using namespace std;
int main() {int row = 0 ,col = 0 ;int** p = nullptr;cout << "依此输入行和列:" << endl;cin >> row>>col;//在堆区分配内存p = (int **)malloc(row * sizeof(int*));for (int i = 0; i < row; i++) {*(p + i) = (int*)malloc(col * sizeof(int));}//输入for (int i = 0; i < row * col; i++) {cin >> p[i / col][i % col];}//输出for (int i = 0; i < row * col; i++) {cout << p[i / col][i % col] << " ";}//释放动态开辟的二维数组for (int i = 0; i < row; i++) {free(p[i]);}free(p);
}

原理是,先创建一个指针数组,然后在利用改一级指针去创建动态int类型数组,在输入时候,用到了一个小技巧,用一层循环给二维数组赋值,在使用二维数组时候,应该先将每一层一级指针指向的内存块释放掉,然后再去释放该释放二级指针本身指向的内存块

1.用C++中的new在堆区分配动态内存

用到C++中的new分配内存,用delete释放内存,这里的new和delete只适用于c++中,malloc与free适用于c/c++,直接上例子

1.使用new进行分配一个动态的一维数组

int main() {int n;cout << "输入数组的大小:";cin >> n;int* p = new int[n];//输入for (int i = 0; i < n; i++) {cin >> *(p + i);}//输出for (int i = 0; i < n; i++) {cout << *(p + i) << " ";}delete[]p;
}

2.创建二维数组

int main() {int rows = 3;int cols = 4;// 创建动态二维数组int** array = new int*[rows];  // 创建一级指针数组for (int i = 0; i < rows; i++) {array[i] = new int[cols];  // 创建二级指针数组}// 使用动态二维数组for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {array[i][j] = i * cols + j;  // 给数组元素赋值}}// 打印动态二维数组for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {std::cout << array[i][j] << " ";}std::cout << std::endl;}// 释放动态二维数组的内存for (int i = 0; i < rows; i++) {delete[] array[i];  // 释放二级指针数组}delete[] array;  // 释放一级指针数组return 0;
}

和malloc的原理都是一样的,起始可以将一维数组创建的长一点,利用p[i / col][i % col];完全可以将一位数组当二维数组用,二维数组的存储方式也是按行存储的,地址都是连续的

在使用delete时候,数组的释放格式为 delete []p;,单个变量的释放格式为 delete p;

五.使用指针为什么能提高程序的性能

  • 直接访问内存:指针允许直接访问和操作内存中的数据。相比于通过变量的拷贝进行操作,直接访问内存可以减少数据的复制和移动,从而提高程序的执行效率。

#include <iostream>
using namespace std;
void Test1(int *p) {(*p)++;
}
void Test2(int m) {m++;
}
int main() {int num1 = 10,num2=10;Test1(&num1);cout << "Test1 :" << num1 << endl;//输出结果11Test2(num2);cout << "Test2 :" << num2 << endl;//输出结果10
}

Test1通过直接访问内存,避免了数据的拷贝和移动,提高了程序的执行效率。

Test2函数通过传递值的拷贝来操作变量。当我们调用该函数后,原始变量的值保持不变

  • 减少内存和时间开销:通过传递指针作为函数参数,可以避免在函数调用时产生变量的副本,从而减少内存的使用和传输的时间开销。特别是在处理大型数据结构或大量数据时,使用指针可以显著减少内存和时间的消耗。

  • 动态内存分配:指针使得动态内存分配成为可能,即在程序运行时根据需要分配和释放内存。相比于静态内存分配,动态内存分配可以更灵活地管理内存,避免内存浪费和限制,并且减少了程序启动时的内存占用。

六.指针与const搭配的四种情况

  • const 写在int之前,则限定不能通过*指针去改变该指针指向的值,但是可以指向别的指针
  • const 写在int之后,则限定可以通过*指针去改变该指针指向的值,但是不能指向别的指针
  • 两个const一个写在int前,一个写在变量名前,限制指针不能指向别的指针,并且不允许修改指针指向的值
  • 总结 : 看const离类型(int)近,还是理变量名近,离谁近,就修饰谁,谁就不能变
#include<iostream>
using namespace std;int main() {int wife = 30;int girl = 18;//第一种 : 渣男型,普通指针可以随意更改指向与指向地址的值int* zha_nan = &wife;cout << *zha_nan << endl;zha_nan = &girl;cout << *zha_nan << endl;//第二种 : 直男型,以自我为中心,可以改变指向,但是不可以改变指向的地址的值const int* zhi_nan = &wife;//*zhi_nan = 25;//报错,不能改变值zhi_nan = &girl;cout << *zhi_nan << endl;//第三种 : 暖男型,专一,不可以改变指向,但是可以改变指向的地址的值int* const nuan_nan = &wife;//nuan_nan = &girl;//报错,不能改变指向*nuan_nan = 25;cout << *nuan_nan << endl;//第四种 : 超级暖男型,超级专一,不能改变指向,也不能改变指向地址的值const int* const _super_nuan_nan = &wife;//*_super_nuan_nan = 25;//报错,不能改变指向地址的值//super_nuan_nan = &girl;//报错,不能改变指向//总结 : const理谁近就修饰谁,理(int)近,则修饰该指针的值不能改变,修饰变量,//	    则该指针不能在指向别的变量了
}

七.引用是实现原理

引用的底层也是用指针进行实现的

	int a = 0;int b = 2;int& c = a;c = b;//c是a的别名,将b的值赋值给c,就相当于将b的值也赋值给了acout << c << endl;//2cout << a << endl;//2//引用变量只能初始化一次,很像 int* const c = a;//该指针也只能进行一次初始化,就可以猜测引用的底层也是用该类型指针实现的

在使用引用的时候,编辑器会将引用类型转换为int * const 类型

例子:

void swap1(int& a, int& b) {int temp = a;a = b;b = temp;
}
void swap2(int* const a,int* const b) {int temp = *a;*a = *b;*b = temp;
}
int main() {int a = 1;int b = 2;swap1(a, b);//引用实现cout << "a = " << a << " b = " << b << endl;//a = 2,b =1swap2(&a, &b);cout << "a = " << a << " b = " << b << endl;//a = 2,b =1
}

对照swap1和swap2,在形参方面,引用变量会被改为int * const类型,在实参方面会将传入整数改为传入地址

八.多级指针

举例二级指针,懂了引用变量的话,那么对二级指针就可以有个优化了,提出指针引用,代码如下:

void home(int * p) {int b = 12;p = &b;
}
int main() {int a = 10;int* p = &a;//让p存放b的地址home(p);cout << *p << endl;//10
}

可以看出以上代码是无法改变p的指向的,改变值需要用一级指针,改变一级指针的指向需要用到二级指针,一次类推,这里直接就不写二级指针了,直接用一级指针的引用代替二级指针

void home(int *& p) {int b = 12;p = &b;
}
int main() {int a = 10;int* p = &a;//让p存放b的地址home(p);cout << *p << endl;//12
}

由此可以看出,利用指针引用可以将p的指向改变,这也的引用可以增强代码的可读性,与简洁性

九. 指针和函数的关系

1.通过指针使函数返回多个值

比如给你了一个已经初始化的数组,需要定义一个函数,用于返回这个数组的最大值与次大值,这个时候,为了增强代码的可读性,尽量返回一个数组,因为当返回的数据多了,也只能用返回数组实现了,代码如下:

void _max(int *nums,int n,int* exterm) {exterm[0] = nums[0];exterm[1] = nums[0];for (int i = 0; i < n; i++) {//大于次大的if (nums[i] > exterm[1]) {if (nums[i] > exterm[0]) {//大于最大的exterm[1] = exterm[0];exterm[0] = nums[i];}if (nums[i] < exterm[0]) {//小于最大的exterm[1] = nums[i];}}}
}int main() {//求该数组中的最大值与次大值int nums[] = { 2,6,4,9,5 };int exterm[2] = { 0 };_max(nums, 5, exterm);cout << exterm[0] << " " << exterm[1] << endl;//9,6
}

2.函数指针

函数指针是指向函数的指针变量。它可以存储函数的地址,并允许我们通过该指针调用相应的函数。函数指针在C和C++中都有广泛的应用,可以用于回调函数、函数参数以及实现函数的动态调用等场景。

要理解函数指针,首先需要了解函数的定义和函数指针的声明以及函数指针的使用方式。

1.函数定义:
返回类型 函数名(参数列表) {// 函数体
}2.函数指针的声明:
返回类型 (*指针变量名)(参数列表);指针变量名:函数指针的名称。
*:用于指明该变量是一个指针。
返回类型:函数指针指向的函数的返回类型。
参数列表:函数指针指向的函数的参数列表。3.将函数指针指向函数
指针变量名 = 函数名;4.通过函数指针调用函数:
(*指针变量名)(参数列表);//方法一
(指针变量名)(参数列表);//方法二

举例:

#include <iostream>int add(int a, int b) {return a + b;
}int subtract(int a, int b) {return a - b;
}int main() {// 声明函数指针int (*p)(int, int);// 将函数指针指向add函数p = add;// 通过函数指针调用add函数int result = (*p)(10, 5);std::cout << "Add: " << result << std::endl;// 将函数指针指向subtract函数p = subtract;// 通过函数指针调用subtract函数result = (*p)(10, 5);std::cout << "Subtract: " << result << std::endl;return 0;
}

3.函数的返回值类型为指针类型

int* creat() {return new int(1);//创建一个int类型的变量初始化为1,动态分配的数组不能进行初始化	
}int main() {//函数的返回值类型为指针变量类型,例子,//在creat函数里面动态的分配内存,将指向该段内存的指针返回int* p = creat();cout << "*p :" << *p << endl;//*p : 1delete p;
}

十.指针和结构体的关系

利用指针访问结构体里面的值

struct Test{int a;int b;int c;};struct Test ss = { 2,3,4 };//声明了结构对象ss,并把ss 的成员初始化为2,3 和4。struct Test* ptr = &ss;//声明了一个指向结构对象ss 的指针。它的类型是//Test *,它指向的类型是Test 。printf("%d", ptr->a);printf("%d", ptr->b);printf("%d", ptr->c);

 

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

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

相关文章

Java for循环每次都通过list.size()和 string.length()获取大小性能

有人说在for循环之前用一个局部变量先获取到list.size()、str.length()&#xff0c;然后在for循环的判断条件里通过这个局部变量替换list.size()、str.length()会节省数据计算的时间。事实真的是这样吗&#xff1f;下面就为大家解答这个问题。 说明&#xff1a;此文章针对Andro…

华为云云服务器评测|基于华为云云耀云服务器L实例开展性能评测,例如 MySQL、Clickhouse、Elasticsearch等等

在当今云计算时代&#xff0c;越来越多的企业和个人开始选择将应用部署在云服务器上&#xff0c;以便更好地满足高性能、可靠性和可扩展性等需求。而华为云云耀云服务器L实例不仅提供了高性能和可靠性的计算和存储资源&#xff0c;而且具有灵活和高效的成本控制&#xff0c;深受…

DDR2 IP核调试记录1

一、IP核生成不成功可能原因 1、打开 Quartus II 软件时&#xff0c;请右键选择以管理员方式运行&#xff0c;切记&#xff0c;否则可能导致 IP 生成不成功。 2、创建工程时不要将工程创建在和 Quartus II 安装目录相同的盘符下&#xff0c;否则可能导致生产 IP 失败。 3、如果…

Virtualenvwrapper 的安装教程

Virtualenvwrapper Virtaulenvwrapper是virtualenv的扩展包&#xff0c;用于更方便管理虚拟环境&#xff0c;它可以做&#xff1a; 将所有虚拟环境整合在一个目录下管理&#xff08;新增&#xff0c;删除&#xff0c;复制&#xff09;虚拟环境快速切换虚拟环境 安装方法 Li…

HTTP协议概述

HTTP 协议定义 HTTP协议&#xff0c;直译为超文本传输协议&#xff0c;是一种用于分布式、协作、超媒体的信息系统的应用协议。HTTP协议是万维网数据通信的基础。HTTP协议在客户端-服务器计算模型中充当请求-响应协议。客户端向服务器提交HTTP请求消息。服务器提供HTML文件和其…

SpringBoot项目在启动后自动关闭

问题描述&#xff1a; 今天搭建了一个SpringBoot项目&#xff0c;但是在启动之后就自行关闭了&#xff0c;就像下面这样&#xff1a; 原因分析&#xff1a;在创建SpringBoot项目的时候&#xff0c;Web的依赖没有导入&#xff0c;默认以普通java项目运行导致的终止。 解决方案…

CData Drivers for SAS xpt Crack

CData Drivers for SAS xpt Crack 使用基于标准的驱动程序&#xff0c;加入数据库、报告工具和自定义程序中的实时SAS xpt(XPORT)数据文件。 与BI分析、报告、ETL工具和自定义解决方案集成。 适用于SAS xpt的CData驱动程序。神奇的功能&#xff1a; BI和分析 我们的驱动程序是将…

aarch64-linux交叉编译libcurl带zlib和openssl

交叉编译libcurl需要依赖zlib和openssl 需要先用aarch64工具链编译zlib和openssl aarch64-linux环境搭建 下载工具链 gcc用于执行交叉编译 gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnusysroot是交叉版本的库文件集合 sysroot-glibc-linaro-2.25-2019.12-aarch64-lin…

线性代数的学习和整理17:向量空间的基,自然基,基变换等(未完成)

目录 3 向量空间的基&#xff1a;矩阵的基础/轴 3.1 从颜色RGB说起 3.2 附属知识 3.3 什么样的向量可以做基&#xff1f; 3.4 基的分类 3.1.1 不同空间的基---向量组的数量可能不同 3.1.2 自然基 3.1.3 正交基 3.1.4 标准正交基 3.1.5 基和向量/矩阵 3.1.6 基变换 …

ClickHouse进阶(五):副本与分片-1-副本与分片

进入正文前&#xff0c;感谢宝子们订阅专题、点赞、评论、收藏&#xff01;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; &#x1f3e1;个人主页&#xff1a;含各种IT体系技术,IT贫道_Apache Doris,大数据OLAP体系技术栈,Kerberos安全认证-CSDN博客 &#x1f4cc;订阅…

2023年7月京东打印机行业品牌销售排行榜(京东运营数据分析)

鲸参谋监测的京东平台7月份打印机行业销售数据已出炉&#xff01; 7月份&#xff0c;打印机市场呈现下滑趋势。根据鲸参谋平台的数据可知&#xff0c;当月京东平台打印机的销量为48万&#xff0c;环比下降约28%&#xff0c;同比下降约18%&#xff1b;销售额为4亿&#xff0c;环…

Django(10)-项目实战-对发布会管理系统进行测试并获取测试覆盖率

在发布会签到系统中使用django开发了发布会签到系统&#xff0c; 本文对该系统进行测试。 django.test django.test是Django框架中的一个模块&#xff0c;提供了用于编写和运行测试的工具和类。 django.test模块包含了一些用于测试的类和函数&#xff0c;如&#xff1a; Tes…

【数据结构】带头双向循环链表及其实现

目录 1.带头双向循环链表 2.带头双向循环链表实现 2.1初始化 2.2销毁 2.3头插 2.4链表打印 2.5头删数据 2.6尾插数据 2.7尾删数据 2.8链表判空 2.9查找一个数据 2.10在pos位置前插入数据 2.11删除pos位置 2.12求链表的长度 2.顺序表和链表的比较 1.带头双向循环…

stable diffusion实践操作-CLIP

系列文章目录 stable diffusion实践操作 文章目录 系列文章目录前言一、CLIP是什么&#xff1f;1.1 定义&#xff1a;1.2 作用 二、使用步骤2.1 设置使用2.1 跳过层对比图&#xff1a; 三、总结 前言 学习本章之前&#xff0c;先看SD生图原理 stable diffusion实践操作-SD原理…

YOLOv5算法改进(12)— 替换主干网络之Swin Transformer

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。Swin Transformer是一种基于Transformer的深度学习模型&#xff0c;它在视觉任务中表现出色。与之前的Vision Transformer&#xff08;ViT&#xff09;不同&#xff0c;Swin Transformer具有高效和精确的特性&#xff0c;并…

B081-Lucene+ElasticSearch

目录 认识全文检索概念lucene原理全文检索的特点常见的全文检索方案 Lucene创建索引导包分析图代码 搜索索引分析图代码 ElasticSearch认识ElasticSearchES与Kibana的安装及使用说明ES相关概念理解和简单增删改查ES查询DSL查询DSL过滤 分词器IK分词器安装测试分词器 文档映射(字…

Windows NUMA编程实践 – 处理器组、组亲和性、处理器亲和性及版本变化

Windows在设计之初没有考虑过对大数量的多CPU和NUMA架构的设备的支持&#xff0c;大部分关于CPU的设计按照64个为上限来设计。核心数越来越多的多核处理器的进入市场使得微软不得不做较大的改动来进行支持&#xff0c;因此Windows 的进程、线程和NUMA API在各个版本中行为不一样…

Vue:关于声明式导航中的 跳转、高亮、以及两个类名的定制

声明式导航-导航链接 文章目录 声明式导航-导航链接router-link的两大特点&#xff08;能跳转、能高亮&#xff09;声明式导航-两个类名定制两个高亮类名 实现导航高亮&#xff0c;实现方式其实&#xff0c;css&#xff0c;JavaScript , Vue ,都可以实现。其实关于路由导航&…

【计算机组成 课程笔记】3.2 算数运算和逻辑运算的硬件实现

课程链接&#xff1a; 计算机组成_北京大学_中国大学MOOC(慕课) 3 - 2 - 302-门电路的基本原理&#xff08;11-39--&#xff09;_哔哩哔哩_bilibili 现代计算机的CPU和其他很多功能部件都是基于晶体管的集成电路&#xff0c;想要了解计算机组成的基本原理&#xff0c;还是需要有…

苹果macOS 14开发者预览版Beta 7发布 新增超过100款视频壁纸和屏保

8 月 31 日&#xff0c;苹果向 Mac 电脑用户推送了 macOS 14 开发者预览版 Beta 7 更新&#xff08;内部版本号&#xff1a;23A5337a&#xff09;&#xff0c;本次更新距离上次发布隔了 8 天。 苹果发布 Beta 7 更新的同时&#xff0c;还发布了第 6 个公测版&#xff0c;正式版…