祖庙网站建设,wordpress主题授权加密,试述网站建设的流程.,wordpress插件 登录#x1f497;个人主页#x1f497; ⭐个人专栏——C学习⭐ #x1f4ab;点击关注#x1f929;一起学习C语言#x1f4af;#x1f4ab; 导读
接着上一篇的内容继续学习#xff0c;今天我们需要重点学习引用。
1. 引用
在C中#xff0c;引用是一种特殊的变量#xff… 个人主页 ⭐个人专栏——C学习⭐ 点击关注一起学习C语言 导读
接着上一篇的内容继续学习今天我们需要重点学习引用。
1. 引用
在C中引用是一种特殊的变量用于别名一个已经存在的对象或变量。通过引用可以使用别名来操作原始对象而不是创建一个新的副本。 引用提供了一种简洁和高效的方式来传递参数、返回值和修改变量的值。
1.1 引用特性
引用在定义时必须初始化一个变量可以有多个引用引用一旦引用一个实体再不能引用其他实体
void TestRef()
{int a 10;int ra a;//定义引用类型printf(%p\n, a);printf(%p\n, ra);
}
int main()
{TestRef();return 0;
}上述代码我们可以发现两者的地址是相同的a和r指向是完全一样的 注意 引用类型必须和引用实体是同种类型的
1.2 做参数使用
引用作为函数参数意味着在函数调用时我们将一个变量的引用传递给函数。这样函数可以直接操作原始变量而不是对其进行拷贝。
void swap(int a, int b) {int temp a;a b;b temp;
}int main() {int x 10;int ref x; // 引用xcout x x endl; // 输出: x 10cout ref ref endl; // 输出: ref 10ref 20; // 修改ref实际上是修改xcout x x endl; // 输出: x 20cout ref ref endl; // 输出: ref 20int a 5;int b 10;swap(a, b); // 传递a和b的引用修改原始变量cout a a endl; // 输出: a 10cout b b endl; // 输出: b 5return 0;
}1.3 做返回值使用
函数返回引用时需要确保返回的引用仍然指向有效的内存空间。通常可以返回类成员变量的引用、静态变量的引用、函数内静态局部变量的引用等。 同时要注意的是返回引用时需要避免返回对局部变量的引用因为局部变量在函数结束后会被销毁返回对其引用可能会导致未定义行为。
int Max(int a, int b)
{return (a b) ? a : b;
}int main()
{int x 10, y 20;int max Max(x, y);max 30; // 修改了y的值cout y: y endl; // 输出: 30return 0;
}我们再来看一下下面的代码
int Add(int a, int b)
{int c a b;return c;
}
int main()
{int ret1 Add(1, 2);int ret2 Add(3, 4);cout Add(1, 2) is : ret1 endl;cout Add(3, 4) is : ret2 endl;return 0;
}按照我们的预期我们输出的两个数应该是3和7然而 这是为什么呢 在函数 Add 中局部变量 c 的生命周期仅限于函数内部。 当函数执行完毕后c 被销毁而返回的引用 ret 将指向一个不存在的对象。 当再次使用这个引用时就会出现未定义的行为。 因此应该避免将局部变量作为返回值的引用类型返回。
1.4 引用和指针的区别
指针使用*来定义而引用使用来定义。
int* ptr; // 声明一个指针
int ref *ptr; // 定义一个引用引用指针所指向的变量
指针可以被初始化为null或指向任意变量的地址而引用必须在声明时初始化并且不能为null。
int* ptr nullptr; // 指针为空
int x 5;
int ref x; // 引用xref指向x的地址
指针可以被重新赋值为指向其他变量的地址而引用一旦初始化后就不能重新赋值为引用其他变量。
int x 5;
int y 10;
int* ptr x; // ptr指向x的地址
ptr y; // ptr现在指向y的地址int ref x; // ref引用x
ref y; // 修改了x的值ref仍然引用x
指针可以为空指针即指向空地址而引用不可以为空。
int* ptr nullptr; // 指针为空
int ref; // 错误引用必须初始化有多级指针但是没有多级引用
1. 5 const引用
常引用可以引用普通变量可以引用常变量可以引用字面变量。 我们来看下面示例
常变量:
const int a 10;
int ra a; // 错误
const int ra a; //正确int ra a; 试图将 a 绑定到一个非常引用 ra 上这是错误的。常量对象不能通过非常引用进行修改。 因此这里应该使用 const int ra a; 来将 a 绑定到一个常引用 ra 上。 字面值:
int b 10; // 错误
const int b 10; // 正确int b 10; 试图将字面值 10 绑定到一个非常引用 b 上这是错误的。字面值是一个临时值不能通过非常引用进行修改。 正确的做法应该是将 b 声明为常引用 const int b 10;。 类型转换
double d 12.34;
int rd d; // 错误
const double rd d; // 正确int rd d; 试图将 d 绑定到一个非常引用 rd 上这是错误的。 d 是一个 double 类型的变量不能通过非常引用来绑定到 int 类型的引用上。 正确的做法是将 rd 声明为 const 引用 const double rd d;。 将 const 修饰符用于 int 类型的引用可以确保在引用对象上不会进行修改操作保护对象的不可变性避免意外的修改导致数据不一致或错误的计算结果。
常引用的声明方式与普通引用相同只是在引用类型前添加const关键字。常引用主要用于函数参数传递和对象成员访问以确保访问的对象不会被修改。
void Print(const int value)
{// value 为 const 引用不能修改其值cout Value: value endl;// value 10; // 错误不能修改 const 引用的值
}int main()
{int num 5;Print(num); // 传递 num 的值给 printValue 函数return 0;
}2. 内联函数
以inline修饰的函数叫做内联函数是C中的一种函数它的定义和调用都被嵌入到调用该函数的地方而不是通过函数调用的机制进行调用没有函数调用建立栈帧的开销。 内联函数的主要目的是为了提高函数的执行效率减少函数调用的开销。
inline int add(int a, int b) {return a b;
}
int main()
{int ret add(10, 20);return 0;
}内联函数的使用有以下几点需要注意 内联函数应该比较短小避免过长的函数体因为内联函数的定义会被嵌入到调用处过长的函数体会导致代码冗长。 内联函数适合用于频繁执行的函数例如在循环中反复调用的函数。 内联函数不能包含复杂的控制流语句例如循环或递归因为内联函数的展开是通过复制代码来实现的这样的代码会导致代码膨胀。 编译器对内联函数的展开是有一定的自由度的它可以根据实际情况决定是否展开函数体因此对于内联函数的定义和使用应该在同一个文件中以便编译器能够进行函数体的展开。 3. auto关键字
auto关键字是C中的一个关键字用于声明变量时自动推导变量的类型。 使用auto关键字可以省略变量类型的声明编译器会根据变量的初始化表达式推导出变量的类型。 例如
auto a 10; // a的类型为int
auto b 3.14; // b的类型为double
auto c hello; // c的类型为const char*使用auto关键字可以使代码更加简洁和易读特别是当变量的类型较为复杂或者不确定时auto关键字可以减少类型声明的冗余。 注意 auto关键字在编译器推导类型时是静态的即编译时就确定了类型无法在运行时动态改变变量的类型。
auto与指针和引用结合起来使用
当auto与指针和引用结合使用时auto会推导出指针或引用的类型。
int x 10;
auto *ptr x; // ptr的类型为int*float y 3.14;
auto *ptr2 y; // ptr2的类型为float*使用auto声明引用类型变量示例
int x 10;
auto ret x; // ref的类型为intfloat y 3.14;
auto ret2 y; // ref2的类型为float4. 基于范围的for循环
基于范围的for循环是一种简化的循环结构用于遍历一个序列如字符串、列表、元组等中的每个元素。
语法形式如下 for 变量 in 序列: 循环体 变量表示当前迭代的元素序列表示需要遍历的序列循环体表示需要执行的操作。 我们常用下面的这种方式来遍历数组
int main()
{int arr[] { 1, 2, 3, 4, 5 };for (int i 0; i sizeof(arr) / sizeof(arr[0]); i)arr[i] * 2;for (int* p arr; p arr sizeof(arr) / sizeof(arr[0]); p)cout *p endl;return 0;
}今天我们来看范围for的使用。
int main()
{int arr[] { 1, 2, 3, 4, 5 };for (auto e : arr)e * 2;for (auto e : arr)cout e ;return 0;
}注意
for循环迭代的范围必须是确定的迭代的对象要实现和的操作。