1.什么是异质链表?
异质链表是指可以链表指针所指向的数据类型并不一致,比如一个链表中可以既存储整形数据,又可以存储浮点性的数据。在面向对象的语言中甚至就是可以指向不同的对象。而普通链表其数据类型必须一致。
先思考一下, 如果将这些不同类型的对象用链表进行直接链接, 显然不太好操作(不能用for循环来搞), 换个思路吧, 我们可以抽象出这些对象的共同点, 将这些共同点构造成结点, 然后把这些结点串起来。 并且需要保证, 通过这些结点, 可以访问到对应的对象,也就是用抽象类指针构造派生类对象链表。
2.默认参数只能从右往左默认,实际调用时只能从左往右传参(C语言不支持缺省参数)
3.float型数据通常用IEEE754单精度浮点数格式表示。若编译器将float型变量x分配到一个32位浮点寄存器FR1中,且x=-8.25,则FR1的内容是()。
本题题意即考查IEEE754单精度浮点数的表示。先将x转换成二进制为-1000.01= -1.000 01×23,其次计算阶码E,根据IEEE754单精度浮点数格式,有E-127=3,故E=130,转换成二进制为1000 0010。最后,根据IEEE754标准,最高位的“1”是被隐藏的。
IEEE754单精度浮点数格式:数符(1位)+阶码(8位)+尾数(23位)。
故,FR1内容为1; 1000 0010; 0000 10000 0000 0000 0000 000。
即,1100 0001 0000 0100 0000 0000 0000 0000=C104000H。
本题易误选D,未考虑IEEE754标准隐含最高位1的情况,偏置值是128。
4.给大家一个运算符优先级的口诀:
括号成员第一; // ()和 .
全体单目第二; // ++ – +(正) -(负) * &
乘除余三 // * / %
加减四 // + -
位移五 // >> <<
关系六 // > < >= <=
等于不等排第七 // == !=
位与异或和位或三分天下 *** 十 //& ^ | 逻辑或跟与十二和十一 // || &&
条件高于赋值
逗号运算符最低
5.#define只是在预处理阶段将a替换为相应数值,具体替换的值只与define在文件中的位置有关,与是否在函数内无关。
6.局部变量默认是随机值,如果初始化表达式的个数比数组元素少,则对外部变量、静态变量和自动变量来说,没有初始化的表达式的元素将被初始化为0。Debug版可能有差异。
- int a[][4]={0,0};
维数组a中初值的个数不能被第二维大小的值整除,则第一维的大小等于所得商数再加1。此例中,初值有2个0,初值个数是2,第二维大小为4,2被4除得0,所以第一维大小是0+1=1。 同时在这种初始化方法下,为予以明确初值的数组元素将会被赋值为0,所以此例中a剩余的两个元素也被初始化为0。
8.标识符由字母,数字,或下划线组成,并且只能已字母或下划线开头,不能是数字。
9.考的 int const *p , const int p 以及 int * const p 的区别,前两个意思是一样的表示p的内容不能修改,最后那个指的指针p是个常变量,不能修改它的值。
10.继承方式:
private能够对外部和子类保密,即除了成员所在的类本身可以访问之外,别的都不能直接访问。protected能够对外部保密,但允许子类直接访问这些成员。public、private和protected对成员数据或成员函数的保护程度可以用下表来描述:
11.若a 是float 型变量,b 是unsigned 型变 量,以下输入语句中合法的是().
若a 是float 型变量,b 是unsigned 型变
量,以下输入语句中合法的是(C).
A:scanf("%6.2f%d",&a,&b);
B:scanf("%f%n",&a,&b);
C:scanf("%f%3o",&a,&b);
D:scanf("%f%f",&a,&b);
解析:
C:scanf("%f%3o",&a,&b);——%f对应&a,没啥疑问,关键是%3o.%3o是接受3位八进制整数的意思,与&b匹配,所以正确.
A错在scanf()不允许指定精度,而控制符%6.2f违反了这个规定;
B错在%n这个控制符是啥意思?没有这个控制符!
D错在把无符号变量的控制符写成float变量控制符了
%d整型输出,%ld长整型输出,
%o以八进制数形式输出整数,
%x以十六进制数形式输出整数,
%u以十进制数输出unsigned型数据(无符号数)。
%c用来输出一个字符,
%s用来输出一个字符串,
%f用来输出实数,以小数形式输出,
%e以指数形式输出实数,
%g根据大小自动选f格式或e格式,且不输出无意义的零。
其中%o和%x都是二进制的延伸,即八进制和十六进制,可以适用于unsigned变量输出
12.以 下 程 序 段 的 输 出 结 果 是 ()。(在vs环境下编译)
int a=21,b=11;
printf("%d\n",–a+b,–b+a);
操作数的求值顺序与运算符的优先级和结合律无关。在一个形如f() + g() * h() + j()的表达式中:
优先级保证g()的返回值与h()的返回值相乘
结合律保证f()的返回值与g() * h()的结果相加,并将结果与j()的返回值相加
但是没有任何保证可以确定这些函数调用的顺序
如果f,g,h,j既没有共同关联参数的(do affect the same object),也不是输入输出系统(IO)函数,那么函数调用的顺序彼此互不影响。如果其中的任何函数都引用了相同的对象,那么这个表达式就是错误的。它会产生未定义的行为。
函数调用是一种表达式。
这里printf调用中嵌套了两个关键的字表达式
–a+b,–b+a
函数调用的结合律只能保证这两个子表达式的结果会被传递到函数调用的形参之中
但是并不能决定他俩的求值顺序
也就是说,子表达式的求值顺序C++标准并未规定,而是完全看编译器实现,真真的靠天吃饭
如果函数实参从右向左压入调用栈
先对右表达式求值,那么最后打印30
如果函数实参从左向右压入调用栈
先对左表达式求值,那么最后打印31
甚至可能有编译器自己的优化导致更加乱序地求值
所以
写出题目这样的表达式本身是一种错误的行为
产生未定义的结果
出这样的题目只能混淆视听
与上面结论相互略有出入
上学期学习了汇编语言,并在操作系统实验中使用了汇编+C语言混合编程,中间也了解了一些C语言与汇编语言的对应关系。
由于汇编语言是底层的编程语言,各种函数参数都要直接控制栈进行存取,在混合编程中,要用汇编来调用C函数,当然就要知道参数的压栈情况了。
当知道C函数的参数压栈顺序是从右到左时,我觉得很奇怪,因为大多数情况下,人们的习惯是从左到右的,难不成设计者学咱们中国古代写字从右到左的习惯不成?
当时只是记下了这个规则而已,并没有去探究这其中的缘由,后来在实验中自己用汇编实现了printf和scanf函数的基本功能,尝到了压栈从右到左的好处,但是仍然没有多想。
直到前阵子看斯坦福大学公开课的时候,老师解释了一番才恍然大悟!
那么,这是为什么呢?
要回答这个问题,就不得不谈一谈printf()函数,printf函数的原型是:printf(const char* format,…)
没错,它是一个不定参函数,那么我们在实际使用中是怎么样知道它的参数个数呢?这就要靠format了,编译器通过format中的%占位符的个数来确定参数的个数。
现在我们假设参数的压栈顺序是从左到右的,这时,函数调用的时候,format最先进栈,之后是各个参数进栈,最后pc进栈,此时,由于format先进栈了,上面压着未知个数的参数,想要知道参数的个数,必须找到format,而要找到format,必须要知道参数的个数,这样就陷入了一个无法求解的死循环了!!
而如果把参数从右到左压栈,情况又是怎么样的?函数调用时,先把若干个参数都压入栈中,再压format,最后压pc,这样一来,栈顶指针加2便找到了format,通过format中的%占位符,取得后面参数的个数,从而正确取得所有参数。
所以,如果不存在…这种不定参的函数,则参数的压栈顺序无论是从左到右还是从右到左都是没关系的。
作者:jiange_zh
来源:CSDN
原文:https://blog.csdn.net/jiange_zh/article/details/47381597
版权声明:本文为博主原创文章,转载请附上博文链接!
c/c++的函数参数压栈顺序.
曾看到一篇文章上面说:c/c++参数压栈顺序是从右到左,pascal参数压栈是从左到右.
为了这句话丢了很多次人.无所谓了,反正咱脸皮厚.
总结一下: 编译出来的c/c++程式的参数压栈顺序只和编译器相关!
下面列举了一些常见的编译器的调用约定
VC6:
调用约定 堆栈清除 参数传递
__cdecl 调用者 从右到左,通过堆栈传递
__stdcall 函数体 从右到左,通过堆栈传递
__fastcall 函数体 从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈
thiscall 函数体 this指针默认通过ECX传递,其他参数从右到左入栈
__cdecl是C/C++的默认调用约定; VC的调用约定中并没有thiscall这个关键字,他是类成员函数默认调用约定;
C/C++中的main(或wmain)函数的调用约定必须是__cdecl,不允许更改;
默认调用约定一般能够通过编译器配置进行更改,假如您的代码依赖于调用约定,请明确指出需要使用的调用约定;
C++Builder6:
调用约定 堆栈清除 参数传递
__fastcall 函数体 从左到右,优先使用寄存器(EAX,EDX,ECX),然后使用堆栈 (兼容Delphi的register)
(register和__fastcall等同)
__pascal 函数体 从左到右,通过堆栈传递
__cdecl 调用者 从右到左,通过堆栈传递(和C/C++默认调用约定兼容)
__stdcall 函数体 从右到左,通过堆栈传递(和VC中的__stdcall兼容)
__msfastcall 函数体 从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈(兼容VC的__fastcall)
上述资料来源于HouSisong的一篇文章:http://www.allaboutprogram.com/index.PHP?option=content&task=view&id=29&Itemid=31.
由于能力和资源有限,只能找到这些东西,主要的差异体现在fastcall上面,vc是前两个参数放入寄存器,后面的压栈,bcb是前3哥参数使用寄存器,
更有变态的,一个朋友朋友说有的参数超过7个以后前5个从左到右传递,后面的从右到走,上面说的不可不信,不可全信.
如何确定您的编译采用的那种顺序那?
#include <stdio.h>
int f(int i,int j,int k);
int main()
{
static int i=0;
f(i++,i++,i++);
return 0;
}
int f(int i,int j,int k)
{
int l;
int g;
printf("k=%d:[%x]/n",k,&k);
printf("j=%d:[%x]/n",j,&j);
printf("i=%d:[%x]/n",i,&i);
printf("___________/n");
printf("l:%x/n",&l);
printf("g:%x/n",&g);
}
看看k->i的地址的增长顺序和l->g的顺序是否相同,假如相同则是从右到左,否则从左到右.
PS:
本来通过打印参数的值来判断那个先入栈,结果被一个朋友批评了,
他说:压栈顺序和参数计算顺序不是一回事,所以还是看地址更有确保.
//看过的朋友当作笑谈吧。
13.C++ int 型负数除法与求模运算
一、结论:
1、除法运算:向零取整(向0方向取最接近精确值的整数,类比向上取整和向下取整);
比如:10/(-4) = -2;10/4 = 2;
2、求模运算: (1) |小| % |大| = |小| ,符号同前; (2) |大 | % |小| = |余| ,符号同前 ; (|n|指n的 绝对值, 求模时参照该公式: “余数=被除数-商*除数 )
比如: 3%4 = 3, (-3)%(-4) = -3,(-3)%4 = -3,3%(-4) = 3; 5%3 = 2, (-5)%(-3) = -2,(-5)%3 = -2,5%(-3) = 2;
14.函数定义不能嵌套,但函数调用可以嵌套
15.c++关键字分类:
数据类型:void,int,char,float,double,bool,w_char
类型定义:struct,union,enum,class,typedef
常量值:true,false
类型修饰符:long,short,singed,unsigned
类型限定符:const,volatile,restrict
存储说明符:auto,register,static,extern,thread_local,mutable
其它修饰符:inline,asm
循环控制:for,while,do
跳转控制:break,continue,return,goto
分支结构: if,else,switch,case,default
内存管理:new, delete
运算符:sizeof,and,and_eq,bitand,bitor,compl,not,not_eq,or,or_eq,xor,xor_eq
访问限定符:this,friend,virtual,mutable,explicit,operator
类访问修饰符:private,protected,public
模板:template,typename
命名空间:namespace,using
异常处理:throw,try,catch
作者:zhanw15
来源:CSDN
原文:https://blog.csdn.net/zhanw15/article/details/80502049
版权声明:本文为博主原创文章,转载请附上博文链接!