建立一个头文件(扩展名为’.h’)。在该文件中,声明一组函数,具有可变参数,返回值包括void、char、int和float类型。建立一个包含上述头文件的.cpp文件,创建所有这些函数的定义。每个定义应该简单地输出函数名,参数列表,并返回类型以便知道它已经被调用。创建另外一个.cpp文件,它包含头文件且定义int main(),在其中调用已经定义的所有函数。编译和运行这个程序。
创建头文件3-1.h:
#define FUNC(type) type type##Func()
#define CALL_FUNC(type) type##Func()
FUNC(void);
FUNC(char);
FUNC(int);
FUNC(float);
创建3-1.cpp文件:
#include "3-1.h"
#include
using namespace std;
FUNC(void) {
cout << "void voidFunc() 被调用" << endl;
}
FUNC(char) {
cout << "char charFunc() 被调用" << endl;
return 'a';
}
FUNC(int) {
cout << "int intFunc() 被调用" << endl;
return 3;
}
FUNC(float) {
cout << "float floatFunc() 被调用" << endl;
return 3.14;
}
创建含有main函数的.cpp文件:
#include "3-1.h"
#include
using namespace std;
int main() {
CALL_FUNC(void);
char a = CALL_FUNC(char);
cout << "返回值为" << a << endl;
int b = CALL_FUNC(int);
cout << "返回值为" << b << endl;
float c = CALL_FUNC(float);
cout << "返回值为" << c << endl;
}
输出:
void voidFunc() 被调用
char charFunc() 被调用
返回值为a
int intFunc() 被调用
返回值为3
float floatFunc() 被调用
返回值为3.14
编写一个程序使用两重for循环和模运算符(%)去寻找和输出质数(只能被1和它本身整除的整数)。
#include
using namespace std;
int main() {
cout << "请输入一个整数:";
int a;
cin >> a;
cout << "在2到" << a << "之间有如下质数:" << endl;
for (int i = 2; i <=a; i++) {
bool isPrime = true;
for (int j = 2; j < i; j++) {
if (i % j == 0) {//能整除,说明不是质数
isPrime = false;
break;
}
}
if (isPrime) {
cout << i << " ";
}
}
cout << endl;
}
输出:
请输入一个整数:20
在2到20之间有如下质数:
2 3 5 7 11 13 17 19
编写一个程序,使用一个while循环从标准输入(cin)中把单词读入到string中。这是一个“无穷”while循环,可以使用break语句中断(和退出程序)。对于读入的每个单词,先用一系列的if语句把该单词“映射”为一个整数值,然后用该整数值作为一个switch语句的选择条件(这些操作并不意味着良好的设计风格,这仅仅是为练习这些控制流程)。在每个case中,输出一些有意义的信息。判定哪些是“有趣”的单词以及这些单词的意义。同时判定哪个单词是程序结束的标志。用文件作为输入来测试该程序(如果想节省输入,这个文件将作为程序的源文件)。
#include
#include
using namespace std;
int main() {
string word;
while (cin >> word) {
if (word == "quit") {
cout << "退出程序";
break;
}
int type = 0;
if (word.size() == 5) {
type = 1;
} else if (word.size() > 5) {
type = 2;
}
switch (type) {
case 0:
cout << word << ":这个单词长度小于5" << endl;
break;
case 1:
cout << word << ":是个有趣的单词,长度等于5" << endl;
break;
case 2:
cout << word << ":这个单词长度大于5" << endl;
break;
}
}
}
输出:
what
what:这个单词长度小于5
are
are:这个单词长度小于5
you
you:这个单词长度小于5
doing
doing:是个有趣的单词,长度等于5
quit
退出程序
修改Menu.cpp程序,使用switch语句代替if语句。
#include
using namespace std;
int main() {
char c; // To hold response
while(true) {
cout << "主菜单:" << endl;
cout << "l: 左, r: 右, q: 退出 -> ";
cin >> c;
if (c == 'q') break;
switch (c) {
case 'l': {
cout << "左键菜单:" << endl;
cout << "选择 a 或 b:";
cin >> c;
switch (c) {
case 'a':
cout << "你选择了'a'" << endl;
continue; // Back to main menu
case 'b':
cout << "你选择了'b'" << endl;
continue; // Back to main menu
default:
cout << "你没有选择 a 或 b!"
<< endl;
continue; // Back to main menu
}
break;
}
case 'r': {
cout << "右键菜单:" << endl;
cout << "选择 c 或 d: ";
cin >> c;
switch (c) {
case 'c':
cout << "你选择了'c'" << endl;
continue; // Back to main menu
case 'd':
cout << "你选择了'd'" << endl;
continue; // Back to main menu
default:
cout << "你没有选择 c 或 d!"
<< endl;
continue; // Back to main menu
}
break;
}
}
cout << "你必须选择 l 或 r 或 q!" << endl;
}
cout << "退出菜单..." << endl;
}
编写一个程序计算在“优先级”一节中的两个表达式的值。
#include
using namespace std;
#define PRINT(X) \
cout << #X " = " << X << endl;
int main() {
int X = 1, Y = 2, Z = 3;
PRINT(X + Y - 2/2 + Z);
PRINT(X + (Y - 2)/(2 + Z));
}
输出:
X + Y - 2/2 + Z = 5
X + (Y - 2)/(2 + Z) = 1
修改YourPets2.cpp程序以使用不同的数据类型(char、int、float、double和这些类型的变型)。运行该程序并画出结果内存分布图。如果能在多种机器、操作系统或者编译器上运行该程序,用尽可能多的变化进行这个试验。
#include
using namespace std;
#define PRINT(type) cout << #type " 大小:" << sizeof(type) << endl;
#define PRINT_ADDR(x, y, z) cout << &x << " " << &y << " " << &z << endl;
int main() {
char ci, cj, ck;
short int si, sj, sk;
int i, j, k;
long int li, lj, lk;
long long lli, llj, llk;
float fi, fj, fk;
double di, dj, dk;
long double ldi, ldj, ldk;
PRINT(char);
// PRINT_ADDR(ci, cj, ck); 不可以直接使用cout << &ci 这种形式打印地址,因为
// &ci,会变成一个char*指针,而使用cout << (char *) 会被认为要打印一个字符数组,
// 所以为了打印,可能把它转成void*来打开地址。
cout << (void*)&ci << " " << (void*)&cj << " " << (void*)&ck << endl;
PRINT(short int);PRINT_ADDR(si, sj, sk);
PRINT(int);PRINT_ADDR(i, j, k);
PRINT(long int);PRINT_ADDR(li, lj, lk);
PRINT(long long);PRINT_ADDR(lli, llj, llk);
PRINT(float);PRINT_ADDR(fi, fj, fk);
PRINT(double);PRINT_ADDR(di, dj, dk);
PRINT(long double);PRINT_ADDR(ldi, ldj, ldk);
}
输出:
char 大小:1
0xbce13ff83f 0xbce13ff83e 0xbce13ff83d
short int 大小:2
0xbce13ff83a 0xbce13ff838 0xbce13ff836
int 大小:4
0xbce13ff830 0xbce13ff82c 0xbce13ff828
long int 大小:4
0xbce13ff824 0xbce13ff820 0xbce13ff81c
long long 大小:8
0xbce13ff810 0xbce13ff808 0xbce13ff800
float 大小:4
0xbce13ff7fc 0xbce13ff7f8 0xbce13ff7f4
double 大小:8
0xbce13ff7e8 0xbce13ff7e0 0xbce13ff7d8
long double 大小:16
0xbce13ff7c0 0xbce13ff7b0 0xbce13ff7a0
创建两个函数,一个接受一个string*参数,另一个接受一个string&参数。每个函数必须用它特有的方式去改变外部的string对象。在main()中,创建和初始化一个string对象,输出它,然后把它传给每个函数,输出结果。
#include
#include
using namespace std;
void modify(string* ps) {
*ps = "string* " + *ps;
}
void modify(string& rs) {
rs = "string& " + rs;
}
int main() {
string a("hello");
cout << "原始字符串:" << a << endl;
modify(&a);
cout << "用指针改变:" << a << endl;
modify(a);
cout << "用引用改变:" << a << endl;
}
输出:
原始字符串:hello
用指针改变:string* hello
用引用改变:string& string* hello
编写一个使用所有三个图形字符(trigraph)的程序,看看你的编译器是否支持它们。
trigraph是什么,看一下这个文章。
#include
using namespace std;
int main() {
cout << "??=" << endl;//如果支持,应该输出#
cout << "??(" << endl;//如果支持,应该输出[
cout << "??)" << endl;//如果支持,应该输出]
cout << "??<" << endl;//如果支持,应该输出{
cout << "??>" << endl;//如果支持,应该输出}
cout << "??/" << endl;//如果支持,应该输出/
cout << "??!" << endl;//如果支持,应该输出|
cout << "??'" << endl;//如果支持,应该输出^
cout << "??-" << endl;//如果支持,应该输出~
}
使用如下makefile编译:
CPP = g++
OFLAG = -o
.SUFFIXES : .o .cpp .c
.cpp.o :
$(CPP) $(CPPFLAGS) -c $<
.c.o :
$(CPP) $(CPPFLAGS) -c $<
3-8: 3-8.o
$(CPP) $(OFLAG) $@ $^
rm $^
./$@
3-8.o: 3-8.cpp
输出:
3-8.cpp:5:14: warning: trigraph ??= ignored, use -trigraphs to enable [-Wtrigraphs]
5 | cout << "??=" << endl;//如果支持,应该输出#
|
3-8.cpp:6:14: warning: trigraph ??( ignored, use -trigraphs to enable [-Wtrigraphs]
6 | cout << "??(" << endl;//如果支持,应该输出[
|
3-8.cpp:7:14: warning: trigraph ??) ignored, use -trigraphs to enable [-Wtrigraphs]
7 | cout << "??)" << endl;//如果支持,应该输出]
|
3-8.cpp:8:14: warning: trigraph ??< ignored, use -trigraphs to enable [-Wtrigraphs]
8 | cout << "??<" << endl;//如果支持,应该输出{
|
3-8.cpp:9:14: warning: trigraph ??> ignored, use -trigraphs to enable [-Wtrigraphs]
9 | cout << "??>" << endl;//如果支持,应该输出}
|
3-8.cpp:10:14: warning: trigraph ??/ ignored, use -trigraphs to enable [-Wtrigraphs]
10 | cout << "??/" << endl;//如果支持,应该输出/
|
3-8.cpp:11:14: warning: trigraph ??! ignored, use -trigraphs to enable [-Wtrigraphs]
11 | cout << "??!" << endl;//如果支持,应该输出|
|
3-8.cpp:12:14: warning: trigraph ??' ignored, use -trigraphs to enable [-Wtrigraphs]
12 | cout << "??'" << endl;//如果支持,应该输出^
|
3-8.cpp:13:14: warning: trigraph ??- ignored, use -trigraphs to enable [-Wtrigraphs]
13 | cout << "??-" << endl;//如果支持,应该输出~
|
g++ -o 3-8 3-8.o
rm 3-8.o
./3-8
??=
??(
??)
??<
??>
??/
??!
??'
??-
按照提示,使用-trigraphs来编译,修改makefile:
CPP = g++
OFLAG = -o
#加一个CPPFLAGS
CPPFLAGS = -trigraphs
.SUFFIXES : .o .cpp .c
.cpp.o :
$(CPP) $(CPPFLAGS) -c $<
.c.o :
$(CPP) $(CPPFLAGS) -c $<
把cpp文件第10行转义一下:
cout << "\??/" << endl;//如果支持,应该输出/
输出:
#
[
]
{
}
\
|
^
~
编译和运行Static.cpp程序。从代码中删除static关键词,再次编译和运行,解释发生的现象。
#include
using namespace std;
void func() {
int i = 0;
cout << "i = " << ++i << endl;
}
int main() {
for(int x = 0; x < 10; x++)
func();
}
输出:
i = 1
i = 1
i = 1
i = 1
i = 1
i = 1
i = 1
i = 1
i = 1
i = 1
删除了static关键字之后,i变成了一个普通的局部变量,每次调用func函数时,都会初始化为0,输出时加1,所以每次调用都输出1。
试编译FileStatic.cpp和FileStatic2.cpp程序并把它们连接起来。得到的错误消息的含义是什么?
错误消息是:
D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: FileStatic2.o:FileStatic2.cp:(.rdata$.refptr.fs[.refptr.fs]+0x0): undefined reference to `fs'
未定义fs引用,也就是说fs定义找不到。因为在FileStatic.cpp中,fs是static的,只能文件内可见,所以在FileStatic2.cpp中虽然声明了fs,但是在连接步骤,连接器是找不到的。
修改Boolean.cpp程序,用double值代替int值。
#include
using namespace std;
int main() {
double i,j;
cout << "Enter an double: ";
cin >> i;
cout << "Enter another double: ";
cin >> j;
cout << "i > j is " << (i > j) << endl;
cout << "i < j is " << (i < j) << endl;
cout << "i >= j is " << (i >= j) << endl;
cout << "i <= j is " << (i <= j) << endl;
cout << "i == j is " << (i == j) << endl;
cout << "i != j is " << (i != j) << endl;
cout << "i && j is " << (i && j) << endl;
cout << "i || j is " << (i || j) << endl;
cout << " (i < 10) && (j < 10) is "
<< ((i < 10) && (j < 10)) << endl;
}
修改Boolean.cpp和Bitwise.cpp程序,使用显示运算符(如果你的编译器与C++标准兼容,那么它会支持这些运算符)。
Boolean.cpp
#include
using namespace std;
int main() {
int i,j;
cout << "Enter an integer: ";
cin >> i;
cout << "Enter another integer: ";
cin >> j;
cout << "i > j is " << (i > j) << endl;
cout << "i < j is " << (i < j) << endl;
cout << "i >= j is " << (i >= j) << endl;
cout << "i <= j is " << (i <= j) << endl;
cout << "i == j is " << (i == j) << endl;
cout << "i != j is " << (i not_eq j) << endl;
cout << "i && j is " << (i and j) << endl;
cout << "i || j is " << (i or j) << endl;
cout << " (i < 10) && (j < 10) is "
<< ((i < 10) and (j < 10)) << endl;
}
Bitwise.cpp
#include "printBinary.h"
#include
using namespace std;
// A macro to save typing:
#define PR(STR, EXPR) \
cout << STR; printBinary(EXPR); cout << endl;
int main() {
unsigned int getval;
unsigned char a, b;
cout << "Enter a number between 0 and 255: ";
cin >> getval; a = getval;
PR("a in binary: ", a);
cout << "Enter a number between 0 and 255: ";
cin >> getval; b = getval;
PR("b in binary: ", b);
PR("a | b = ", a bitor b);
PR("a & b = ", a bitand b);
PR("a ^ b = ", a xor b);
PR("~a = ", compl a);
PR("~b = ", compl b);
// An interesting bit pattern:
unsigned char c = 0x5A;
PR("c in binary: ", c);
a or_eq c;
PR("a |= c; a = ", a);
b and_eq c;
PR("b &= c; b = ", b);
b xor_eq a;
PR("b ^= a; b = ", b);
}
使用在Rotation.cpp程序中的函数去修改Bitwise.cpp程序。确保用这种方式能清楚地显示在旋转过程中的结果。
#include "printBinary.h"
#include
using namespace std;
// A macro to save typing:
#define PR(STR, EXPR) \
cout << STR; printBinary(EXPR); cout << endl;
extern unsigned char rol(unsigned char val);
extern unsigned char ror(unsigned char val);
int main() {
unsigned char a;
cout << "输入一个 0 到 255 之间的数: ";
cin >> a;
cout << (int)a << endl;
PR("当前数的二进制: ", a);
cout << "开始左转:" << endl;
for (int i = 0; i < 8; i++) {
a = rol(a);
PR("左转1位:", a);
}
PR("当前数的二进制:", a)
cout << "开始右转:" << endl;
for (int i = 0; i < 8; i++) {
a = ror(a);
PR("右转1位:", a);
}
}
输出:
当前数的二进制: 01100001
开始左转:
左转1位:11000010
左转1位:10000101
左转1位:00001011
左转1位:00010110
左转1位:00101100
左转1位:01011000
左转1位:10110000
左转1位:01100001
当前数的二进制:01100001
开始右转:
右转1位:10110000
右转1位:01011000
右转1位:00101100
右转1位:00010110
右转1位:00001011
右转1位:10000101
右转1位:11000010
右转1位:01100001
修改Ifthen.cpp程序,使用三重if-else运算符(?:)。
#include
using namespace std;
int main() {
int i;
cout << "type a number and 'Enter'" << endl;
cin >> i;
i > 5 ? cout << "It's greater than 5" << endl :
i < 5 ? cout << "It's less than 5 " << endl :
cout << "It's equal to 5 " << endl;
cout << "type a number and 'Enter'" << endl;
cin >> i;
i < 10 ? i > 5 ? cout << "5 < i < 10" << endl :
cout << "i <= 5" << endl :
cout << "i >= 10" << endl;
}
创建一个含有两个string对象和一个int对象的struct。使用typedef为该struct命名。创建struct的一个实例,初始化实例的三个值,然后输出它们。获得实例的地址,然后赋值给定义的struct类型的指针。改变实例的三个值,然后通过指针把它们打印出来。
#include
#include
using namespace std;
typedef struct {
string a;
string b;
int c;
} MyStruct;
int main() {
MyStruct a;
a.a = "hello";
a.b = "world";
a.c = 100;
cout << a.a << " " << a.b << " " << a.c << endl;
MyStruct *pa;
pa = &a;
pa->a = "Hello";
pa->b = "World";
pa->c = 200;
cout << pa->a << " " << pa->b << " " << pa->c << endl;
}
输出:
hello world 100
Hello World 200
编制一个使用颜色枚举类型的程序。创建一个enum类型的变量,然后用for循环输出与颜色名对应的数字。
#include
using namespace std;
enum Color {
COLOR_MIN,
BLACK,
WHITE,
RED,
GREEN,
BLUE,
COLOR_MAX
};
int main() {
Color color = RED;
for (int i = COLOR_MIN + 1; i < COLOR_MAX; i++) {
if (i == color) {
cout << i << endl;
break;
}
}
}
用Union.cpp程序做一个试验,删除各种union元素,观察对union大小的影响。试给该union的一个元素赋值(属于某一类型),然后通过不同的元素(属于不同的类型)输出它的值,看看发生了什么情况。
#include
using namespace std;
union Packed { // Declaration similar to a class
char i;
short j;
int k;
long l;
float f;
double d;
// The union will be the size of a
// double, since that's the largest element
}; // Semicolon ends a union, like a struct
int main() {
cout << "sizeof(Packed) = "
<< sizeof(Packed) << endl;
Packed x;
x.i = 'c';
cout << x.i << endl;
cout << x.j << endl;
cout << x.k << endl;
cout << x.l << endl;
cout << x.f << endl;
cout << x.d << endl;
}
因为short, int , long与char存储格式一致,所以都能够正确输出char 'c’的十进制数,但是由于浮点数的格式不一样,所以无法正确输出’c’对应十进制数99的浮点数。
输出:
sizeof(Packed) = 8
c
99
99
99
1.38729e-43
4.89125e-322
union大小是元素里类型字节占用最大的大小,在本cpp中就是double,占用8个字节,如果你删除l, f, d元素,那么大小就会变成int k的字节大小,也就是4个字节。
编制一个程序,连续定义两个int数组。第二个数组的开始下标紧接第一个数组的结束下标。给两个数组赋值。打印出第二个数组观察由此引起的变化。再在两个数组定义之间定义一个char变量,重复上述操作。可以创建一个数组输出函数以简化程序。
NND,我愣是没看懂啥意思
修改ArrayAddresses.cpp程序,使之能处理char、long、int、float以及double类型数据。
#include
using namespace std;
int main() {
char a[10];
cout << "sizeof(char) = "<< sizeof(char) << endl;
for(int i = 0; i < 10; i++)
cout << "&a[" << i << "] = "
<< (void*)&a[i] << endl; // 打印char的地址必须转换成别的类型,否则会当成字符串
long b[10];
cout << "sizeof(long) = "<< sizeof(long) << endl;
for(int i = 0; i < 10; i++)
cout << "&a[" << i << "] = "
<< &b[i] << endl;
// float, double忽略了
}
输出:
sizeof(char) = 1
&a[0] = 0xb0651ff89e
&a[1] = 0xb0651ff89f
&a[2] = 0xb0651ff8a0
&a[3] = 0xb0651ff8a1
&a[4] = 0xb0651ff8a2
&a[5] = 0xb0651ff8a3
&a[6] = 0xb0651ff8a4
&a[7] = 0xb0651ff8a5
&a[8] = 0xb0651ff8a6
&a[9] = 0xb0651ff8a7
sizeof(long) = 4
&a[0] = 0xb0651ff870
&a[1] = 0xb0651ff874
&a[2] = 0xb0651ff878
&a[3] = 0xb0651ff87c
&a[4] = 0xb0651ff880
&a[5] = 0xb0651ff884
&a[6] = 0xb0651ff888
&a[7] = 0xb0651ff88c
&a[8] = 0xb0651ff890
&a[9] = 0xb0651ff894
运用ArrayAddresses.cpp程序中的技术,输出在StructArray.cpp程序中定义的struct的大小以及数组元素的地址。
#include
using namespace std;
typedef struct {
int i, j, k;
} ThreeDpoint;
int main() {
ThreeDpoint a[10];
cout << "sizeof(ThreeDpoint) = "<< sizeof(ThreeDpoint) << endl;
for(int i = 0; i < 10; i++)
cout << "&a[" << i << "] = "
<< &a[i] << endl;
}
输出:
sizeof(ThreeDpoint) = 12
&a[0] = 0xceb6dffbb0
&a[1] = 0xceb6dffbbc
&a[2] = 0xceb6dffbc8
&a[3] = 0xceb6dffbd4
&a[4] = 0xceb6dffbe0
&a[5] = 0xceb6dffbec
&a[6] = 0xceb6dffbf8
&a[7] = 0xceb6dffc04
&a[8] = 0xceb6dffc10
&a[9] = 0xceb6dffc1c
创建一个string对象数组且对每一个元素赋一个字符串。用for循环输出该数组。
#include
#include
using namespace std;
int main() {
string strArr[3];
strArr[0] = "hello"; strArr[1] = "csdn"; strArr[2] = "!";
for (int i = 0; i < 3; i++) {
cout << strArr[i] << endl;
}
}
在ArgsToInts.cpp的基础上,编制两个新程序,它们各自使用atol()和atof()函数。
#include
#include
using namespace std;
int main(int argc, char* argv[]) {
if (argc < 3) {
cout << "请输入2个参数" << endl;
return 0;
}
cout << atol(argv[1]) << endl;
cout << atof(argv[2]) << endl;
}
修改PointerIncrement2.cpp程序,其中用union代替struct。
#include
using namespace std;
typedef union {
char c;
short s;
int i;
long l;
float f;
double d;
long double ld;
} Primitives;
int main() {
Primitives p[10];
Primitives* pp = p;
cout << "sizeof(Primitives) = "
<< sizeof(Primitives) << endl;
cout << "pp = " << pp << endl;
pp++;
cout << "pp = " << pp << endl;
}
输出:
sizeof(Primitives) = 16
pp = 0x9dc2bffbe0
pp = 0x9dc2bffbf0
修改PointerArithmetic.cpp程序,其中使用long和long double。
这个比较简章,就是替换一下变量。
#include
using namespace std;
#define P(EX) cout << #EX << ": " << EX << endl;
int main() {
long a[10];
for(int i = 0; i < 10; i++)
a[i] = i; // Give it index values
long* ip = a;
P(*ip);
P(*++ip);
P(*(ip + 5));
long* ip2 = ip + 5;
P(*ip2);
P(*(ip2 - 4));
P(*--ip2);
P(ip2 - ip); // Yields number of elements
}
输出:
*ip: 0
*++ip: 1
*(ip + 5): 6
*ip2: 6
*(ip2 - 4): 2
*--ip2: 5
ip2 - ip: 4
定义一个float变量。获得它的地址,把地址转化为unsigned char,赋值给一个unsigned char指针。使用指针和[ ]符号引用float变量中的下标,并用本章中定义的printBinary()函数输出该float的内存映像。(从0到sizeof(float))。改变该float变量的值看看是否能推算出下一步的情况(float包含编码的数据)。
#include "printBinary.h"
#include
using namespace std;
int main() {
float f = 3.5;//根据IEEE标准,实际二进制格式为01000000 01100000 00000000 00000000
unsigned char *p = (unsigned char*)&f;
int len = sizeof(float)/sizeof(unsigned char);
for (int i = 0; i < len; i++) {
printBinary(p[i]);cout << " ";
}
cout << endl;
for (int i = 0; i < len; i++) {
printBinary(p[len - 1 - i]);cout << " ";
}
}
输出:
00000000 00000000 01100000 01000000
01000000 01100000 00000000 00000000
第二种输出顺序与IEEE标准的格式完全一致,第二种输出是先输出高位,然后是低位,分别对应了float字节的高位和低位,说明存储的字节序是小端字节序,即低位字节码存储在低地址上。
定义一个int数组。获得该数组的起始地址,使用static_cast把它转化为void*。写一个带以下参数的函数:一个void*、一个数字(表明字节的数目)和一个值(表明每个字节需要设定的值)。该函数必须为特定范围内的每个字节设定特定的值。在这个int数组上试验函数。
#include
using namespace std;
void setArray(void *p, int size, int val) {
unsigned char * pch = static_cast<unsigned char*>(p);
for (int i = 0; i < size; i++) {
pch[i] = val;
}
}
int main() {
const int LEN = 10;
int a[LEN];
setArray(static_cast<void*>(a), sizeof(a), 1);
for (int i = 0; i < LEN; i++) {
cout << "a[" << i << "] = 0x" << hex << a[i] << endl;
}
}
输出:
a[0] = 0x1010101
a[1] = 0x1010101
a[2] = 0x1010101
a[3] = 0x1010101
a[4] = 0x1010101
a[5] = 0x1010101
a[6] = 0x1010101
a[7] = 0x1010101
a[8] = 0x1010101
a[9] = 0x1010101
建立一个const double类型数组和一个volatile double类型数组。通过引用每个数组的下标且用const_cast把每个元素分别转换为non-const和non-volatile,然后对每个元素赋值。
#include
using namespace std;
int main() {
const double a[10] = {0};
volatile double b[10];
for (int i = 0; i < 10; i++) {
const_cast<double&>(a[i]) = i;
const_cast<double&>(b[i]) = i;
}
for (int i = 0; i < 10; i++) {
cout << a[i] << " ";
}
cout << endl;
for (int i = 0; i < 10; i++) {
cout << b[i] << " ";
}
cout << endl;
}
输出:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
建立一个函数,该函数接受一个指向double类型数组的指针和一个表明该数组大小的值。该函数应该输出数组中的每个元素值。现在建立一个double类型的数组,且初始化每个元素的值为0,然后使用你的函数输出该数组。接着使用reinterpret_cast关键字把数组的起始地址转化为unsigned char*,把每个元素设置为1(提示:必须用sizeof运算符计算一个double类型变量包含的字节数)。现在使用你的数组输出函数输出结果。想想为什么每个元素值不设成1.0?
#include
using namespace std;
void displayArray(double *pa, int len) {
for (int i = 0; i < len; i++) {
cout << pa[i] << " ";
}
cout << endl;
}
int main() {
double a[10] = {0};
unsigned char *p = reinterpret_cast<unsigned char*>(a);
for (int i = 0, size = sizeof(a); i < size; i++) {
p[i] = 1;
}
displayArray(a, 10);
}
输出:
7.7486e-304 7.7486e-304 7.7486e-304 7.7486e-304 7.7486e-304 7.7486e-304 7.7486e-304 7.7486e-304 7.7486e-304 7.7486e-304
可以把1.0赋值为每个元素,但是unsigned char*只接受0~255之间的数,即使你给它赋值为1.0,也会被截断成1赋值给每个元素。
(带有挑战性)修改FloatingAsBinary.cpp程序以便能够以单独的二进制位组输出double类型数据。为实现目标,必须用自己的特殊代码(可以从printBinary()函数中衍生)去替换对printBinary()的调用,还必须查阅并理解自己的编译器的浮点数字节格式(这是具有挑战性的部分)。
单独的二进制位
应该指的是分别输出符号位、尾数、指数。
创建makefile文件,可以把编译YourPets1.cpp和YourPets2.cpp程序(用你特定的编译器)以及执行这两个程序作为默认的目标,确保使用后缀规则。
3-30.makefile
CPP = g++
OFLAG = -o
.SUFFIXES : .o .cpp
.cpp.o :
$(CPP) $(CPPFLAGS) -c $<
all: \
YourPets1 \
YourPets2
YourPets1: YourPets1.o
$(CPP) $(OFLAG)$@ $<
rm $<
./$@
YourPets2: YourPets2.o
$(CPP) $(OFLAG)$@ $<
rm $<
./$@
YourPets1.o: YourPets1.cpp
YourPets2.o: YourPets2.cpp
执行输出:
$ make -f 3-30.makefile
g++ -c YourPets1.cpp
g++ -oYourPets1 YourPets1.o
rm YourPets1.o
./YourPets1
g++ -c YourPets2.cpp
g++ -oYourPets2 YourPets2.o
rm YourPets2.o
./YourPets2
char 大小:1
0x932b5ffc2f 0x932b5ffc2e 0x932b5ffc2d
short int 大小:2
0x932b5ffc2a 0x932b5ffc28 0x932b5ffc26
int 大小:4
0x932b5ffc20 0x932b5ffc1c 0x932b5ffc18
long int 大小:4
0x932b5ffc14 0x932b5ffc10 0x932b5ffc0c
long long 大小:8
0x932b5ffc00 0x932b5ffbf8 0x932b5ffbf0
float 大小:4
0x932b5ffbec 0x932b5ffbe8 0x932b5ffbe4
double 大小:8
0x932b5ffbd8 0x932b5ffbd0 0x932b5ffbc8
long double 大小:16
0x932b5ffbb0 0x932b5ffba0 0x932b5ffb90
修改StringizingExpressions.cpp程序,通过设置一个命令行标志,使用P(A)能用条件#ifdef与调试代码分离开。需要参数编译器文档,了解在命令行上怎样定义和取消定义预处理的值。
cpp文件:
#include
using namespace std;
#ifdef LOG
#define P(A) cout << #A << ": " << (A) << endl;
#else
#define P(A) cout << (A) << endl;
#endif
int main() {
int a = 1, b = 2, c = 3;
P(a); P(b); P(c);
P(a + b);
P((c - a)/b);
}
编译命令:
$ make -f gcc.makefile StringizingExpressions
g++ -c StringizingExpressions.cpp
g++ -oStringizingExpressions StringizingExpressions.o
rm StringizingExpressions.o
./StringizingExpressions
1
2
3
3
1
编译命令上添加宏定义标志,需要修改makefile文件,在后缀规则前面添加下面一行,表示定义一个宏:
CPPFLAGS = -DLOG
再看输出:
$ make -f gcc.makefile StringizingExpressions
g++ -DLOG -c StringizingExpressions.cpp
g++ -oStringizingExpressions StringizingExpressions.o
rm StringizingExpressions.o
./StringizingExpressions
a: 1
b: 2
c: 3
a + b: 3
(c - a)/b: 1
定义一个函数,该函数接受一个double型参数且返回一个int值。创建和初始化一个指向该函数的指针,通过这个指针调用这个函数。
#include
using namespace std;
int f(double d) {
cout << "int f(double d) 被调用" << endl;
return 0;
}
int main() {
int (*pf)(double);
pf = f;
pf(0);
}
输出:
int f(double d) 被调用
声明一个函数,该函数接受一个int参数且返回指向另一个函数的指针,这个函数接受一个char变量且返回一个float值。
#include
using namespace std;
float f(char a) {
cout << "float f(char a) 被调用" << endl;
return 0;
}
float (*ff(int))(char) {
return f;
}
typedef float (*pf)(char);
//或者如下声明ff也可以更简单
pf ff1(int) {
return f;
}
int main() {
pf a = ff(0);
a(1);
a = ff1(0);
a(1);
}
输出:
float f(char a) 被调用
float f(char a) 被调用
修改FunctionTable.cpp程序使每个函数返回一个string(而不是输出一个消息)以便在main()函数中输出。
#include
#include
using namespace std;
// A macro to define dummy functions:
#define DF(N) string N() { \
return "function " #N " called..."; }
DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g);
string (*func_table[])() = { a, b, c, d, e, f, g };
int main() {
while(1) {
cout << "press a key from 'a' to 'g' "
"or q to quit" << endl;
char c;
cin >> c;
if ( c == 'q' )
break; // ... out of while(1)
if ( c < 'a' || c > 'g' )
continue;
cout << (*func_table[c - 'a'])() << endl;
}
}
输出:
press a key from 'a' to 'g' or q to quit
a
function a called...
press a key from 'a' to 'g' or q to quit
b
function b called...
press a key from 'a' to 'g' or q to quit
c
function c called...
press a key from 'a' to 'g' or q to quit
d
function d called...
press a key from 'a' to 'g' or q to quit
e
function e called...
press a key from 'a' to 'g' or q to quit
f
function f called...
press a key from 'a' to 'g' or q to quit
g
function g called...
press a key from 'a' to 'g' or q to quit
h
press a key from 'a' to 'g' or q to quit
q
为前面某个练习(自己选择)建立一个makefile文件,允许键入make以构建这个程序,并且键入make debug以构建带有调试信息的程序。
3-35.cpp
#include
using namespace std;
int main() {
#ifdef DEBUG
cout << "debug info" << endl;
#endif
}
3-35.makefile:
CPP = g++
OFLAG = -o
#CPPFLAGS = -DLOG
.SUFFIXES : .o .cpp .c
.cpp.o :
$(CPP) $(CPPFLAGS) -c $<
all: \
3-35
debug: \
3-35-debug
3-35: 3-35.o
$(CPP) $(OFLAG)$@ $<
rm $<
./$@
3-35-debug: 3-35-debug.o
$(CPP) $(OFLAG)$@ $<
rm $<
./$@
3-35.o:3-35.cpp
3-35-debug.o: 3-35.cpp
$(CPP) -DDEBUG $(OFLAG)$@ -c $<
默认目标是all,所以编译不带debug信息的命令如下:
$ make -f 3-35.makefile
g++ -c 3-35.cpp
g++ -o3-35 3-35.o
rm 3-35.o
./3-35
编译debug信息的,需要使用debug目标:
$ make -f 3-35.makefile debug
g++ -DDEBUG -o3-35-debug.o -c 3-35.cpp
g++ -o3-35-debug 3-35-debug.o
rm 3-35-debug.o
./3-35-debug
debug info