C++ 基础:指针和引用浅谈

指针

基本概念

C++中,指针是存储其他变量的内存地址的变量。

我们在程序中声明的每个变量在内存中都有一个关联的位置,我们称之为变量的内存地址。
如果我们的程序中有一个变量 var,那么&var 返回它的内存地址。

int main()
{

   int var1 = 3;
   int var2 = 90;
   int var3 = 520;

   cout<<"Address of var1: "<<&var1<<endl;
   cout<<"Address of var2: " <<&var2<<endl;
   cout<<"Address of var3: "<<&var3 <<endl;

   
   return 0;
}

image-20240625094624250

  • 开头的0x代表十六进制形式的地址。
  • 注意,第一个地址与第二个地址相差 4 个字节,第二个地址与第三个地址相差 4 个字节。
  • 区别是因为在64位系统中int的大小是4个字节
  • 运行该程序时,您可能不会得到相同的结果。这是因为地址取决于程序运行的环境。

如何定义指针:

int* pointer;

以下是我们如何为指针分配地址:

int var = 5;
int* ptr = &var;

在这里,变量 var 被赋值为 5。然后,通过代码 ptr = &var,将变量 var 的地址分配给 ptr指针。

声明指针之后立即对其进行赋值操作是一个不错的编码习惯;

  • 通过指针获取值

需要获取指针指向的变量地址中的值,可以使用*来进行;

int main()
{

   int var1 = 5;
   int* ptr = &var1;

   cout<<"Address of var1: "<<&var1<<endl;
   cout<<"ptr value: "<< *ptr<<endl;


   return 0;

}

我们使用 *point_var 来获取存储在该地址中的值。当将 * 与指针一起使用时,称之为解引用运算符。它作用于指针并给出指针中存储的地址指向的值。也就是说,*point_var = var

再看一个例子,强化对指针和解引用概念的理解:

#include <iostream>
using namespace std;
int main() {
    int var = 5;

    // store address of var
    int* point_var = &var;

    // print value of var
    cout << "var = " << var << endl;

    // print address of var
    cout << "Address of var (&var) = " << &var << endl
         << endl;

    // print pointer point_var
    cout << "point_var = " << point_var << endl;

    // print the content of the address point_var points to
    cout << "Content of the address pointed to by point_var (*point_var) = " << *point_var << endl;
    
    return 0;
}

Working of C++ Pointers


  • 改变指针指向的值

如果point_var指向var的地址,我们可以使用*point_var来改变var的值。

int main()
{

   int var1 = 3;
   int* ptr = &var1;

   *ptr = 1;
   cout<<"Address of var1: "<<&var1<<endl;
   cout<<"ptr value: "<< *ptr<<endl;


   return 0;

}

这里,point_var&var具有相同的地址;当*point_var改变时,var 的值也会改变。

  • 使用指针时候的常见错误用法:
int var = 5;

// Wrong! 
// point_var is an address but var is not
int* point_var = var;

// Wrong!
// &var is an address
// *point_var is the value stored in &var
*point_var = &var;

// Correct! 
// point_var is an address and so is &var
point_var = &var;

 // Correct!
// both *point_var and var are values
*point_var = var;

指针和数组

C++ 中,指针是保存其他变量地址的变量。指针不仅可以存储单个变量的地址,还可以存储数组单元的地址。

int *ptr;
int arr[5];

// store the address of the first
// element of arr in ptr
ptr = arr;
  • 这里,ptr是一个指针变量,而arr是一个int数组。
  • 代码ptr = arr; 将数组的第一个元素的地址存储在变量ptr中。
  • 注意,我们使用的是arr而不是&arr[0]。这是因为它们是相同的。因此,下面的代码与上面的代码相同。
int *ptr;
int arr[5];
ptr = &arr[0];

其余数组元素的地址由 &arr[1]、&arr[2]、&arr[3] &arr[4] 给出。


  • 使用指针获取指定元素

假设我们需要使用相同的指针 ptr 指向数组的第四个元素。
这里,如果 ptr 指向上例中的第一个元素,那么 ptr + 3 将指向第四个元素地址。例如:

int *ptr;
int arr[5];
ptr = arr;

ptr + 1 is equivalent to &arr[1];
ptr + 2 is equivalent to &arr[2];
ptr + 3 is equivalent to &arr[3];
ptr + 4 is equivalent to &arr[4];

