题目:
子网掩码是用来判断任意两台计算机的IP地址是否属于同一子网络的根据。 最为简单的理解就是两台计算机各自的IP地址与子网掩码进行AND运算后,如果得出的结果是相同的,则说明这两台计算机是处于同一个子网络上的,可以进行直接的通讯。
给定两个IP和一个子网掩码,判断两个IP是否属于同一子网。输出0代表不是同一子网,输出1代表是同一子网。同时输出第一个IP与子网掩码相与的结果。
保证输入数据合法
相与过程示范:
IP地址:192.168.0.1 子网掩码:255.255.255.0 AND运算 转化为二进制进行运算:
IP地址:11010000.10101000.00000000.00000001
子网掩码:11111111.11111111.11111111.00000000
AND运算:11010000.10101000.00000000.00000000 转化为十进制后为: 192.168.0.0
输入:
输入一行字符 代表两个ip和一个子网掩码,中间实用空格隔开
eg1: 192.168.1.1 192.168.1.2 255.255.255.0
eg2: 182.168.1.1 192.168.2.1 255.255.255.0
输出:
如果两个ip是同一子网输出0,否则输出1。同时输出第一个ip与子网掩码相与的结果(10进制)
与输入相对应输出:
eg1: 1 192.168.1.0
eg2: 0 192.168.1.0
核心思想1(这是一种很笨的解法):
- 输入我是读入了三个字符串,然后使用遍历的方法将数字给分离出来的(这很蠢)
- 将IP1,IP2,mask分别转换成对应的32位二进制形式的01数组(对每个数字进行十进制到二进制的转换)
- 两个IP分别于mask相与,结果仍然是32位的二进制数组,然后逐位进行比较,即可得出是否是同一子网
- 将IP1与mask相与后的二进制数组再转换为对应的十进制形式的IP输出即可
很明显,这种转换费时费力,很麻烦,很容易出错。所以这种方法很笨
代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<math.h>
using namespace std;
vector<int> transToArray(char str[]); //将一个ip字符串转换为各个部分对应的整数,进一步转换为二进制返回
vector<int> trans_to_b2(int num); //将一个十进制的数转换为它的二进制逆序 eg:2 -->01
void isRight(vector<int> ip1, vector<int> ip2, vector<int> mask);//判断两个ip是否在同一子网下,并打印ip1与mask的与值
int trans_to_num(vector<int> ip);//将二进制的ip再转换为十进制
int main()
{
char ip1[50];
char ip2[50];
char mask[50];
scanf("%s %s %s",ip1,ip2,mask);
vector<int> ip1_trans = transToArray(ip1);
vector<int> ip2_trans = transToArray(ip2);
vector<int> mask_trans = transToArray(mask);
isRight(ip1_trans, ip2_trans, mask_trans);
}
void isRight(vector<int> ip1, vector<int> ip2, vector<int> mask)
{
int k = 1;
for(int i=0; i<32; i++){
if( ip1[i]==1 && mask[i]==1 ){
ip1[i] = 1;
}else{
ip1[i] = 0;
}
}
for(int i=0; i<32; i++){
if( ip2[i]==1 && mask[i]==1 ){
ip2[i] = 1;
}else{
ip2[i] = 0;
}
}
for(int i=0; i<32; i++){
if( ip1[i]!=ip2[i] ){
k = 0;
}
}
printf("%d ",k);
trans_to_num(ip1);
}
vector<int> transToArray(char str[])//把字符串转换为二进制存储
{
vector<int> b2(32);
b2.clear();
int len = strlen(str);
str[len]='.';
len++;
int i=0; int j=0;
for(j=0; j<len; j++){
if(str[j]=='.'){
int num = 0;
for(int k=j-1,t=0; k>=i; t++,k--){
num += (str[k]-48)*(int)pow(10,t);
}
vector<int> t = trans_to_b2(num);
if( t.size()<8 ){
for(int k=0; k<8-t.size(); k++)
b2.push_back(0);
}
for(int k=t.size()-1; k>=0; k--){
b2.push_back(t[k]);
}
i = j+1;
}
}
return b2;
}
vector<int> trans_to_b2(int num)
{
vector<int> tra(8);
tra.clear();
while(num!=0){
tra.push_back(num%2);
num = num/2;
}
return tra;
}
int trans_to_num(vector<int> ip)
{
int j=7;
for(int k=0; k<4; k++){
int num=0;
for(int i=j,t=0;i>=j-7;i--,t++){
num+=ip[i]*(int)pow(2,t);
}
j+=8;
if(k<3){
printf("%d.",num);
}else{
printf("%d\n",num);
}
}
}
通过图:
核心思想2(目前来说,我觉得这是思路比较清晰的):
- 对一个字符串型的ip怎么分割?详见C我的另一篇博客:C++中的字符串分割函数-----strtok
- 对应数字也不需要转换为二进制进行相与运算,直接用位与运算符即可。eg: 1&2 等价00000001&00000010,结果就是十进制的0
代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<vector>
using namespace std;
vector<char*> split(char str[]);
//将字符串192.168.1.1 转换为四个字符串 192 168 1 1存储在vector<char*>数组中
vector<int> trans_to_num(vector<char*> s);
//将vector<char*>数组中的四个字符串 转换成四个整数 存储在vector<int>数组中
bool isSame(vector<int> ip1,vector<int> ip2,vector<int> mask);
//判断ip1和ip2是否在同一个子网,采用与运算,就不用转换2进制了
void print(vector<int> ip1,vector<int> mask);
//输出第一个ip与mask相与的结果
int main()
{
char ip1[50];
char ip2[50];
char mask[50];
scanf("%s %s %s",ip1,ip2,mask);
vector<char*> ip1_str = split(ip1);
vector<char*> ip2_str = split(ip2);
vector<char*> mask_str = split(mask);
vector<int> ip1_num = trans_to_num(ip1_str);
vector<int> ip2_num = trans_to_num(ip2_str);
vector<int> mask_num = trans_to_num(mask_str);
if( isSame(ip1_num,ip2_num,mask_num) ){
printf("1 "); //在同一子网下
print(ip1_num,mask_num);
}else{
printf("0 "); //不在同一子网下
print(ip1_num,mask_num);
}
return 0;
}
vector<char*> split(char str[])
{
vector<char*> s;
char *p;
p = strtok(str, ".");
s.push_back(p);
do{
p = strtok(NULL, ".");
if(p){
s.push_back(p);
}
}while(p);
return s;
}
vector<int> trans_to_num(vector<char*> s)
{
vector<int> nums;
for(int i=0; i<s.size(); i++){
int num = 0;
for(int j=strlen(s[i])-1,t=0; j>=0; j--,t++){
num += (s[i][j]-48)*pow(10,t);
}
nums.push_back(num);
}
return nums;
}
bool isSame(vector<int> ip1,vector<int> ip2,vector<int> mask)
{
for(int i=0; i<ip1.size(); i++){
if((ip1[i]&mask[i])!=(ip2[i]&mask[i])){ //注意,&的优先级低于!=,所以要加括号
return false;
}
}
return true;
}
void print(vector<int> ip1,vector<int> mask)
{
for(int i=0; i<ip1.size()-1; i++){
printf("%d.",ip1[i]&mask[i]);
}
printf("%d\n",ip1[3]&mask[3]);
}
核心思想3(最变态):
怎么搞呢?使用scanf的格式化输入,直接得到数字(不需要和傻子一样先拆分,再转换,没错,我就是傻子)!!!
具体是,如果在格式控制字符串中除了格式声明以外还有其他字符,则在输入数据时必须在对应位置上输入与这些字符相同的字符
代码: int a,b,c; scanf("a=%d,b=%d,c=%d",&a,&b,&c); 命令行输入: a=1,b=3,c=2 这时才会将1 3 2分别送入整形变量a,b,c中
我们只用规定一个scanf("%d.%d.%d.%d",&a,&b,&c,&d);就可以轻松分解输入的ip了
具体实现见我的另一篇博客:判断两个IP是否属于同一子网(牛客网)
两个题目在输入输出要求是不一样的,所以写了两个
综上