c-用于检查给定字符串是否可以是有效IP地址的建议/help/更好的解决方案



老实说,我认为我写的代码是垃圾,我认为这不是解决问题的最佳方法。我需要一些建议或改进来解决这个问题。我对编码还是个新手。如果你能提供一些关于如何使用字符串和各种字符串函数的技巧,请不胜感激。

字符串为IP地址的条件:-

连接到internet的设备的标识号。以点四进制表示法编写的IPv4地址由四个用句点分隔的8位整数组成。

换句话说,它是一个由四个数字组成的字符串,每个数字都在0到255之间,并带有一个""每个数字之间的字符。所有数字都应不带前导零。

示例:

  1. 192.168.0.1是一个有效的IPv4地址
  2. 255.255.255.255是有效的IPv4地址
  3. 280.100.92.101不是有效的IPv4地址,因为280太大,不能是8位整数(最大的8位整数是255(
  4. 255.100.81.160.172不是有效的IPv4地址,因为它包含5个整数而不是4
  5. 1..0.1不是有效的IPv4地址,因为它的格式不正确
  6. 17.233.00.131和17.233.01.131不是有效的IPv4地址,因为它们包含前导零

这是我的代码(我知道这是垃圾,没有任何意义(:-

bool isIPv4Address(char * inputString) {
int count = 0, period = 0;
int k = 0, i = 0;
int digit = 0;


while(inputString[i] != '')
{ 
count = 0;
digit = 0;
i = k;

if(inputString[i] == '0' || inputString[i] == '.')
{
if(inputString[i+1] >47 && inputString[i+1] < 58)
{
return false;
}
}

while(inputString[i] != '.' && inputString[i] != '')
{
if(inputString[i] < 48 || inputString[i] > 57)
{
return false;
} 
count += (int)inputString[i];
i++;
digit++;
}

if(digit == 3)
{
if(inputString[i - 3] > '2')
{
return false;
}
}

if(inputString[i] == '.')
{
period++;
}

k = i+1;

if(count < 48 || count > 156)
{
return false;
}

if(inputString[i] == '')
{
break;
}
}

if(period == 3)
{
return true;
}else
{
return false;
}  
}

在POSIX系统上,使用inet_addr()函数:

名称

inet_addrinet_ntoa-IPv4地址操作

概要

#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
char *inet_ntoa(struct in_addr in);

描述

inet_addr()函数应将cp指向的字符串(采用标准IPv4点小数表示法(转换为整数适合用作互联网地址的值。

除非您是为实践编写代码,否则没有必要重新设计现有的标准解决方案。

。。。

返回值

成功完成后,inet_addr((应返回互联网住址否则返回( in_addr_t)(-1)

我在代码审查网站上发现了这个问题。由于代码没有按预期工作,这个问题不适合代码审查,所以我将在这里提供审查。

幻数

这在之前的回答中提到过:

代码中不清楚数字47、48、59和156的含义。

您不能假设使用的字符集是ASCII,因此使用基于09的范围检查更安全。

if(inputString[i] == '0' || inputString[i] == '.')
{
if(inputString[i+1] < '0' && inputString[i+1] > '9')
{
return false;
}
}

最好使用ctype.h提供的isdigit功能

if(inputString[i] == '0' || inputString[i] == '.')
{
if(!isdigit(inputString[i+1]))
{
return false;
}
}

复杂性

如果将函数分解为只有一个用途的较小函数,则此代码将更易于读取、编写和调试。每个内部循环或检查都应该是一个函数。

编程的艺术就是把问题分解成越来越小的部分,直到每一部分都很容易解决。有一些编程原则,例如"单一责任原则"来描述这一点。

使用C库简化检查

有两个函数可以将字符串转换为整数,这将使检查255以上的数字变得更容易。第一个是atoi,第二个是strtol,这两个函数中的任何一个都会给你一个可以与255进行比较的数字。

'0'之类的东西有很多松散的47、48等值。最好使用后一种语法。

进行了多次if范围检查。使用一些额外的状态变量可以降低复杂性。

在任何地方使用inputString[i]都很麻烦。做得更好(例如int chr = inputString[i];,而使用chr——它更简单、更容易阅读(。

原始程序在上识别错误

192.168.0.1
280.100.92.101

我重构了代码并构建了一个诊断测试程序。注释:

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define ERR(_expr) 
if (err != NULL) 
break; 
if (_expr) { 
err = #_expr; 
break; 
}
const char *bigerr;
int opt_i;
bool
isfix1(const char *inputString)
{
int i = 0;
int ndig = -1;
int ndot = 0;
int val = 0;
int leading_zero = 0;
unsigned char ipv[4];
const char *err = NULL;
while (1) {
int chr = inputString[i++];
int eos = (chr == 0);
// check the last number we got
if ((chr == '.') || eos) {
ERR(ndig == 0);
// we don't allow (because it might be decoded as octal):
//   x.00.y.z x.01.y.z
// but this must be ok:
//   x.0.y.z
ERR(leading_zero && (ndig > 1));
// we can only have 3 dots in the string
ndot += (! eos);
ERR(ndot > 3);
ndig = 0;
val = 0;
if (eos) {
// we must have _exactly 3 dots in the string
ERR(ndot != 3);
break;
}
continue;
}
// collect digits
if ((chr >= '0') && (chr <= '9')) {
val *= 10;
chr -= '0';
val += chr;
if (ndig < 0)
ndig = 0;
// remember whether substring started with "0"
if (ndig == 0)
leading_zero = (chr == 0);
// we can only have up to 3 digits per byte
++ndig;
ERR(ndig > 3);
// max value for byte
ERR(val > 255);
// just for fun -- the binary IP address
ipv[ndot] = val;
continue;
}
// any invalid character
ERR(chr != 0);
}
if (0)
printf("IPV: %d.%d.%d.%dn",ipv[0],ipv[1],ipv[2],ipv[3]);
bigerr = err;
return (err == NULL);
}
bool
isorig(const char *inputString)
{
int count = 0,
period = 0;
int k = 0,
i = 0;
int digit = 0;
while (inputString[i] != '') {
count = 0;
digit = 0;
i = k;
if (inputString[i] == '0' || inputString[i] == '.') {
if (inputString[i + 1] > 47 && inputString[i + 1] < 58) {
return false;
}
}
while (inputString[i] != '.' && inputString[i] != '') {
if (inputString[i] < 48 || inputString[i] > 57) {
return false;
}
count += (int) inputString[i];
i++;
digit++;
}
if (digit == 3) {
if (inputString[i - 3] > '2') {
return false;
}
}
if (inputString[i] == '.') {
period++;
}
k = i + 1;
if (count < 48 || count > 156) {
return false;
}
if (inputString[i] == '') {
break;
}
}
if (period == 3) {
return true;
}
else {
return false;
}
}
int
dofnc(bool (*fnc)(const char *),const char *ipaddr,const char *reason)
{
int valid;
bigerr = NULL;
valid = fnc(ipaddr);
printf("%s",valid ? "valid" : "INVALID");
if (bigerr != NULL)
printf(" (%s)",bigerr);
printf(" (%s)n",(valid != (reason == NULL)) ? "FAIL!" : "pass");
return valid;
}
void
dotest(const char *ipaddr,const char *reason)
{
static int sep = 0;
if (sep)
printf("n");
sep = 1;
printf("IPADDR: %s",ipaddr);
if (reason != NULL)
printf(" -- %s",reason);
printf("n");
int valid[2];
printf("isorig: ");
valid[0] = dofnc(isorig,ipaddr,reason);
printf("isfix1: ");
valid[1] = dofnc(isfix1,ipaddr,reason);
do {
if (opt_i)
break;
for (int idx = 0;  idx < 2;  ++idx) {
if (valid[idx] != (reason == NULL))
exit(1);
}
} while (0);
}
int
main(int argc,char **argv)
{
--argc;
++argv;
for (;  argc > 0;  --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'i':
opt_i = ! opt_i;
break;
}
}
dotest("192.168.0.1",NULL);
dotest("255.255.255.255",NULL);
dotest("280.100.92.101","280 is too large to be an 8-bit integer");
dotest("255.100.81.160.172","contains 5 integers instead of 4");
dotest("1..0.1","not properly formatted");
dotest("1.0.1.","not properly formatted");
dotest("17.233.00.131","contain leading zeros");
dotest("17.233.01.131","contain leading zeros");
return 0;
}

这是程序输出:

IPADDR: 192.168.0.1
isorig: INVALID (FAIL!)
isfix1: valid (pass)
IPADDR: 255.255.255.255
isorig: valid (pass)
isfix1: valid (pass)
IPADDR: 280.100.92.101 -- 280 is too large to be an 8-bit integer
isorig: valid (FAIL!)
isfix1: INVALID (val > 255) (pass)
IPADDR: 255.100.81.160.172 -- contains 5 integers instead of 4
isorig: INVALID (pass)
isfix1: INVALID (ndot > 3) (pass)
IPADDR: 1..0.1 -- not properly formatted
isorig: INVALID (pass)
isfix1: INVALID (ndig == 0) (pass)
IPADDR: 1.0.1. -- not properly formatted
isorig: INVALID (pass)
isfix1: INVALID (ndig == 0) (pass)
IPADDR: 17.233.00.131 -- contain leading zeros
isorig: INVALID (pass)
isfix1: INVALID (leading_zero && (ndig > 1)) (pass)
IPADDR: 17.233.01.131 -- contain leading zeros
isorig: INVALID (pass)
isfix1: INVALID (leading_zero && (ndig > 1)) (pass)

相关内容

最新更新