-4

I'm trying to compare an input of characters with a string that can be of the format "!x" where x is any integer.

What's the easiest way to do this? I tried

int result = strcmp(input,"!%d");

which did not work.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
sc1892353
  • 85
  • 1
  • 10

4 Answers4

2

Here's one way to do it:

int is_bang_num(const char *s) {
    if (*s != '!') {
        return 0;
    }
    size_t n = strspn(s + 1, "0123456789");
    return n > 0 && s[1 + n] == '\0';
}

This verifies that the first character is !, that it is followed by more characters, and that all of those following characters are digits.

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • I do think that this is what the OP wants. But this code is unecessarily unsafe. – Iharob Al Asimi Sep 19 '15 at 21:54
  • @iharob How is it unsafe? – melpomene Sep 19 '15 at 21:54
  • @iharob This function takes a string. `NULL` is not a string. You can't guard against a caller passing non-strings. `*s == '\0'` is fine. What's unsafe about that? – melpomene Sep 19 '15 at 21:55
  • Oh, right. I didn't think of that. Sorry :) I still like to check against `NULL`, any good reason to not do that? – Iharob Al Asimi Sep 19 '15 at 21:58
  • 3
    @iharob None of the string functions in the standard library check for `NULL`. And all you could do in that situation is hide a bug in the caller (or call `abort()`, but in that case why not simply crash?). – melpomene Sep 19 '15 at 22:00
  • Not necessarily crash, and you sould give a warning like *WARNING: There is a bug in your code.* You know that the program can continue without crashing if `s == NULL`, don't you? Dereferencing a `NULL` poitner is *Undefined Behavior* so you can't predict the outcome. And if you let the program continue after that, you can corrupt data in the program, thus potentially corrupting data on the permanent storage like a database. It has happened to me in the past and since then, I became extremely paranoic about this. Also, don't you check for `NULL` before calling one of the `str`* functions? – Iharob Al Asimi Sep 19 '15 at 22:02
  • Some programmers do things like `char *string = malloc(length + 1); strcpy(string, something);`. This is potentially dereferencing a `NULL` pointer too. Checking for `NULL` was bad because computers were slow and it seemed like a waste of cpu cycles. But undefined behavior is your enemy, you should avoid it as much as possible. It's just my opinion though. – Iharob Al Asimi Sep 19 '15 at 22:07
  • 1
    OP's coding code is "Comparing an input string with a string ...". `NULL` is not a string so no requirement to check if `s==NULL`. We _could_ add a check for `NULL`, could add a check to see if the integer is in an `int` range, all sort of unrequested checks. Rather than those side issues: what about code goal issues of "x is any integer." like "-123", `+0xABC"? These are not address here. – chux - Reinstate Monica Sep 20 '15 at 01:50
  • @chux I totally agree with you. – Iharob Al Asimi Sep 20 '15 at 12:21
1

You see, scanf() family of functions return a value indicating how many parameters where converted.

Even books usually ignore this value and it leads programmers to ignore that it does return a value. One of the consequences of this is Undefined Behavior when the scanf() function failed and the value was not initialized, not before calling scanf() and since it has failed not by scanf() either.

You can use this value returned by sscanf() to check for success, like this

#include <stdio.h>

int
main(void)
{
    const char *string;
    int value;
    int result;
    string = "!12345";
    result = sscanf(string, "!%d", &value);
    if (result == 1)
        fprintf(stderr, "the value was: %d\n", value);
    else
        fprintf(stderr, "the string did not match the pattern\n");
    return 0;
}

As you can see, if one parameter was successfuly scanned it means that the string matched pattern, otherwise it didn't.

With this approach you also extract the integral value, but you should be careful because scanf()'s are not meant for regular expressions, this would work in very simple situations.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
0

Since the stirng must begin with a ! and follow with an integer, use a qualified strtol() which allows a leading sign character. As OP did not specify the range of the integer, let us allow any range.

int is_sc_num(const char *str) {
  if (*str != '!') return 0;
  str++;

  // Insure no spaces- something strtol() allows.
  if (isspace((unsigned char) *str) return 0;

  char *endptr;
  // errno = 0;

  // By using base 0, input like "0xABC" allowed
  strtol(str, &endptr, 0);

  // no check for errno as code allows any range
  // if (errno == ERANGE) return 0

  if (str == endptr) return 0;  // no digits
  if (*endptr) return 0; // Extra character at the end
  return 1;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
-2

If you want to test that a string matches a format of an exclamation point and then some series of numbers, this regex: "!\d+" will match that. That won't catch if the first number is a zero, which is invalid. This will: "![1,2,3,4,5,6,7,8,9]\d*".

Patrick Stephen
  • 325
  • 1
  • 8