【C++】引用、内联函数、auto关键字、基于范围的for循环、指针空值nullptr

文章目录

  • 前言
  • 引用
    • 引用概念
    • 引用特性
    • 常引用
    • 使用场景
    • 传值、传引用效率对比
    • 引用和指针的区别
  • 内联函数
    • 概念
    • 特性
  • auto关键字
    • auto概念
    • auto的使用细则
    • auto不能推导类型的场景
  • 基于范围的for循环(C++11)
    • 范围for的语法形式
    • 范围for的使用条件
  • 指针空值nullptr的出现
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:

C++是一门强大而灵活的编程语言,拥有许多特性和语法糖,让程序员能够更高效地编写代码。在本博客中,我们将探讨一些C++中常用的特性,包括引用、内联函数、auto关键字、基于范围的for循环以及指针空值nullptr。通过深入了解这些特性,我们可以写出更简洁、高效且易于维护的C++代码。


提示:以下是本篇文章正文内容,下面案例可供参考

引用

引用概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

这就好比一个人的名字,身份证上是你的名字,你可能也有乳名或者外号,但是这都代表的是你本人!!!

使用:类型& 引用变量名(对象名)= 引用实体;

看一段程序
在这里插入图片描述

你会发现,pa和a的地址是同一个地址,这也证明了变量和引用变量共享同一块内存空间

注意:引用类型必须和引用实体是同种类型的。扩展点:引用的本质是指针,但是语法上引用变量不会开辟空间

引用特性

  • 引用在定义的时候必须初始化
int& b;//这种写法编译器会报错
  • 一个变量可以有多个引用
int a=0;
int& ra=a;
int& rb=a;
int& rra=ra;
  • 引用一旦引用一个实体,再也不能引用其他实体
int a=0;
int& ra=a;
int x=0;
ra=x;

这里最后是赋值操作,并不是ra重新引用x变量

常引用

先看一段代码,思考一下为什么???

#include <iostream>
using namespace std;
int main()
{
	int a = 0;
	int& b = a;

	const int c = 0;
	int& d = c;
	return 0;
}

在这里插入图片描述
这里很明显上面代码没错,下面代码报错了。结论:这是因为在指针和引用中,权限只能缩小,不能放大!!!
在上面代码中,a变量是可读可写的,b也是可读可写的,这里没问题,但是下面c是只读的,d是可读可写的,这里就会出大问题,问题就在于,他们两个共用一块内存,变量c自身都是只读的,被你引用后你怎么能修改我呢??这就是权限只能缩小,不能放大的由来

还有一种情况就是类型不一致的情况

在这里插入图片描述
这里编译器也报错了,报错原因是无法用 “double” 类型的值初始化 “int &” 类型的引用(非常量限定) ,这里又是为什么呢?接下来我讲用画图板来给大家解释。
在这里插入图片描述
类型不同时,隐式类型转换和引用都会中间产生一个临时变量,而临时变量具有常性(相当于被const修饰),因此int&b的引用相当于权限的放大,这里加上const之后就没问题了

修改后,程序编译通过

在这里插入图片描述

注意:变量之间的赋值没有权限的的缩小和放大问题,只有引用和指针有,因为变量赋值不是共用一块内存空间

在这里插入图片描述
在这里插入图片描述

使用场景

  1. 作参数
#include <iostream>
using namespace std;
void swap(int& num1, int& num2)//引用做参数
{
	int tmp = num1;
	num1 = num2;
	num2 = tmp;
}
int main()
{
	int num1 = 10;
	int num2 = 20;
	swap(num1, num2);
	cout << num1 << " " << num2 << endl;
	return 0;
}

图解
在这里插入图片描述

  1. 作返回值
int& test()//引用做返回值
{
	static int n = 0;
	n++;
	return n;
}
int main()
{
	/*int num1 = 10;
	int num2 = 20;
	swap(num1, num2);
	cout << num1 << " " << num2 << endl;*/
	cout << test() << endl;
	cout << test() << endl;
	cout << test() << endl;
	return 0;
}

注意:如果函数返回时,出了函数作用域,如果返回对象还未还给操作系统,则可以使用引用返回,如果已经还给系统,则必须使用传值返回

总结:通常情况下,如果引用返回的是局部变量,那么很可能会出现潜在的问题,返回的变量中的值可能是随机值,所以一般情况下,引用返回的是全局变量或者被static修饰等,那么原因是什么??

图解

在这里插入图片描述
总的来说,传值返回发生了一次拷贝,多开辟了一次空间,而传引用返回仅仅是返回变量的别名,没有开辟新的空间!!

传值、传引用效率对比

传值与传引用效率对比示例:

在C++中,函数参数的传递方式对性能有一定影响。传值方式会将实参的值复制到形参,而传引用方式直接传递实参的地址。以下是一个简单的例子,展示了传值与传引用的效率对比:

#include <iostream>
#include <chrono>

// 传值方式
void passByValue(int a, int b) {
    // 一些操作
    int result = a + b;
}

// 传引用方式
void passByReference(const int& a, const int& b) {
    // 一些操作
    int result = a + b;
}

int main() {
    // 测试传值方式
    auto startValue = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000; ++i) {
        passByValue(42, 23);
    }
    auto endValue = std::chrono::high_resolution_clock::now();
    auto durationValue = std::chrono::duration_cast<std::chrono::microseconds>(endValue - startValue);
    std::cout << "传值方式耗时: " << durationValue.count() << " 微秒" << std::endl;

    // 测试传引用方式
    auto startReference = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000; ++i) {
        passByReference(42, 23);
    }
    auto endReference = std::chrono::high_resolution_clock::now();
    auto durationReference = std::chrono::duration_cast<std::chrono::microseconds>(endReference - startReference);
    std::cout << "传引用方式耗时: " << durationReference.count() << " 微秒" << std::endl;

    return 0;
}

示例说明:

在上述例子中,通过std::chrono库计算了通过传值方式和传引用方式调用函数的耗时。通常情况下,传引用方式相对于传值方式可能具有更好的性能,因为它避免了值的复制操作。

注意事项:

  • 对于小型数据或内置类型,传值可能更为合适。在大型数据结构或自定义类型时,传引用可以减少复制开销。
  • 优化建议:在实际应用中,应该根据具体情况选择合适的传递方式,并根据实际性能需求进行优化。

引用和指针的区别

在语法概念上,引用就是一个别名,没有自己独立的空间,和其引用实体共用同一块空间。

int main()
{
 	int a = 10;
 	int& ra = a;
 
 	cout<<"&a = "<<&a<<endl;
 	cout<<"&ra = "<<&ra<<endl;
	 return 0;
}

但是在底层实现上,引用实际是有空间的,因为引用是按照指针的方式来实现的。

我们来看下引用和指针的汇编代码对比

在这里插入图片描述
在这里插入图片描述

引用和指针的不同点:

1. 定义和声明:

  • 引用: 引用是变量的别名,必须在定义时初始化,并且初始化后不能再引用其他变量。
    int x = 10;
    int& ref = x;  // 引用的初始化
    
  • 指针: 指针是一个变量,存储另一个变量的地址,可以在任何时候指向其他变量。
    int x = 10;
    int* ptr = &x;  // 指针的初始化
    

2. 内存操作:

  • 引用: 引用在内部被视为被引用变量的别名,没有自己的内存地址。
  • 指针: 指针有自己的内存地址,存储其他变量的地址。

3. 空值(Null):

  • 引用: 不存在空引用的概念,必须在初始化时指向有效的对象。
  • 指针: 可以具有空指针值,即指向空地址(nullptr)。

4. 重指向:

  • 引用: 一旦引用被初始化,就无法更改其引用对象。
  • 指针: 可以通过重新分配来更改指针所指向的对象。
    int x = 10;
    int* ptr = &x;  // 指向 x
    int y = 20;
    ptr = &y;       // 指向 y
    

5. 访问方式:

  • 引用: 使用引用时,不需要使用解引用运算符*,直接使用引用变量即可。
  • 指针: 使用指针时,需要通过解引用运算符*来访问指针所指向的值。
    int x = 10;
    int& ref = x;    // 使用引用
    int* ptr = &x;   // 使用指针
    std::cout << ref << std::endl;  // 不需要解引用
    std::cout << *ptr << std::endl; // 需要解引用
    

6. 大小:

  • 引用: 引用在内存中通常不占用额外空间。
  • 指针: 指针在内存中占用一定的空间,通常是机器的字长。

示例说明:

#include <iostream>

int main() {
    int x = 10;
    
    // 引用的使用
    int& ref = x;
    std::cout << "引用值:" << ref << std::endl;

    // 指针的使用
    int* ptr = &x;
    std::cout << "指针值:" << *ptr << std::endl;

    // 重指向
    int y = 20;
    ptr = &y;
    std::cout << "重指向后的指针值:" << *ptr << std::endl;

    return 0;
}

上述示例展示了引用和指针的基本用法以及它们之间的不同点。根据具体的场景和需求,选择引用或指针将有助于更清晰和有效地编写代码。

内联函数

概念