类似地,我们可以使用单个指针访问元素。例如:

*ptr == arr[0];
*(ptr + 1) is equivalent to arr[1];
*(ptr + 2) is equivalent to arr[2];
*(ptr + 3) is equivalent to arr[3];
*(ptr + 4) is equivalent to arr[4];

假设我们已经初始化了 ptr = &arr[2];

ptr - 2 is equivalent to &arr[0];
ptr - 1 is equivalent to &arr[1]; 
ptr + 1 is equivalent to &arr[3];
ptr + 2 is equivalent to &arr[4];

Working of C++ Pointers with Arrays

int main()
{

   float arr[3];

   float *ptr;

   for(int i=0;i<3;i++)
   {
      cout<<"&arr["<<i<<"]=" <<&arr[i] <<endl;
   }

   ptr = arr;

   cout<<endl;

   for(int i=0;i<3;i++)
   {
      cout <<"ptr + " << i <<"  = " << ptr+i<<endl;
   }

   return 0;

}

在上面的程序中,我们分别使用普通方式和指针的方式打印了数组元素的地址信息;

在大多数情况下,数组名称会退化为指针。简单来说,数组名称被转换为指针。这就是为什么我们可以使用指针来访问数组元素的原因。但是,我们应该记住,指针和数组并不相同。在某些情况下,数组名称不会衰减为指针。具体情况可以查阅:https://stackoverflow.com/questions/17752978/exceptions-to-array-decaying-into-a-pointer

// C++ Program to insert and display data entered by using pointer notation.

#include <iostream>
using namespace std;

int main() {
    float arr[5];
    
   // Insert data using pointer notation
    cout << "Enter 5 numbers: ";
    for (int i = 0; i < 5; ++i) {

        // store input number in arr[i]
        cin >> *(arr + i) ;

    }

    // Display data using pointer notation
    cout << "Displaying data: " << endl;
    for (int i = 0; i < 5; ++i) {

        // display value of arr[i]
        cout << *(arr + i) << endl ;

    }

    return 0;
}

其中的cin >> *(arr + i) ;等同于cin >> arr[i];;

请注意,我们没有声明单独的指针变量,而是使用数组名称 arr 作为指针表示法。
我们已经知道,数组名 arr 指向数组的第一个元素。因此,我们可以将 arr 视为一个指针。


引用

基本概念

我们使用&符号来创建引用。例如:

string& ref_city = city;
#include <iostream>

using namespace std;

int main() {

    string city = "Paris";

    // create a reference to the variable
    string& ref_city = city;
    
    // display the variable
    cout << "Variable Value: " << city << endl;
    cout << "Reference Value: " << ref_city << endl;

    return 0;
}

上面的代码中我们使用引用变量 ref_city 来显示变量 city 的值。


  • 通过引用修改变量

我们可以通过简单地为引用变量分配一个新值来修改变量。

int main()
{
   string city = "Shanghai";

   string& ref_city = city;

   ref_city = "Hk";
   cout <<"var:" << city <<endl;
   cout<<"ref: "<< ref_city<<endl;

   return 0;

}

我们可以在创建引用时将 & 符号与数据类型或变量一起放置。但是,标准做法是将符号与数据类型一起使用。例如:

// create a variable
string city = "Paris";

// valid but not a standard practice
string &ref_city = city;

// valid and a standard practice
sring& ref_city = city;

一旦我们创建了对变量的引用,就无法将其更改为引用另一个变量。例如:

int main() {

    string city1 = "Paris";

    // create a reference to the variable
    string& ref_city = city1;
    
    // display the variable
    cout << "city1 = " << city1 << endl;
    cout << "ref_city = " << ref_city << endl;
    
    string city2 = "New York";
    
    // trying to modify the ref_city reference variable to refer to city2
    // but it assigns the value of city2 to the variable city1
    ref_city = city2;

    // display the variables
    cout << endl << "city1 = " << city1 << endl;
    cout << "city2 = " << city2 << endl;
    cout << "ref_city = " << ref_city << endl;

    return 0;
}

注意,虽然这里最后引用ref_city输出的是新的值New York,但他指向的始终还是开始的那个city1,只是引用的值变为了新的New York

引用传递

