[c++基础] 程序设计基本概念
2017-03-13 22:16
387 查看
赋值语句
1.i的值为?#include <iostream> using namespace std; int i = 1; int main() { int i = i; }
解析:
此时main函数内的i是优先考虑局部变量,除非使用作用域符号,否则是和外面值为1的i是无关的。
其次,使用g++编译,
g++ main.cpp -Wall就会出现提示说i是未定义值的警告,因此虽然此处的i会始终输出为0,但是实际上它是未定义值。
传送门讲的比较清楚,要把声明、定义、初始化、赋值区分开,其中初始化又分为default
initialization、 list initialization、 value initialization。第一个说内置类型的变量是未初始化的,第三个说内置类型的变量是初始化为0的,其实测试的结果更倾向为value initialization。
i++
1.下面两段代码输出有何不同?#include <iostream> using namespace std; int main() { int a, x; for (a = 0, x= 0; a <= 1 && !x++; a++) { a++; } cout << a << x << endl; return 0; }
#include <iostream> using namespace std; int main() { int a, x; for (a = 0, x = 0; a <= 1 && !x++;) { a++; } cout << a << x << endl; return 0; }
解析:
分别是21和12,第二段当x的非为0时,虽然不执行循环体,但x++还是要执行的。
输出:1,3,3
2.下面代码的输出结果是什么?
#include <stdio.h> int main() { int b = 3; int arr[] = {6, 7, 8, 9, 10}; int *ptr = arr; *(ptr++) += 123; printf("%d %d\n", *ptr, *(++ptr)); }
解析:
8 8
在打印前,数组的值为{129, 7, 8, 9, 10}, ptr指向第2个。
由于C中的printf函数计算参数是从右到左压栈(不同语言不同编译器的函数,参数入栈顺序是可以不同的,但是因为C支持可变参数函数,例如printf函数的参数就是不确定的,因此函数无法知道具体有多少参数,在创建被调用者的AC(activation record)时就采用了从右往左入栈参数的方式,这样第一个参数就在栈顶了,这个编译原理课的道理,这有网上参考资料,之后顺带提一下,C是不支持默认参数的,关于编译器的新学到的知识,有两点,一点是副作用,一点是顺序点,大意就是在这个顺序点时,编译器要处理完前面所有语句带来的副作用,在这个点之后才可以进行新的语句的副作用的执行,那么,在两个顺序点之间的动作执行顺序是没有规定的哦,由不同家的编译器自己玩,科科传送门
最后,我们这一题,先算
*(++ptr),那就是第ptr指向了第三个并取值,之后再算左边也是变成取第三个值了哦,那就是8
8.
后来经过测试(g++),发现从右往左压栈时,每次都计算了参数的值再压栈的。比如i++在i压栈后i自增,而++i是在压栈前自增再入栈。
类型转换
1.程序结果为?#include <iostream> #include <cstdio> #include <cstring> using namespace std; int main() { float a = 1.0f; cout << (int)a << endl; cout << &a << endl; cout << (int&)a << endl; cout << boolalpha << ((int)a == (int&)a) << endl; //此时会输出什么? float b = 0.0f; cout << (int)b << endl; cout << &b << endl; cout << (int&)b << endl; cout << boolalpha << ((int)b == (int&)b) << endl; //此时会输出什么? return 0; }
解析:
a是一个float类型的数,float在内存中的存储方式请看传送门,(0为特例,浮点数值为0时,指数和底数都为0),那么a内存中的32个字节放的是0
01111111 00000000000000000000000;一个int类型也是32个字节,int在内存中的存储方式请看传送门.
(int)a表示将浮点数强制转换为整型,小数部分将被直接截断,结果为0;
&a输出的是变量a在内存中的位置
(int&)a,是用整型的解释方式来读取浮点数a的内存,结果就为 1065353216(127<<23)
此时(int)a和(int&)a是不同的值,比较是否相等时输出false。
而值为0的浮点数在内存中的表示,所有位上全为0.因此,此时用整型的解释方式读取内存得到的结果还是0.
2.下面的程序结果是什么?
#include <stdio.h> int main() { unsigned int a = 0xFFFFFFF7; unsigned char i = (unsigned char)a; char* b = (char*)&a; printf("%08x, %08x", i, *b); }
解析:
这里因为考虑是x86系列机器(《计算机组成原理》的相关知识啦),是小端存储(俗称“低低高高”,低字节放低地址,高字节放高地址),所以字符型i的内存是整型a的小端部分,也就是F7. 而b直接对a内存取地址并截取一个字节出来,此时得到的是小端部分F7。因为%08x是将参数以整型的16进制格式输出,不足部分左侧补符号位,i是无符号的,b是有符号的,所以输出为
0x000000F7 和0xFFFFFFF7
运算符问题
1.下面程序的结果?#include <iostream> using namespace std; int main() { unsigned char a=0xA5; unsigned char b=~a>>4+1; printf("b=%d\n", b); return 0; }
解析:
b的值应该为((~a)>>(4+1)), 此时要进行算数运算就要涉及到一个“整数提升”的问题,也就是说a要转成int类型才能进行计算。
那么a转成了0x000000A5, 进行取反0xFFFFFF02, 右移5位后,赋给b,则b截取了最右边的8位为11111010, 最后按照整型的类型打印,无符号位高字节补0,则可以得到:250(十进制)
等号是最弱的会产生副作用的运算符,接着是移位,然后是四则运算,取值,单目运算等等等等
2.用一个表达式判断一个数
x是否是
2^N,不可用循环语句
解析:
!(X&(X-1))返回值为false说明是2的幂次方,否则不是
3.下面代码的作用?
int f(int x, int y) { return (x&y)+((x^y)>>1) }
解析:
相同位的与 + 不同位的平均 = 两个数的平均值
4.利用位运算实现两个整数的加法运算
解析:
递归的思想,详细解释
int Add(int a, int b) { if (b == 0) return a; int sum = a^b; int carry = (a&b)<<1; Add(sum, carry); }
a、b交换与比较
1.不使用"if"、"?:"、"switch"或其他判断语句,找出两个数中的最大值解释:
方案一:利用abs函数
int max = (abs(a-b)+(a+b))/2;
方案二:判断差值的符号位
方案三:采用bool值
bool fun(int a, int b) { return a < b; } int max(int a, int b) { bool flag = fun(a, b); return flag*b+(1-flag)*a; }
3.有两个数据,写一个交换两个数据的宏
解释:
方案一:利用异或运算(不考虑浮点数)
define swap(a, b) {a=a^b; b= a^b; a=a^b;}
方案二:利用加减法
define swap(a, b) {a=a+b; b = a-b; a = a-b;}
方案三:内存交换
define swap(a, b) \ {char tempBuf[10]; memcpy(tempBuf, &a, sizeof(a)); memcpy(&a, &b, sizeof(b)); memcpy(&b, tempBuf, sizeof(b)); }
C和C++的关系
c++语言支持函数重载,c语言不支持。c++通过加extern"C",调用c编译后的函数
ifndef/define/endif 是条件编译的一种,防止头文件重复引用、防止重定义(变量、宏或结构)
c是结构化的语言,重点在数据结构和算法,首先要考虑如何通过一个过程,对输入产生输出。
c++首先要考虑如何构造一个对象模型来解决问题。
float x 与“零值”比较
constfloat EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON)
不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。
在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern “C”?
C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为: voidfoo(int x, int y);该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。
编写strcpy函数
(1)不调用C++/C的字符串库函数,请编写函数 strcpy
char *strcpy(char *strDest, const char *strSrc) {
assert((strDest!=NULL) && (strSrc !=NULL));
char*address = strDest;
while( (*strDest++ = * strSrc++) != ‘\0’ );
return address;
}
若循环写成while(*src!='\0') *dst++=*src++; 循环体结束后,dst字符串的末尾没有正确地加上'\0'。
(2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
为了实现链式表达式,比如:
int length = strlen( strcpy( strDest,“hello world”) );
相关文章推荐
- C/C++基础知识:函数指针和指针函数的基本概念
- C++基础学习笔记----第七课(面向对象的基本概念)
- C/C++基础知识:函数指针和指针函数的基本概念
- 关于C++程序设计的基础核心之二:继承与派生的基本知识
- C++_面向对象程序设计基本概念
- C/C++基础知识:函数指针和指针函数的基本概念
- C/C++基础知识:函数指针和指针函数的基本概念
- c++基础学习6-c++面向对象基本概念
- C++中的一些基本概念,很基础,但很重要!
- JavaSE 拾遗(1)——JavaSE 面向对象程序设计语言基础(1)...基本概念和常识
- 程序员面试精要-C/C++程序设计-程序设计基本概念(面试宝典读书笔记)
- Linux程序设计学习笔记----多线程编程基础概念与基本操作
- 【C++基础】指针好难啊,一点点啃——基本概念
- C++基础学习笔记----第七课(面向对象的基本概念)
- C/C++基础知识:函数指针和指针函数的基本概念
- C/C++基础知识:函数指针和指针函数的基本概念
- C++ 程序设计基本概念 知识点 小结
- JavaScript的基本概念及程序设计基础
- c++基础:C++的一些基本概念
- 日拱一卒之C++基础一 指针与引用基本概念