inline修饰的函数叫内联函数,编译时,C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升了程序运行的效率。
在这里插入图片描述
如果在上述函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。
查看方式:

  1. 在release模式下,查看编译器生成的汇编代码中是否存在call Add
  2. 在debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不会对代码进行优化.

特性

  1. inline是一种以空间换时间的做法,省去调用函数的额外开销,所以代码很长或者有递归的函数不适宜使用作为内联函数。
  2. inline对于编译器来说只是一个建议,编译器会自动优化,如果定义为inline的函数体内有递归等等,编译器优化时会忽略内联。
  3. inline不建议声明和定义分离,分离会导致链接错误,因为inline被展开了,就没有函数地址了,链接就会找不到。

宏的优缺点?
优点:
1.增强代码的复用性。
2.提高性能。
缺点:
1.不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型安全的检查 。
C++有哪些技术替代宏?

  1. 常量定义 换用const
  2. 函数定义 换用内联函数

auto关键字

auto概念

早期C++语法中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但是可惜的是一直没有人去使用,大家可以去网上搜寻一下是为什么?
C++11中,赋予了auto全新的含义:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto申明的变量必须由编译器在编译时期推导而得

int TestAuto()
{
	return 10;
}
int main()
{
	int a = 10;
 	auto b = a;
 	auto c = 'a';
 	auto d = TestAuto();
 
 	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
 	cout << typeid(d).name() << endl;
 
 //auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
 return 0;
}

上述代码中使用的auto关键字来推导接收到的值是什么类型,并使用typeid().name()来判断对象或者变量所属的类型是什么

注意:使用auto定义的变量必须对其初始化(这里和引用一样),在编译阶段编译器需要根据初始化表达式来推导auto的实际类型,因此auto并非是一种“类型的”声明,而是一个类型声明时的“占位符”,编译器在编译期间会将auto替换成变量实际的类型

auto的使用细则

  • auto把指针和引用结合起来使用

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用时则必须加&

int a = 10;
auto b=&a;
auto* c=&a;
auto& d=a;
  • 在同一行,使用auto定义多个变

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际上只对第一个类型进行推导,然后用推导出来的类型定义其他变量

auto i=10,j=20;
auto x=10,y='1';// 该行代码会编译失败,因为x和y的初始化表达式类型不同

auto不能推导类型的场景

  • 在函数形参中不能使用
void test(auto a)
{}
  • auto不能直接用来声明数组
void test()
{
	auto arr[]={1,2,3,4,5,6,7,8,9,10}
}
  • auto在实际中最常见的用法就是跟以后C++11提供的新式for循环,还有lambda表达式等进行配合使用。

基于范围的for循环(C++11)

范围for的语法形式

对于一个有范围的集合来说,由程序员自己来说明循环的范围是非常多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号:分成两个部分,第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围

#include <iostream>
using namespace std;
void test()
{
    int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    for (auto& e : arr)
    {
        e*=2;
    }
    for (auto e : arr)
    {
        cout << e << " " ;
    }
}
int main()
{
    test();
    return 0;
}

注意:和普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环

范围for的使用条件

  • for循环迭代的范围必须是确定的

对于数组而已,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。

以下代码就存在问题,因为for的范围不确定

void test(int arr[])
{
	for(auto&e : array)
	{
		cout<<e<<" ";
	}
}

因为这里形参的数组,已经退化成指针,所有形参中的arr并不能获得数组的范围

  • 迭代的对象要实现++和==的操作。(这里牵涉到后期的知识,留给大家思考一下吧哈哈)

指针空值nullptr的出现

相信一个拥有良好编程习惯的同学,一定会在声明一个变量的时候给他初始化,否则可能就会出现使用未初始化的变量的错误,比如未初始化指针等等。在C语言中,如果指针没有一个合法的指向,我们基本都是按照下面的方式对其进行初始化的:
在这里插入图片描述
NULL实际上是一个宏,在传统的C头文件(stddef.h)中,可以看到以下代码:
在这里插入图片描述
这段代码是对NULL宏的定义,用于在C和C++中表示空指针的常量。

  1. 条件编译:

    • #ifndef NULL:如果NULL未定义(即未被之前的代码或头文件定义过)。
    • #ifdef __cplusplus:如果是C++环境。
  2. 宏定义:

    • #define NULL 0:在C++环境下,将NULL宏定义为整数0,表示空指针。
  3. 备选定义:

    • #else#define NULL ((void *)0):如果不在C++环境下,则将NULL宏定义为一个空指针,即(void *)0

这段代码的目的是确保在C和C++中都有一个合适的空指针表示。在C++中,空指针通常表示为整数0,而在C中,可以用(void *)0表示空指针。这种做法是为了保持对旧代码的兼容性,以及确保在不同编译环境下都能正确使用NULL