在 C++ 函数教程中,我们学习了如何将参数传递给函数。使用的这种方法称为按值传递,因为传递的是实际值。
但是,还有另一种传递参数的方法,称为引用传递
引用传递是一种在函数中传递参数的方法,其中将实际参数的引用而不是它们的值传递给函数。

// function that takes value as parameter

void func1(int num_val) {
    // code
}

// function that takes reference as parameter
// notice the & before the parameter
void func2(int& num_ref) {
    // code
}

int main() {
    int num = 5;

    // pass by value
    func1(num);

    // pass by reference
    func2(num);

    return 0;
}

注意 void func2(int& num_ref) 中的 &。这表示我们使用变量的引用作为参数。
因此,当我们通过传递变量 num 作为参数来调用 main() 中的func2()函数时,我们实际上传递的是 num 变量的引用而不是值 5

void swap(int &n1,int &n2)
    {
        int temp;
        temp = n1;
        n1 = n2;
        n2 = temp;
    }
int main() {

    int a {1},b {2};
    cout<<"Before swaping" << endl;
    cout<<"a = "<< a <<endl;
    cout<<"b = "<< b << endl;

    swap(a,b);

    cout<<"\nAfter swaping" << endl;
    cout<<"a = "<< a <<endl;
    cout<<"b = "<< b << endl;

    return 0;
}

在这个程序中,我们将变量 a 和 b 传递给 swap() 函数。请注意函数的定义、其中的参数我们使用的是引用类型;

因此,编译器可以识别出传递给函数参数的不是实际值,而是变量的引用。
swap() 函数中,函数参数 n1 n2 分别指向与变量 a b 相同的值。因此,交换是在实际值上进行的。


常量引用

当变量的值不需要更改时,我们可以将它们作为常量引用传递。
我们来看一个例子:

#include <iostream>
using namespace std;

// function to add two numbers 
// using const references
int add(const int& num1, const int& num2) {
    return num1 + num2;
}

int main() {
    int number1, number2;

    // take input
    cout << "Enter the first number: ";
    cin >> number1;

    cout << "Enter the second number: ";
    cin >> number2;

    // call add function
    int sum = add(number1, number2);

    // displaying the result
    cout << "The sum of " << number1 << " and " << number2 << " is " << sum << endl;

    return 0;
}

在这里,我们使用 const 关键字通过 const 引用传递值。
使用 const 引用可防止函数内的值发生更改。例如,让我们尝试使用 const 引用来交换两个数字。

#include <iostream>
using namespace std;

// function definition to swap values
// using const references
void swap(const int& n1,const int& n2) {
    int temp;
    temp = n1;
    n1 = n2;
    n2 = temp;
}

int main() {

    // initialize variables
    int a = 1, b = 2;

    cout << "Before swapping" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    // call function to swap numbers
    swap(a, b);

    cout << "\nAfter swapping" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    return 0;
}

这个程序运行是会报错的,因为对于参数,我们使用了const进行修饰

image-20240625172322268

对于这个交换函数,我们使用指针传递参数也是可以实现的,但是不建议使用这种方式:

#include <iostream>
using namespace std;

// function prototype with pointers as parameters
void swap(int*, int*);

int main() {

    // initialize variables
    int a = 1, b = 2;

    cout << "Before swapping" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    // call function by passing variable addresses
    swap(&a, &b);

    cout << "\nAfter swapping" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    return 0;
}

// function definition to swap numbers
void swap(int* n1, int* n2) {
    int temp;
    temp = *n1;
    *n1 = *n2;
    *n2 = temp;
}
  • *n1*n2 分别给出存储在地址 n1 和 n2 处的值。*
  • 由于n1n2包含a和b的地址,因此对*n1*n2进行任何操作都会改变ab的实际值。因此,当我们在 main() 函数中打印 a b 的值时,这些值会发生变化,也就完成了交换;

使用引用而不是指针通常更容易且不易出错,因为它不涉及直接的指针操作。
指针只能用于在特别需要指针的上下文中或与 C 库交互时传递参数。


内存管理

  • C++ 允许我们在运行时动态分配内存。这就是所谓的动态内存分配。
  • 在 Java 和 Python 等其他编程语言中,编译器会自动管理分配给变量的内存。但 C++ 并非如此。
  • 在 C++ 中,当我们不再使用变量时,需要手动取消分配动态分配的内存。
  • 我们可以使用 new 和 delete 操作符分别动态分配和取消分配内存。

