views:

2104

answers:

7

Hi!

I have an IP address in char type Like char ip = "192.123.34.134" I want increment the last value (134). Does anyone how should i do it? I think, i should convert it to an integer, and then back, but unfortunately i don't know how? :( I'm using C++.

Please help me!

Thanks, kampi

+1  A: 

I would write a method that accepts a string in that format.
Convert it to 4 integers. increment. (Important Check range)
Then convert back to a string.

If you want somthing more long term and robust a class representing the IP address. Then you maintain the class an manipulate as appropraite and convert to string when needed.

#include <iostream>
#include <istream>
#include <sstream>
#include <string>
#include <stdexcept>



class MyIp
{
    struct Dot
    {};
    struct Byte
    {
        Byte(unsigned char& val)
            :m_val(val)
        {}
        unsigned char&  m_val;
    };
    friend std::istream& operator>>(std::istream& str,MyIp::Dot const& d);
    friend std::istream& operator>>(std::istream& str,MyIp::Byte const& b);
    friend std::ostream& operator<<(std::ostream& str,MyIp const& ip);
    public:
        MyIp(std::string const& ip)
        {
            std::stringstream str(ip);
            str >> Byte(ad[0]) >> Dot() >> Byte(ad[1]) >> Dot() >> Byte(ad[2]) >> Dot() >> Byte(ad[3]);
            std::string leftover;
            if (str >> leftover)
            {   throw std::runtime_error("InvalidIP: Long");
            }
        }
        void inc(int index)
        {
            if ((index >= 0) && (index <=3))
            {
                ++ad[index];
                if (ad[index] == 0)
                {
                    inc(index-1);
                }
            }
        }
    private:
        unsigned char   ad[4];
};
std::istream& operator>>(std::istream& str,MyIp::Dot const& d)
{
    char x  = str.get();
    if (x != '.')
    {   throw std::runtime_error("Invalid IP: Dot");
    }
    return str;
}
std::istream& operator>>(std::istream& str,MyIp::Byte const& b)
{
    unsigned int val;
    str >> val;
    if (!str || val > 255)
    {   throw std::runtime_error("Invalid IP: Val");
    }
    b.m_val = static_cast<unsigned char>(val);
    return str;
}
std::ostream& operator<<(std::ostream& str,MyIp const& ip)
{
    return str  << static_cast<unsigned int>(ip.ad[0])
                << "." << static_cast<unsigned int>(ip.ad[1])
                << "." << static_cast<unsigned int>(ip.ad[2])
                << "." << static_cast<unsigned int>(ip.ad[3]);
}

int main()
{
    try
    {
        std::string ip("127.0.0.1");

        MyIp    addr(ip);

        std::cout << addr << "\n";
        addr.inc(3);
        std::cout << addr << "\n";
    }
    catch(std::exception const& e)
    {
        std::cout << "What: " << e.what() << "\n";
    }
}
Martin York
this is hilarious. +1.
ithcy
People like over kill :-)
Martin York
+18  A: 

You can convert the IP address from a string to an integer using inet_addr, then, after manipulating it, convert it back to a string with inet_ntoa.

See the documentation for these functions for more info on how to use them.

Here's a small function that will do what you want:

// NOTE: only works for IPv4.  Check out inet_pton/inet_ntop for IPv6 support.
char* increment_address(const char* address_string)
{
    // convert the input IP address to an integer
    in_addr_t address = inet_addr(address_string);

    // add one to the value (making sure to get the correct byte orders)
    address = ntohl(address);
    address += 1;
    address = htonl(address);

    // pack the address into the struct inet_ntoa expects
    struct in_addr address_struct;
    address_struct.s_addr = address;

    // convert back to a string
    return inet_ntoa(address_struct);
}

Include <arpa/inet.h> on *nix systems, or <winsock2.h> on Windows.