在这个宏定义中,可以看到,NULL可能被定义成字面常量0,或者在cpp中被定义为(void*)0。但是不管采取何种定义,在使用空值指针的时候,都不可避免的会遇到一些麻烦

void f(int)
{
 	cout<<"f(int)"<<endl;
}
void f(int*)
{
 	cout<<"f(int*)"<<endl;
}
int main()
{
	f(0);
 	f(NULL);
 	f((int*)NULL);
 	return 0;
}

程序结果
在这里插入图片描述
程序本意是想把f(NULL)调用指针版本的 f(int)。但是由于NULL被定义为字面常量0,所以程序输出恰好相反。
在C++98中,字面常量0既可以是一个整型数字,也可以是无类型的指针 (void
)0 ,但是编译器默认情况下会将其看成是一个整型常量,如果要将其按照指针方式来使用,必须要对其进行强转(void*)0**

注意:建议在中统一使用nullptr代替NULL++

  • 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
  • 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同
  • 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr

总结

C++作为一门现代编程语言,提供了许多方便的语法糖和特性,使得程序员能够更好地应对各种编程场景。引用为我们提供了更直观的数据操作方式,内联函数优化了程序的执行效率,auto关键字简化了变量声明,基于范围的for循环使代码更具可读性,而指针空值nullptr则更安全地表示空指针。通过充分利用这些特性,我们能够在C++中编写出更加优雅和高效的代码,提升编程体验和代码质量。

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

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

相关文章

【VMware】Windows安装MySQL及网络配置---图文并茂详细介绍

目录 目录 一 安装MySQL ① 连接虚拟机传输MySQL压缩包 ②解压MySQL压缩包 ③ my文件拷贝mysql安装根目录下 ④ 修改my文件 ⑤ 5.7版本安装MySQL 5.1 注册mysql服务 5.2 初始化 5.3 启动MySQL 5.4 登入MySQL 5.5 修改默认密码 ⑥ 8版本安装MySQL 6.1 解压压缩包 …

手把手将ReactJS项目部署到Ubuntu

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版&#xff0c;欢迎购买。点击进入详情 1.构建项目 npm run build 生成build目录&#xff1a; 2.上传项目 将build目录上传到Ubuntu。 可以使用Xftp工具。 3.启动项目 npm install -g serve serve -s …

数据结构第2章 栈和队列

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 本篇笔记整理&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 0、思维导图栈和队列1、栈1&#xff09;特点2&#xff0…

8295座舱首家量产/连续两款车型落地,智能座舱进阶3.0时代

兼具豪华感与科技感的数字座舱&#xff0c;已经成为当前各大高端智能车型的核心卖点。 在2023年广州车展上&#xff0c;高端智能纯电轿车吉利银河E8正式发布&#xff0c;极具科技感的座舱空间设计与智能化能力让这款车脱颖而出。 例如极具视觉震撼效果的45英寸贯穿屏&#xff…

Flutter 中使用 ICON

Flutter Icon URL &#xff1a; https://fonts.google.com/icons&#xff1a; 在Flutter中使用 Icon 步骤如下&#xff1a; 导入图标库 在Dart 文件中导入 material.dart 包&#xff0c;该包包含了 Flutter 的图标库。 import package:flutter/material.dart;使用图标组件 …

尚硅谷大数据技术-数据湖Hudi视频教程-笔记01

大数据新风口&#xff1a;Hudi数据湖&#xff08;尚硅谷&Apache Hudi联合出品&#xff09;尚硅谷数据湖Hudi视频教程 B站直达&#xff1a;https://www.bilibili.com/video/BV1ue4y1i7na百度网盘&#xff1a;https://pan.baidu.com/s/1NkPku5Pp-l0gfgoo63hR-Q?pwdyyds阿里云…

【React】02-如何理解React通过对DOM的模拟,最大限度地减少与DOM的交互

如何理解React通过对DOM的模拟&#xff0c;最大限度地减少与DOM的交互 背景分析关于虚拟DOM 背景 在学习React的过程中&#xff0c;发现很多文档上关于React的高效都有这么一句话的描述——React通过对DOM的模拟&#xff0c;最大限度地减少与DOM的交互&#xff0c;对于我这种前…

Springboot集成RabbitMq一

0、知识点 1、创建项目-生产者 默认官方start.spring.io已不支持自动生成低版本jkd的Spring项目&#xff0c;自定义用阿里云的starter即可&#xff1a;https://start.aliyun.com 2、创建配置类 package com.wym.rabbitmqprovider.utils;import org.springframework.amqp.core.…

Vue3-34-路由-路由配置参数 props

