网站宣传方式有哪些,商业网站开发,广州优秀网站建设,大秀平台app下载引用 1.swap交换两个变量值的时候可以用引用 2.例题中通过前序遍历数组构建二叉树#xff0c;可以用引用传别名. #include stdio.h
#include stdlib.h
typedef struct BinaryTreeNode {char data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
…引用 1.swap交换两个变量值的时候可以用引用 2.例题中通过前序遍历数组构建二叉树可以用引用传别名. #include stdio.h
#include stdlib.h
typedef struct BinaryTreeNode {char data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
} BTNode;
BTNode* BinaryTreeCreate(char* a, int* pi)
{if(a[*pi]#)
{ (*pi);return NULL;}
BTNode* newnode(BTNode*)malloc(sizeof(BTNode));
newnode-dataa[(*pi)];
newnode-leftBinaryTreeCreate(a,pi);
newnode-rightBinaryTreeCreate(a,pi);
return newnode;}
void InOrder(BTNode* root)
{if(rootNULL)
return ;
InOrder(root-left);
printf(%c ,root-data);
InOrder( root-right);}int main() {char arr[100];scanf(%s,arr);int i0;BTNode*bk BinaryTreeCreate(arr,i);InOrder(bk);
} i变量是在main函数栈帧中创建的在调用BinaryTreeCreate(arr,i);完不会被销毁可以用引用. 修改如下 #include stdio.h
#include stdlib.h
typedef struct BinaryTreeNode {char data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
} BTNode;
BTNode* BinaryTreeCreate(char* a, int pi)
{if(a[pi]#)
{ pi;return NULL;}
BTNode* newnode(BTNode*)malloc(sizeof(BTNode));
newnode-dataa[pi];
newnode-leftBinaryTreeCreate(a,pi);
newnode-rightBinaryTreeCreate(a,pi);
return newnode;}
void InOrder(BTNode* root)
{if(rootNULL)
return ;
InOrder(root-left);
printf(%c ,root-data);
InOrder( root-right);}int main() {char arr[100];scanf(%s,arr);int i0;BTNode*bk BinaryTreeCreate(arr,i);InOrder(bk);
}用到引用的地方都是输出型参数 引用做返回值 注意如果函数返回时出了函数作用域如果返回对象还在(还没还给系统)则可以使用引用返回如果已经还给系统了则必须使用传值返回。 下面代码输出什么结果为什么
#includeiostream
using namespace std;
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;return 0;
}分析这个程序是不对的我们刚才说过要使用引用的话必须是输出型参数也就是出了作用域不销毁的参数而这里的c是局部变量是临时变量出了作用域要被销毁的。如果传引用回去的话c地址上的值会被修改。因为c地址上的值随着栈帧的销毁而被修改。这里为什么会是7因为再次调用同个函数时用的是和上一个调用的add函数同样的栈帧所以原地址上的c地址上的值会被新的值7覆盖于是ret就是7了.
#includeiostream
using namespace std;
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;return 0;
}如果删除一行打印出来的值不一定是3取决于不同的编译器。栈帧中变量空间是否被回收不知道.
传值返回 1.传参返回时不是直接返回会产生临时变量. 2.静态变量出栈不会被销毁也产生临时变量.
传引用返回 1.用于出了作用域。不销毁的变量. 2.减少了临时变量的拷贝. 3.调用者可以修改返回对象比如上面的ret. 4.栈帧销毁内存消除不确定. 5.出栈帧不存在的变量会出现错误就不要用引用返回. 6.静态全局上一次栈帧malloc来的变量可以用引用. 7.传引用返回比传值返回提高了效率不用建立临时变量. 常引用
权限放大
#includeiostream
using namespace std;int main()
{const int c 2;int d c;}将只读的变量c,使用引用d变量的权限不能变成既能读又能写.权限不能放大. 在举一个指针权限放大的
#includeiostream
using namespace std;int main()
{const int* pi NULL;int* p2 p1;}同样也是权限放大编译器会保错. 权限保持
只读-只读
#includeiostream
using namespace std;int main()
{const int* pi NULL;const int* p2 pi;}权限缩小
#includeiostream
using namespace std;int main()
{int x 1;const int y x;}指针也一样
权限放大缩小适用于指针和引用.
下面这个可以吗
#includeiostream
using namespace std;int main()
{int i 0;double rd i;}强制类型转换是将i的值做强制类型转换后的值存在一个临时变量中而这里的rd是临时变量的别名而不是i的别名临时变量具有常性也就是只读这里属于权限放大了加上const的话属于权限平移.
#includeiostream
using namespace std;int main()
{int i 0;const double rd i;}引用和指针的区别 在语法概念上引用就是一个别名没有独立空间和其引用实体共用同一块空间.在底层实现上实际是有空间的因为引用是按照指针方式来实现的. 引用和指针的不同点: 引用概念上定义一个变量的别名指针存储一个变量地址。引用在定义时必须初始化指针没有要求引用在初始化时引用一个实体后就不能再引用其他实体而指针可以在任何时候指向任何一个同类型实体没有NULL引用但有NULL指针在sizeof中含义不同引用结果为引用类型的大小但指针始终是地址空间所占字节个数(32位平台下占4个字节)引用自加即引用的实体增加1指针自加即指针向后偏移一个类型的大小有多级指针但是没有多级引用访问实体方式不同指针需要显式解引用引用编译器自己处理引用比指针使用起来相对更安全 内联函数
以inline修饰的函数叫做内联函数编译时C编译器会在调用内联函数的地方展开没有函数调用建立栈帧的开销内联函数提升程序运行的效率。
内联函数的引出 我们之前学过宏定义函数
#includeiostream
using namespace std;
#define ADD(a,b) ((a)(b))
int main()
{int retADD(1, 2);printf(%d, ret);}宏定义的函数不用创建栈帧. 但是宏定义的函数只能是死替换
#includeiostream
using namespace std;
#define ADD(a,b) (a*b)
int main()
{int retADD(12, 23);printf(%d, ret);}这样死套就会出错内联函数的引入也不会创建栈帧
#includeiostream
using namespace std;
int add(int a, int b)
{int c a b;return c;}
int main()
{int ret add(1, 2);return ret;}对应汇编语言有call指令说明有创建栈帧. 使用inline函数是否创建栈帧 查看方式
在release模式下查看编译器生成的汇编代码中是否存在call Add在debug模式下需要对编译器进行设置否则不会展开(因为debug模式下编译器默认不 会对代码进行优化以下给出vs2013的设置方式) 使用inline函数后没有call指令说明没有创建栈帧 inline是一种以空间换时间的做法如果编译器将函数当成内联函数处理在编译阶段会用函数体替换函数调用缺陷可能会使目标文件变大优势少了调用开销提高程序运行效率。 inline对于编译器而言只是一个建议不同编译器关于inline实现机制可能不同一般建议将函数规模较小(即函数不是很长具体没有准确的说法取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰否则编译器会忽略inline特性.
#includeiostream
using namespace std;inline int add(int a, int b)
{int c a b;c a b;c a b;c a b;c a*b;c a*b;c a b;c a b;return c;}
int main()
{int ret add(1, 2);return ret;}此函数没有liline展开成函数体有call指令创建了函数栈帧. 面试题
宏的优缺点 优点 1.增强代码的复用性。 2.提高性能。
缺点 1.不方便调试宏。因为预编译阶段进行了替换 2.导致代码可读性差可维护性差容易误用。 3.没有类型安全的检查 。
C有哪些技术替代宏 短小函数定义 换用内联函数