Neil Williams
I know mine is going to be faster execution, but this answer is definitely more correct.
Erich
I'm just going to assume you mean inet_ntop instead of the *deprecated* inet_ntoa, right? **Right?**
R. Bemrose
@R. Bemrose IPv6 just complicates this question unnecessarily; the original question stated that the address would be in dotted quad format which implies IPv4 only. I'll gladly update the code if you have any suggestions for replacing the htonl/ntohl calls with something that'll work for IPv6 addresses.
Neil Williams
I'm using Dev-C++ under Windows. If i try to compile your code, than i get an error for "in_addr_t". It seemd, that Dev-C++ doesn't recognize this type. Could you tell me, how can i solve this problem? Thanks in advance!
kampi
Just use `unsigned long` instead of `in_addr_t`. You'll also probably have to capitalize the S in `s_addr` (so it should look like `S_addr`.) I don't have access to a Windows computer at the moment, so I hope that does it.
Neil Williams
A: 

This site ate my tabs, so I'll try again. I'm sure there is a library to do something like this, but this should work (assuming my syntax isn't messed up) enough to get the idea across.

Pseudo Code:

char[] ipAddress= "192.123.34.134";

if (ipAddress[ipAddress.Length-1] == '9')
{
    if(ipAddress[ipAddress.Length-2]=='9')
    {
        ipAddress[ipAddress.Length-1]='0';
        ipAddress[ipAddress.Length-2]='0';
        ipAddress[ipAddress.Length-3]=(char)ipAddress[ipAddress.Length-3]+1;
    }
    else
    {
        ipAddress[ipAddress.Length-2]=(char)ipAddress[ipAddress.Length-2]+1;
        ipAddress[ipAddress.Length-1]='0';
    }
}
else
{
     ipAddress[ipAddress.Length-1]=(char)ipAddress[ipAddress.Length-1]+1;
}
Erich
What about `192.123.34.255` ?
Kirill V. Lyadvinsky
At this point, I figured that sort of range checking had already been handled. To me, I don't think it would make sense to turn 192.123.34.255 into 192.123.35.0, which I think the other solutions would by going through an integer.
Erich
Eh, now that you mention it, x.x.x.99, or x.x.x.9 doesn't work either. I could fix these, but in reality, the above answers using socket library functions are more correct anway.
Erich
+1  A: 

Quick/Dirty!

void increment(std::string& ip)
{
    std::string::size_type dot = ip.find_last_of('.');
    std::stringstream stream(ip.substr(dot+1));
    int part = 0;

    stream >> part;

    part++;

    stream.str(""); stream.clear();

    stream << part;

    ip.replace(dot+1, std::string::npos, stream.str());
}
AraK
I was typing as you were coding :) My C++ skills are rusty but yours look spot on. Good show.
Deverill
A: 

You can also use the location of the last "." and take from there to the end to convert to an int, bump it up 1, check boundaries and then convert it to a string and append to the base part.

Deverill
A: 

This probably isn't very sane but it was fun to think about.

Since the IP address space is 32-bits you could write a function to convert IP addresses into unsigned 32-bit integers. Then you can add or subtract 1 or as much as you want, and convert back into an IP address. You wouldn't have to worry about range checking.

In pseduo-code for 192.123.34.134 you'd do:

int i = (192 << 24) + (123 << 16) + (34 << 8) + 134

More generally, for a.b.c.d:

int i = (a << 24) + (b << 16) + (c << 8) + d

Now change i as much as you want (i++, i+=10000) and convert back:

String ip = (i >> 24) + "." + 
            ((i >> 16) mod 256) + "." + 
            ((i >> 8) mod 256) + "." + 
            (i mod 256);

Excuse the syntax - I couldn't write C++ to save myself.

MK

monorailkitty
That's exactly what inet_addr_t is, as in Neil's answer, so no need to roll your own. So whether it's sane or not, it's what C programmers have been doing for years...
Steve Jessop
I guess I've been in a Java world too long if I'm thinking bit-twiddling is a bit too hardcore, Thanks for the pointer! (Pun not originally intended but kept when spotted.)
monorailkitty
+1  A: 
int a,b,c,d;
sscanf(str, "%d.%d.%d.%d", &a,&b,&c,&d);
sprintf(str, "%d.%d.%d.%d\0", a,b,c,d+1);
ragnarius