0

I'm trying to create a counter that counts the amount of characters in a string before "?". I have issues with using strcmp to terminate the while-loop and end up with a segmentation fault. Here's what I have:

void printAmount(const char *s)
{
    int i = 0;
    while ( strcmp(&s[i], "?") != 0 ) {
        i++;
    }
    printf("%i", i);
}
huge_gape
  • 13
  • 1
  • If you want to count characters use character comparison (`s[i] != '?'`). `strcmp` is for comparing null-terminated strings. – UnholySheep Feb 18 '22 at 13:52
  • Any particular reason why you aren't using `strchr`? – Lundin Feb 18 '22 at 13:53
  • Your loop should also include some condition for reaching the end of the string without finding a `?` character – UnholySheep Feb 18 '22 at 13:54
  • @Lundin Not sure if the OP requires `'\0'` characters inside the string. – Martin Rosenau Feb 18 '22 at 19:02
  • @MartinRosenau Then it isn't a string and strcmp wouldn't work either. – Lundin Feb 18 '22 at 20:33
  • @Lundin The OP writes that his program ends in a segmentation fault. So we don't know if `strcmp` works. In programming languages that do not use "NUL-terminated strings" (such as Java or C#), `"AB\0C\0D"` is a perfectly valid string containing two NUL bytes in the middle. So why should an `'X'`-terminated string containing NUL bytes not be valid? – Martin Rosenau Feb 19 '22 at 06:58
  • @Lundin Surely you could argue that a string containing NUL bytes in the middle cannot be passed to functions like `puts()`. However, an `'X'`-terminated string cannot be passed to `puts()` anyway so the OP must write his own `strlen()` function (searching for `'X'` instead of `'\0'`) and then use `fwrite()` to write the string to `stdout`. This would also work with an "`'X'`-terminated string" containing NUL bytes in the middle if his `strlen()` implementation treats NUL as normal character. – Martin Rosenau Feb 19 '22 at 07:02

3 Answers3

1

Don't use strcmp for this. Just use the subscript operator on s directly.

Example:

#include <stdio.h>

void printAmount(const char *s) {
    int i = 0;
    while (s[i] != '?' && s[i] != '\0') {
        i++;
    }
    printf("%d", i);
}

int main() {
    printAmount("Hello?world"); // prints 5
}

Or use strchr

#include <string.h>

void printAmount(const char *s) {
    char *f = strchr(s, '?');
    if (f) {
        printf("%td", f - s);
    }
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Again, any particular reason for not using `strchr`? – Lundin Feb 18 '22 at 13:55
  • @Lundin No, not at all. Added. – Ted Lyngmo Feb 18 '22 at 13:55
  • `printf("%zu", f - s);` -> `printf("%td", f - s);`. Or preferably cast to some more sensible type after subtracting the pointers. – Lundin Feb 18 '22 at 14:01
  • @Lundin Nice. I wasn't even aware `printf` had a special modifier for pointer diffs. Thanks! – Ted Lyngmo Feb 18 '22 at 14:03
  • @TedLyngmo Basically its a `size_t`, you get while subtracting two pointers. – BitTickler Feb 18 '22 at 14:05
  • `ptrdiff_t` is a weird type regardless, so I wouldn't really recommend using it. However, it can actually be larger than `size_t`. `printf("%zu", (size_t)(f - s));` would be fine though. – Lundin Feb 18 '22 at 14:05
  • @Lundin is the requirement for size_t not `sizeof(size_t) == sizeof(void*)`? There is also `ssize_t` to consider with its own pitfalls (half-range). Don't program in C if you can avoid it :) – BitTickler Feb 18 '22 at 14:06
  • 1
    @BitTickler I don't remember the standard giving any such guarantee. However, `sizeof(size_t)` doesn't necessarily correspond to the largest value `SIZE_MAX` of that type. Regarding weird behavior of `size_t` vs `ptrdiff_t` check out this: [Why is the maximum size of an array "too large"?](https://stackoverflow.com/questions/42574890/why-is-the-maximum-size-of-an-array-too-large) – Lundin Feb 18 '22 at 14:12
0

strcmp() compares strings, not characters. So, if you input is something like "123?456", your logic does not work, because "?" != "?456". Thus, your while loop never terminates and you start using stuff outside the string.

void printAmount(const char * s) {
  int i = 0;
  for (; s[i] != '?' && s[i] != '\0'; i++) {
     /* empty */
  }
  if (s[i] == '?') {
    printf("%d",i); // the correct formatting string for integer is %d not %i
  }  
}
BitTickler
  • 10,905
  • 5
  • 32
  • 53
0

Unless you have very strange or specialized requirements, the correct solution is this:

#include <string.h>

char* result = strchr(str, '?');
if(result == NULL) { /* error handling */ }

int characters_before = (int)(result - str);
Lundin
  • 195,001
  • 40
  • 254
  • 396