指针作为C/C++的灵魂,其可玩性可以说是相当不错的。
指 float 为 int
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char const *argv[]){
float a = 20.59375;
int *p = (int *)&a;
// int *p = reinterpret_cast<int*>(&a); // c++ 一般采用这种写法,效果一样
cout << (*p) << endl;
return 0;
}
输出
1101316096
1101316096是个啥?
我们来看看它的二进制形式:
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char const *argv[]){
float a = 20.59375;
int *p = (int *)&a;
cout << (*p) << endl;
cout << bitset<32>(*p) << endl;
return 0;
}
输出
1101316096
01000001101001001100000000000000
我们发现它就是20.59375的IEEE754格式(理所当然):
原理
初学时我们说变量是一个盒子,其实变量代表一块内存空间,里面存着很多0或1。
我们通过取址(&)拿到变量a这块内存空间的地址,a是一个float的变量,&a自然是一个float的地址,但是我们“骗”计算机说这是一个int的地址,再通过取值(*)得到了1101316096,在这过程中,内存里其实并没有改变(始终是01000001101001001100000000000000),只是我们看待这块内存的方式变了,所以数字也就从20.59375变成了1101316096。
所以,指针可以强制改变“看待某段内存的方式”,你说这段内存是啥它就是啥
同理:
1852076899 是 ‘csdn’?
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char const *argv[]){
int a = 1852076899;
cout << bitset<32>(a) << endl;
printf("%d\n", a);
printf("%f\n", *(float*)&a);
for (int i=0; i<4; i++){
putchar(((char*)&a)[i]);
}
return 0;
}
输出
01101110011001000111001101100011
1852076899
17675519055701040529804361728.000000
csdn
ascii码对照:
为什么反了?详见内存中的整数
让我们来玩儿点花的
#include <bits/stdc++.h>
using namespace std;
void to_charArr(){
char *p = (char*)&cin;
for (int i = 0; i < sizeof(cin); ++i,i%16||putchar('\n')){
printf("%d,\t", *p);
p++;
}
cout << endl;
}
int main(int argc, char const *argv[]){
to_charArr();
char s[] = {
88, 12, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-128, 12, 73, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 2, 16, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0, -112, 102, 72, 0, 0, 0, 0, 0,
96, 73, 72, 0, 0, 0, 0, 0, 0, 106, 72, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -64, 90, 72, 0, 0, 0, 0, 0,
-64, 81, 72, 0, 0, 0, 0, 0, 48, 90, 72, 0, 0, 0, 0, 0,
16, 90, 72, 0, 0, 0, 0, 0
};
istream *ccin = (istream*)(&s);
string x;
(*ccin) >> x;
cout << x << endl;
return 0;
}
我们让一个istream指针ccin指向一个字符数组,告诉它“没错,这就是个istream”,这个ccin同样能当cin用。
当然,这段代码大概率是没法在其他电脑上正常运行的,因为cin内部在不同的机器上会有不同的样子,这个数组s[]需要手动改成控制台上输出的那个数组。