我找不到这个分段错误
I can't find this segmentation fault
所以我正在做 this codewars kata,我在每个测试中都取得了成功,但最终结果失败了,因为我的代码有一个分段错误,而且我认为我对找语言吧!有人可以暂停吗?
int is_valid_ip(const char *addr)
{
char set[] = "1234567890";
int current;
int octet_counter = 0;
char *octet = 0;
octet = strtok(addr, ".");
while (octet)
{
if (strspn(octet, set) != strlen(octet)) return 0; // checks for spaces
if (strlen(octet) > 1 && (octet[0]) == '0') return 0; // checks for preceding zeros
sscanf(octet, "%d", ¤t);
if (current < 0 || current > 255) return 0; // checks for range
octet = strtok(0, ".");
++octet_counter;
}
if (octet_counter == 4) return 1; // checks for number of octets
return 0;
};
我的代码比较简洁,但在尝试解决这个问题时弄得一团糟后,它变成了这个...
因为 strtok()
修改了要标记化的字符串并且 addr
被定义为 const char *
(我假设这是一个要求)你可以复制输入字符串 *addr
:
char ip[16]; // enought to hold nnn.nnn.nnn.nnn
if(strlen(addr)>15) return 0;
strcpy(ip, addr);
随后对 ip
而不是 addr
进行操作
或者...避免使用 strtok
和 parse/scan 字符串而不修改它。
这是一个使用 sscanf
的愚蠢解决方案,只是为了证明它是可行的。 (下面有一些更好的解决方案。)
#include <stdio.h>
/* True if its argument represents a decimal number between
* 0 and 255 without leading zeros. Assumes the characters are
* all digits and that there are at most three of them.
*/
static int good(const char* octet) {
switch (octet[0]) {
case '0': return octet[1] == 0;
case '1': return 1;
case '2': return octet[1] == 0 || octet[2] == 0
|| octet[1] < '5'
|| octet[1] == '5' && octet[2] < '6';
default: return octet[1] == 0 || octet[2] == 0;
}
}
struct OctetSep { char oct[4], sep[2] };
int is_valid_ip(const char *addr) {
struct OctetSep bits[4];
/* The last %c conversion is expected to fail. */
return sscanf(addr, "%3[0-9]%1[.]%3[0-9]%1[.]%3[0-9]%1[.]%3[0-9]%1c",
bits[0].oct, bits[0].sep,
bits[1].oct, bits[1].sep,
bits[2].oct, bits[2].sep,
bits[3].oct, bits[3].sep) == 7
&& good(bits[0].oct) && good(bits[1].oct)
&& good(bits[2].oct) && good(bits[3].oct);
}
当然,大部分工作都是由 good
完成的,将它变得更通用一点会很容易:
#include <stddef.h>
/* This idiocy is avoid problems with signed characters */
static int my_isdigit(char c) { return c >= '0' && c <= '9'; }
/* Returns the address of the first unmatched character after a match
* of an integer with no leading zeros and maximum value 255.
* This address may be in the middle of the integer, if it is too big.
* If the string doesn't start with a digit, returns NULL.
*/
static const char* good(const char* octet) {
switch (octet[0]) {
case '0': return octet + 1;
case '1': return !my_isdigit(octet[1]) ? octet + 1
: !my_isdigit(octet[2]) ? octet + 2
: octet + 3;
case '2': return !my_isdigit(octet[1]) ? octet + 1
: !my_isdigit(octet[2]) ? octet + 2
: octet[1] < '5' || octet[1] == '5' && octet[2] < '6'
? octet + 3
: octet + 2;
case '3': case '4': case '5': case '6': case '7': case '8':
case '9': return !my_isdigit(octet[1]) : octet + 1 ? octet + 2;
default: return NULL;
}
}
int is_valid_ip(const char *addr) {
for (const char* i = "..."; (addr = good(addr)); ++addr, ++i) {
if (*addr != *i) break;
if (!*i) return 1;
}
return 0;
}
但可能最简单的代码来自 strtol
的使用,尽管您仍然需要大量的手动检查。 (此解决方案更适用于有效整数范围大于 256 的应用程序。)
#include <stdlib.h>
/* This idiocy is avoid problems with signed characters */
static int my_isdigit(char c) { return c >= '0' && c <= '9'; }
/* Returns the address of the first character following the integer
* starting precisely at the supplied address, provided the integer
* has no leading zeros and a maximum value of 255. Otherwise,
* returns NULL.
*/
static const char* good(const char* octet) {
if (*octet == '0') return octet + 1;
/* This check is necessary because strtol also accepts whitespace and - */
if (!my_isdigit(*octet)) return NULL;
char *endptr;
long value = strtol(octet, &endptr, 10);
/* We already handled 0, so value==0 must be an error return */
if (value <= 0 || value > 255) return NULL;
return endptr;
}
int is_valid_ip(const char *addr) {
for (const char* i = "..."; (addr = good(addr)); ++addr, ++i) {
if (*addr != *i) break;
if (!*i) return 1;
}
return 0;
}
所以我正在做 this codewars kata,我在每个测试中都取得了成功,但最终结果失败了,因为我的代码有一个分段错误,而且我认为我对找语言吧!有人可以暂停吗?
int is_valid_ip(const char *addr)
{
char set[] = "1234567890";
int current;
int octet_counter = 0;
char *octet = 0;
octet = strtok(addr, ".");
while (octet)
{
if (strspn(octet, set) != strlen(octet)) return 0; // checks for spaces
if (strlen(octet) > 1 && (octet[0]) == '0') return 0; // checks for preceding zeros
sscanf(octet, "%d", ¤t);
if (current < 0 || current > 255) return 0; // checks for range
octet = strtok(0, ".");
++octet_counter;
}
if (octet_counter == 4) return 1; // checks for number of octets
return 0;
};
我的代码比较简洁,但在尝试解决这个问题时弄得一团糟后,它变成了这个...
因为 strtok()
修改了要标记化的字符串并且 addr
被定义为 const char *
(我假设这是一个要求)你可以复制输入字符串 *addr
:
char ip[16]; // enought to hold nnn.nnn.nnn.nnn
if(strlen(addr)>15) return 0;
strcpy(ip, addr);
随后对 ip
而不是 addr
或者...避免使用 strtok
和 parse/scan 字符串而不修改它。
这是一个使用 sscanf
的愚蠢解决方案,只是为了证明它是可行的。 (下面有一些更好的解决方案。)
#include <stdio.h>
/* True if its argument represents a decimal number between
* 0 and 255 without leading zeros. Assumes the characters are
* all digits and that there are at most three of them.
*/
static int good(const char* octet) {
switch (octet[0]) {
case '0': return octet[1] == 0;
case '1': return 1;
case '2': return octet[1] == 0 || octet[2] == 0
|| octet[1] < '5'
|| octet[1] == '5' && octet[2] < '6';
default: return octet[1] == 0 || octet[2] == 0;
}
}
struct OctetSep { char oct[4], sep[2] };
int is_valid_ip(const char *addr) {
struct OctetSep bits[4];
/* The last %c conversion is expected to fail. */
return sscanf(addr, "%3[0-9]%1[.]%3[0-9]%1[.]%3[0-9]%1[.]%3[0-9]%1c",
bits[0].oct, bits[0].sep,
bits[1].oct, bits[1].sep,
bits[2].oct, bits[2].sep,
bits[3].oct, bits[3].sep) == 7
&& good(bits[0].oct) && good(bits[1].oct)
&& good(bits[2].oct) && good(bits[3].oct);
}
当然,大部分工作都是由 good
完成的,将它变得更通用一点会很容易:
#include <stddef.h>
/* This idiocy is avoid problems with signed characters */
static int my_isdigit(char c) { return c >= '0' && c <= '9'; }
/* Returns the address of the first unmatched character after a match
* of an integer with no leading zeros and maximum value 255.
* This address may be in the middle of the integer, if it is too big.
* If the string doesn't start with a digit, returns NULL.
*/
static const char* good(const char* octet) {
switch (octet[0]) {
case '0': return octet + 1;
case '1': return !my_isdigit(octet[1]) ? octet + 1
: !my_isdigit(octet[2]) ? octet + 2
: octet + 3;
case '2': return !my_isdigit(octet[1]) ? octet + 1
: !my_isdigit(octet[2]) ? octet + 2
: octet[1] < '5' || octet[1] == '5' && octet[2] < '6'
? octet + 3
: octet + 2;
case '3': case '4': case '5': case '6': case '7': case '8':
case '9': return !my_isdigit(octet[1]) : octet + 1 ? octet + 2;
default: return NULL;
}
}
int is_valid_ip(const char *addr) {
for (const char* i = "..."; (addr = good(addr)); ++addr, ++i) {
if (*addr != *i) break;
if (!*i) return 1;
}
return 0;
}
但可能最简单的代码来自 strtol
的使用,尽管您仍然需要大量的手动检查。 (此解决方案更适用于有效整数范围大于 256 的应用程序。)
#include <stdlib.h>
/* This idiocy is avoid problems with signed characters */
static int my_isdigit(char c) { return c >= '0' && c <= '9'; }
/* Returns the address of the first character following the integer
* starting precisely at the supplied address, provided the integer
* has no leading zeros and a maximum value of 255. Otherwise,
* returns NULL.
*/
static const char* good(const char* octet) {
if (*octet == '0') return octet + 1;
/* This check is necessary because strtol also accepts whitespace and - */
if (!my_isdigit(*octet)) return NULL;
char *endptr;
long value = strtol(octet, &endptr, 10);
/* We already handled 0, so value==0 must be an error return */
if (value <= 0 || value > 255) return NULL;
return endptr;
}
int is_valid_ip(const char *addr) {
for (const char* i = "..."; (addr = good(addr)); ++addr, ++i) {
if (*addr != *i) break;
if (!*i) return 1;
}
return 0;
}