new关键字

我们可以使用新表达式在运行时分配内存。例如

int* point_var;
point_var = new int;
*point_var = 45;

在这里,我们使用 new 表达式为一个 int 变量动态分配了内存。
请注意,我们使用了指针 point_var 来动态分配内存。这是因为 new 表达式返回的是内存位置的地址。
我们还可以在相同的步骤中分配内存并初始化值:

int* point_var = new int{45};

使用此语法可以避免未初始化的指针。取消引用时,未初始化的指针可能会导致未定义的行为。所以这是首选语法。
使用新表达式的语法是:

data_type* pointer_variable = new data_type{value};

delete关键字

一旦我们不再需要使用动态声明的变量,就可以取消分配该变量占用的内存。
为此,我们可以使用delete关键字。它将内存归还给操作系统。这就是所谓的内存去分配。
删除表达式的语法如下:

int* point_var = new int{45};

// print the value stored in memory
cout << *point_var; 

// deallocate the memory
delete point_var;

// set pointer to nullptr
point_var = nullptr;

在这里,我们使用指针 point_var 为一个 int 变量动态分配了内存。
打印完 point_var 的内容后,我们使用 delete 删除了内存。
一个好的做法是,在取消分配内存后将指针设置为 nullptr,以避免在指针被取消引用时出现未定义的行为。

不正确地删除内存会造成内存泄漏,进而导致程序消耗大量内存。正确使用删除表达式对于防止内存泄漏和确保高效内存管理至关重要。

下面再看两个例子,加深理解:

  • ex1
#include <iostream>
using namespace std;

int main() {

    // dynamically allocate memory
    int* point_int = new int{45};
    float* point_float = new float{45.45f};

    cout << *point_int << endl;
    cout << *point_float << endl;

    // deallocate the memory
    // set pointers to nullptr
    delete point_int;

    delete point_float;
    
    return 0;
}

在这个程序中,我们为两个 int 和 float 类型的变量动态分配了内存。在为它们赋值并打印后,我们最后使用删除表达式去分配内存。

动态内存分配可以提高内存管理的效率,尤其是对于数组而言,很多时候我们可能要到运行时才能知道数组的大小。

  • ex2
#include <iostream>
using namespace std;

int main() {

    int num;
    cout << "Enter total number of students: ";
    cin >> num;
    float* ptr;
    
    // memory allocation of num number of floats
    ptr = new float[num];
    
    cout << "Enter GPA of students." << endl;
    for (int i = 0; i < num; ++i) {
    cout << "Student" << i + 1 << ": ";
    cin >> *(ptr + i);
    }
    
    cout << "\nDisplaying GPA of students." << endl;
    for (int i = 0; i < num; ++i) {
    cout << "Student" << i + 1 << ": " << *(ptr + i) << endl;
    }
    
    // ptr memory is released
    delete[] ptr;
    ptr = nullptr;
    
    return 0;
}

在这个程序中,我们要求用户输入学生人数,并将其存储在 num 变量中。然后,我们使用 new 为浮点数组动态分配了内存。
我们使用指针符号将数据输入数组(随后打印数据)。在不再需要数组后,我们使用代码去分配数组内存:

注意删除后的[]。我们使用方括号 [] 来表示内存的删除是删除一个数组。

  • ex3
#include <iostream>
using namespace std;

class Student {
    private:
    int age;
    
    public:
    
    // constructor initializes age to 12
    Student() : age(12) {}
    
    void get_age() {
      cout << "Age = " << age << endl;
    }
};

int main() {

    // dynamically declare student object
    Student* ptr = new Student();
    
    // call get_age() function
    ptr->get_age();
    
    // ptr memory is released
    delete ptr;
    
    return 0;
}

在这个程序中,我们创建了一个 Student 类,该类有一个私有变量 age
我们在默认构造函数 Student() 中将 age 初始化为 12,并使用函数 get_age() 打印了它的值。
main() 中,我们使用 new 表达式创建了一个 Student 对象,并使用指针 ptr 指向其地址。
对象创建后,Student() 构造函数将年龄初始化为 12 岁。


为什么要使用动态内存分配?

