asp网站建设实例花网站,字体模板素材免费下载网站,网络系统管理员获取ip,百度指数查询官网入口登录C入门#xff08;二#xff09; 作者#xff1a;小卢 专栏#xff1a;《C》 喜欢的话#xff1a;世间因为少年的挺身而出#xff0c;而更加瑰丽。 ——《人民日报》 1.引用
1.1.引用的概念及应用
引用#xff08;#xff09;
引用不是新定义一个变量#xff0…C入门二 作者小卢 专栏《C》 喜欢的话世间因为少年的挺身而出而更加瑰丽。 ——《人民日报》 1.引用
1.1.引用的概念及应用
引用
引用不是新定义一个变量而是给已存在变量取了一个别名
它和它引用的变量共用同一块内存空间
类型 引用变量名(对象名) 引用实体
引用在定义时必须初始化
一个变量可以多次引用
1.2.传值返回和传址返回和传引用返回的底层原理
int Cout()
{int n 0;n;return n;
}
int main()
{int ret Cout();return 0;
}n是如何传给ret的呢
因为这里的n没有用static修饰为临时变量Cout函数调用时开辟了一段栈帧n存在于这段栈帧内。但函数调用结束后栈帧销毁。
n可以传过去是因为函数栈帧结束前用了一个临时变量n然后用这个临时变量来作为返回值给ret。
这个临时变量应该内存比较小的时候是用寄存器。
int Cout()
{static int n 0;n;return n;
}
int main()
{int ret Cout();return 0;
}这种情况下n在静态区这里n还是用一个临时变量来作为中间段来进行返回值。
这种情况有优化的空间
这种返回类型为传值返回。那如果用传引用返回呢
这种就是利用一些变量出了作用域过后还存在的情况例如引用malloc…
int Cout()
{static int n 0;n;return n;
}
int main()
{int ret Cout();return 0;
}引用返回的好处 1.减少拷贝 2.调用者可以修改返回对象
//引用返回
//1.减少拷贝
//2.调用者可以修改返回对象
#define N 10
typedef struct Array
{int a[N];int size;
}AY;
int PostAt(AY ay, int i)
{assert(i N);return ay.a[i];
}
int main()
{//int ret Cout();AY ay;for (int i 0; i N; i){PostAt(ay, i) i * 10;}for (int i 0; i N; i){cout PostAt(ay, i) ;}cout endl;return 0;
}int Add(int a, int b)
{int c a b;return c;
}
int main()
{int ret Add(1, 2);Add(3, 4);cout Add(1, 2) is : ret endl;//ret为随机值return 0;
}这里ret为随机值这里c返回的是一个别名相当于返回的是一个c的别名ret就是c的别名。
int main()
{int a 1;int b a;//指针和引用赋值/初始化权限可以缩小但不可以放大const int c 2;int d c;return 0;
} 指针和引用赋值/初始化权限可以缩小但不可以放大
1.3.指针和引用的区别
从语法角度引用是不开辟空间的指针需要开辟空间
从底层角度两种都是一样的
2.内联函数
2.1.宏的缺点
1.不能调试
2.没有类型安全的检查
3.有些场景下非常复杂
#define ADD(x,y) ((x)*(y))//正确的宏函数//宏不是传参而是替换
#define ADD(x,y) (x)*(y)///((a | b)* (a b)),错误
#define ADD(x,y) (x*y)///(510*620)错误
#define ADD(x,y) x*y
//510*62085错误替换可能会造成运算过程出错
int main()
{ADD(1, 2);//宏不是传参而是替换int a 1, b 2;ADD(a| b, a b); ///(a | b* a b)return 0;}这里宏是替换而不是传值它不会检查替换的值像(a | b a b)就会错误
使用宏函数需要尽量加括号很容易错。
2.2.内联函数
inline int Add(int x, int y)
{int z x y;return z;
}
int main()
{int ret Add(1, 2);cout ret endl;return 0;
}release中没有call Add减少了函数调用时栈帧的开辟
效率提高并且可以调试很好的替代了宏
inline内联函数是一种以空间换时间的情况这里的空间指的是编译的指令不是内存
// F.h
#include iostream
using namespace std;
inline void f(int i);
// F.cpp
#include F.h
void f(int i)
{
cout i endl;
}
// main.cpp
#include F.h
int main()
{
f(10);
return 0;
}这里会出现链接错误
内联函数不建议定义和实现分离
当定义和实现分别在.c文件和.h文件中时程序运行时当程序运行时main函数编译到f10的地方会优先编译函数定义并不会链接而在链接过程中通过头文件找到函数调用
当f为内联函数时内联函数是在编译过程完成编译的因此系统就会认为f是一个内联函数所以不会将其链接所以就会出现链接错误。
3.auto关键字
#include iostream
using namespace std;
int main()
{int a 0;auto b a;auto c a;//typeid(变量名).name()可以获取变量的实际类型cout typeid(b).name() endl;//intcout typeid(c).name() endl;//int*return 0;
}3.1auto的好处
std::mapstd::string, std::stringdict;std::mapstd::string, std::stringditdict;//上一行和下一行是一样的这就是auto的实际好处auto dit dict.begin();3.2typedef的缺点
typedef char* pstring;
int main()
{const pstring p1;//编译是否成功const pstring* p2;//编译是否成功//p1失败p2成功return 0;
}p1实际上使用typedef后const pstring p1会变成char* const p1
这里const修饰的是p1而这样的p1只有一次初始化的机会因此必须初始化。
4.范围for
自动依次取数组中数据赋值给e对象自动判断结束
for循环后的括号由冒号“ ”分为两部分
第一部分是范围内用于迭代的变量第二部分则表示被迭代的范围。
int array[] { 1,2,3,4,5,6,6,4 };for (int i 0; i sizeof(array) / sizeof(int); i){cout array[i] ;}cout endl;//范围for --语法糖for (auto e : array){cout e ;}//两种结果一样cout endl;5.nullptr
void f(int)
{cout f(int) endl;
}
void f(int*)
{cout f(int*) endl;
}//这里函数重载但结果都是fint
//C中NULL被定义为0这也不知道为什么是个错误不太好
int main()
{f(0);f(NULL);return 0;
}因此C11中打了一个补丁用nullptr来代替NULL。
注意
在使用nullptr表示指针空值时不需要包含头文件因为nullptr是C11作为新关键字引入的。在C11中sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。为了提高代码的健壮性在后续表示指针空值时建议最好使用nullptr。