指针运算

Published: 01 Apr 2016 Category: C

昨天做了华为的一个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;    
}    
comments powered by Disqus