说明 路由的路径中可以携带参数&#xff0c; 形式如 &#xff1a;/a/:pname &#xff0c;这个:表示这是个参数&#xff0c;pname &#xff1a;表示 参数名称。 在组件中&#xff0c;可以通过 当前路由对象的 params 属性来获取到这个参数&#xff0c; 当前路由对象 可以通过 us…

[Ray Tracing: The Rest of Your Life] 笔记

前言 开年第一篇博客~ 整理了三四个小时才整理完orz。 这一部分是光线追踪三部曲的最后一部&#xff0c;主要介绍了蒙特卡洛积分、重要性采样等内容。场景上没有什么大的改变&#xff0c;基本上就是在Cornell Box中渲染的&#xff0c;本篇主要在加速收敛&#xff0c;提升渲染效…

踩坑记录-安装nuxt3报错:Error: Failed to download template from registry: fetch failed;

报错复现 安装nuxt3报错&#xff1a;Error: Failed to download template from registry: fetch failednpx nuxi init nuxt-demo 初始化nuxt 项目 报错 Error: Failed to download template from registry: fetch faile 解决方法 配置hosts Mac电脑&#xff1a;/etc/hostswin电…

java StringBuilder对比String的优点和15个经典案例

文章目录 区别&#xff1a;1. 字符串拼接2. 构建动态查询语句3. 格式化输出4. 字符串反转5. 插入字符串6. 删除子串7. 字符串替换8. 构建复杂JSON或XML结构9. 处理用户输入的大量数据10. 动态生成HTML页面11. 处理字符串格式转换12. 实现字符串缓冲区13. 拼接大量字符串数组元素…

LLVM(简介)

历史 LLVM(low level virtual machine)起源于伊利诺伊大学的一个编译器实验项目&#xff0c;目前已经发展成一个集编译器和工具链为一体的商业开源项目&#xff0c;因此其英文名称的含义被扩大&#xff0c;不再仅仅是字面意思。其创始人为 Chris Lattner。LLVM项目遵循的开源许…

java数据结构与算法刷题-----LeetCode746. 使用最小花费爬楼梯

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难&#xff0c;但它就是固定套路而已。其实动态规划只…

嵌入式系统(二)单片机基础 | 单片机特点 内部结构 最小系统 电源 晶振 复位

上一篇文章我们介绍了嵌入式系统 嵌入式系统&#xff08;Embedded System&#xff09;是一种特定用途的计算机系统&#xff0c;它通常嵌入在更大的产品或系统中&#xff0c;用于控制、监测或执行特定的任务。这些系统通常由硬件和软件组成&#xff0c;旨在满足特定的需求&…

SQL窗口函数大小详解

窗口大小 OVER 子句中的 frame_clause 选项用于指定一个滑动的窗口。窗口总是位于分区范围之内&#xff0c;是分区的一个子集。指定了窗口之后&#xff0c;分析函数不再基于分区进行计算&#xff0c;而是基于窗口内的数据进行计算。 指定窗口大小的语法如下&#xff1a; ROWS…

了解并使用django-rest-framework-jwt

一 JWT认证 在用户注册或登录后&#xff0c;我们想记录用户的登录状态&#xff0c;或者为用户创建身份认证的凭证。我们不再使用Session认证机制&#xff0c;而使用Json Web Token&#xff08;本质就是token&#xff09;认证机制。 Json web token (JWT), 是为了在网络应用环…

2023年12月GESP C++七级编程题转Python真题解析

七、2023年12月GESP C(Python)七级编程题 2023年12月GESP Python最高六级&#xff0c;但C与Python同级编程题相同。本篇引用2023年12月GESPC七级编程题&#xff0c;用Python实现。 【七级编程题1】 【试题名称】&#xff1a;商品交易 时间限制&#xff1a;1.0 s 内存限制&…

CMake入门教程【核心篇】引用子模块.cmake文件(include)

&#x1f608;「CSDN主页」&#xff1a;传送门 &#x1f608;「Bilibil首页」&#xff1a;传送门 &#x1f608;「本文的内容」&#xff1a;CMake入门教程 &#x1f608;「动动你的小手」&#xff1a;点赞&#x1f44d;收藏⭐️评论&#x1f4dd; 文章目录 include子模块举个例…

四、HTML 属性

属性是 HTML 元素提供的附加信息。 一、HTML 属性 HTML 元素可以设置属性属性可以在元素中添加附加信息属性一般描述于开始标签属性总是以名称/值对的形式出现&#xff0c;比如&#xff1a;name"value"。 二、 属性实例 HTML 链接由 <a> 标签定义。链接的地…
最新文章