指针运算
昨天做了华为的一个OJ练习题,题目本身没什么难度,但是自己仍然执着地犯了典型的错误(-.- 又放水了哎)。错误的大概内容在指针的加减运算这一块。
先上题,如下:
IP地址的长度为32,即有2^32-1个地址。IP地址一般采用点分十进制表示法,例如"192.168.1.1"。IP地址也可以直接用一个32位的整数进行表示。本题目要求根据给定的整数IP地址表示发,将其转换为点分十进制的形式。
举个例子:输入整数IP地址为 3232235777
其对应十六进制为 0xC0A80101
每字节转为十进制 0xC0=192,0xA8=168,0x01=1,0x01=1
则输出为 192.168.1.1
首次写出的代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int main(){
unsigned int a;
cin >> a;
for(int i=0;i<4;i++){
unsigned char tmp;
memcpy(&tmp,&a+i,1);
printf("%u",tmp);
if(i!=0) printf(".");
}
return 0;
}
编译后,输入3232235777,输出错误。(gdb)x/4xb &a
打印出的结果是0x7fffffffdccc: 0x01 0x01 0xa8 0xc0
发现Big-Endian,这个简单,改啊。于是第二个版本是这样的:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int main(){
unsigned int a;
cin >> a;
for(int i=3;i>=0;i--){
unsigned char tmp;
memcpy(&tmp,&a+i,1);
printf("%u",tmp);
if(i!=0) printf(".");
}
return 0;
}
编译后,输入3232235777,输出仍然错误。错误在哪呢?
memcpy (在(gdb)p &a
打印结果是..dcdc,而(gdb)p &a+1
打印结果是..dce0
这简直是一个再典型不过的错误了。C/C++的指针运算中, 虽然计算机通常把地址当做整数来处理。将整数变量加1后,其值将增加1;但将指针变量加1后,增加的量等于它指向的类型的字符数。 将指向都变了的指针加1后,则数值增加8;将指向short的指针加1后,指针值将增加2。void memcpy(voiddest, const void src, size_t n)中&a+i按 a的类型计算每个单位的长度,所以&a+i的增加量实际为isizeof(a)。
第三次修改如下:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int main(){
unsigned int a;
cin >> a;
for(int i=3;i>=0;i--){
unsigned char tmp;
char* tp = (char*)&a;
memcpy(&tmp,tp+i,1);
printf("%u",tmp);
if(i!=0) printf(".");
}
return 0;
}