动态内存分配有几个优点,例如:

  • 灵活性: 动态内存分配允许我们在运行时根据需要分配内存。当编译时不知道数据结构的大小,或在程序执行过程中数据结构的大小发生变化时,这种灵活性就非常有用。
  • 数据结构: 数据结构(如链表、树、图和可调整大小的数组(C++ 中的向量))通常需要动态分配内存,以容纳不同数量的数据。
  • 资源管理: 我们可以在需要时分配内存,并在不再需要时取消分配。这样可以提高资源利用率。
  • 动态数组: 在 C++ 等语言中,静态数组的大小是在编译时确定的。动态内存分配允许我们创建数组,其大小可在运行时确定。

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

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

相关文章

A股3000点下方继续跳水,股民都跌懵了。

今天的A股跌懵了&#xff0c;让人几乎无法呼吸&#xff0c;盘面上出现2个重要信号&#xff0c;不废话&#xff0c;直接说重点&#xff1a; 1、今天两市又跳水了&#xff0c;但绝大多数的个股已经拒绝下跌&#xff0c;市场已然处于一个阶段底部&#xff0c;短线反弹随时可能出现…

昇思25天学习打卡营第1天|新手上路

这里写自定义目录标题 打卡昇思MindSpore扫盲快速入门 打卡 昇思MindSpore扫盲 第一节基本是一个mindspore的科普扫盲。大概介绍一通mindspore的一些架构&#xff0c;feature&#xff0c;以及其对比于其他同类框架的优势。简单扫读了一遍大概有点印象直接跳过。 快速入门 这…

面相对象程序设计

面相对象程序设计包含内容如下 局域网聊天程序设网页浏览器设计电子日历记事本的设计 以其中的一个的报告进行举例 1需求与总体设计 1 1.1需求分析 1 1.2总体设计方案 1 1.2&#xff0e;1系统功能分析以及功能表 1 1.3系统类图的关系以及表之间的联系 2 2详细设计 3 2.1 Manag…

python操作excel

1. 引言 在数据处理和自动化办公领域&#xff0c;Python以其简洁的语法和强大的库&#xff0c;成为许多数据科学家和开发者的首选语言。本文将带你一步步学习如何使用Python操作Excel。 2. 环境准备 在开始之前&#xff0c;请确保你的环境中安装了Python和以下库&#xff1a…

数据结构-----【链表:基础】

链表基础 1、链表的理论基础 1&#xff09;基础&#xff1a; 链表&#xff1a;通过指针串联在一起的线性结构&#xff0c;每个节点由两部分组成&#xff0c;一个是数据域&#xff0c;一个是指针域&#xff08;存放指向下一个节点的指针&#xff09;&#xff0c;最后一个指针…

2024年必备的15个免费 SVG 设计资源

在动态设计领域&#xff0c;SVG&#xff08;可缩放矢量图形&#xff09;已成为设计师打造响应迅速、清晰且适应性强的视觉效果的必备工具。 这些设计非常适合幻灯片 PowerPoint 演示文稿、应用程序设计、网站设计、原型设计、社交媒体帖子等。 在这篇文章中&#xff0c;我们将…

LeetCode刷题之HOT100之最小栈

听歌&#xff0c;做题&#xff01; 1、题目描述 2、逻辑分析 拿到题目一脸懵&#xff0c;有点看不懂啥意思&#xff0c;看了题解才知道啥意思。要实现在常数时间内检索到最小元素的栈&#xff0c;需要使用一个辅助栈来每次存入最小值。 使用Deque作为栈的实现是因为它提供了…

最热门的智能猫砂盆好不好用?这期统统告诉你!

身为上班族的我们&#xff0c;常常被工作和出差填满日程。忘记给猫咪铲屎也不是一次两次了。但我们必须意识到&#xff0c;不及时清理猫砂盆不仅会让猫咪感到不适&#xff0c;还可能引发泌尿系统感染、皮肤疾病等健康问题。为了解决这个问题&#xff0c;越来越多的铲屎官开始将…

Unity数据持久化3——Json

概述 基础知识 Json文件格式 Json基本语法 练习 可以搜索&#xff1a;Json在线&#xff0c;复制代码进去解析是否写错了。 Excel转Json C#读取存储Json文件 JsonUtility using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine;[Sy…

使用Birdeye访问Sui上加密市场数据

是一个链上加密交易数据聚合器&#xff0c;于2024年4月开始整合Sui数据。 个人DeFi用户可以在Birdeye的首页找到丰富的数据&#xff0c;包括关于主流区块链上的tokens、交易和交易者钱包的详细信息。 Birdeye提供API和WebSockets数据服务&#xff0c;涵盖token价格和其他DeFi…

【jupyter notebook】解决打不开以及安装扩展插件的问题

文章目录 问题描述问题 1解决问题 2解决 问题描述 问题 1 在自定义的虚拟环境下&#xff0c;安装 jupyter notebook 6.4.12 版本时&#xff0c;报以下错误&#xff1a; 解决 查了一些 解决方法&#xff0c;执行以下命令即可解决&#xff1a; conda install traitlets5.9.0 …

PS系统教程27

Photoshop与Camera Raw Camera本身是作为插件存在的&#xff0c;处理对象Raw格式&#xff08;高清格式的图片标准&#xff09; JPG是压缩格式 Camera是源数据包&#xff0c;无损高清数据包 通道 通道只有黑白灰三种颜色&#xff0c;图层类似于前台&#xff0c;通道就是后台…

代码随想录算法训练营第七十天 | 108.冗余连接、109.冗余连接||

108.冗余连接 文字讲解&#xff1a;108. 冗余连接 | 代码随想录 解题思路 节点A 和节点 B 不在同一个集合&#xff0c;那么就可以将两个 节点连在一起 已经判断 节点A 和 节点B 在在同一个集合&#xff08;同一个根&#xff09;&#xff0c;如果将 节点A 和 节点B 连在一起就…

LabVIEW与PLC通讯方式及比较

LabVIEW与PLC之间的通讯方式多样&#xff0c;包括使用MODBUS协议、OPC&#xff08;OLE for Process Control&#xff09;、Ethernet/IP以及串口通讯等。这些通讯方式各有特点&#xff0c;选择合适的通讯方式可以提高系统的效率和稳定性。以下将详细介绍每种通讯方式的特点、优点…

Typora自动保存和找回未保存文件

在用typora做记录的时候没有手动保存&#xff0c;然后电脑崩了&#xff0c;还好有找回未保存文件功能&#xff0c;在这里存一下。 找到未保存的文件版本后将其内容复制到新文件即可。

【AI落地应用实战】如何高效检索与阅读论文——302.AI学术论文工具评测

一、引言 作为一名学术领域的探索者&#xff0c;我们都知道&#xff0c;检索和阅读论文是我们获取知识、启发思考、验证假设的基石&#xff0c;也是日常学习中必不可少的基本功之一。然而在浩瀚的学术海洋中&#xff0c;如何快速、准确地找到我们需要的论文&#xff0c;就像是…

Rust编写测试及控制执行

编写测试及控制执行 在 Rust 中&#xff0c;测试是通过函数的方式实现的&#xff0c;它可以用于验证被测试代码的正确性。测试函数往往依次执行以下三种行为&#xff1a; 设置所需的数据或状态运行想要测试的代码判断( assert )返回的结果是否符合预期 让我们来看看该如何使…

这几个PR小技巧你Get到了吗?

学习是永无止境的&#xff0c;需要不间断地学习&#xff0c;获取新知识。今天带来了5个PR小技巧&#xff0c;可以先收藏起来Adobe Premiere Pro 2024的获取查看Baidu Cloud 1、双倍稳定画面更舒适 一般来说大型电视剧、电影使用的拍摄设备都是非常高端的&#xff0c;不像我们…

Chrome插件:​Vue.js Devtools 高效地开发和调试

在现代前端开发中&#xff0c;Vue.js因其灵活性和性能优势&#xff0c;受到越来越多开发者的青睐。然而&#xff0c;随着项目规模的扩大&#xff0c;调试和优化变得愈发复杂。幸运的是&#xff0c;Vue.js Devtools的出现&#xff0c;为开发者提供了一套强大的工具集&#xff0c…

Unity 弧形图片位置和背景裁剪

目录 关键说明 Unity 设置如下 代码如下 生成和部分数值生成 角度转向量 计算背景范围 关键说明 效果图如下 来自红警ol游戏内的截图 思路&#xff1a;确定中心点为圆的中心点 然后 计算每个的弧度和距离 Unity 设置如下 没什么可以说的主要是背景图设置 代码如下 …