2

I'm trying to get 2 more characters after finding the first occurrence with strchr over a char pointer. The string can look like:

foo;bar;2012 -> should output foo;b
foo;caz;     -> should output foo;c
foo;         -> should output foo (there are no +2 chars)
foo          -> null

For the first case, I figure I can do something like,

#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] = "foo;bar;2012";
  char *pch = NULL;

  if ((pch=strchr(str,';')) != NULL) {
    *pch++;
    *pch++;
    *pch = '\0';
  }
  puts(str);
  return 0;
}

But what's the proper way of checking if I can advance the pointer within the string without going over?

Peter D
  • 47
  • 5
  • 1
    If you need to handle more than 2 characters, or an arbitrary number of them, then use strlen(str) to get the length. After that you can create an end pointer with str + len to compare against pch or you can find your index by pch - str to compare against len. Then you subtract to find how many characters are at the end of the string. – Zan Lynx May 30 '16 at 03:23
  • @ZanLynx Thanks, great to know about that. – Peter D May 30 '16 at 03:26
  • Try changing each `*pch++;` to `if (*pch) pch++;` – Dmitri May 30 '16 at 04:18

1 Answers1

3

The *pch++ lines should be generating a compiler warning (if they don't, you aren't compiling with enough warnings enabled). I compile with warnings treated as errors so I get:

xw31.c:10:5: error: value computed is not used [-Werror=unused-value]
     *pch++;

You should use pch++; — that doesn't read but ignore the value.

You should check that you've not reached end of string while accessing beyond where strstr() points you, so could use:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char str[] = "foo;bar;2012";
    char *pch;

    if ((pch = strchr(str, ';')) != NULL)
    {
        if (pch[1] != '\0' && pch[2] != '\0')
            pch[3] = '\0';
        puts(str);
    }
    return 0;
}

If the inner test fails, the string is short enough already. pch[0] is the semicolon, of course. This generates foo;ba as the output. If you want just foo;b, then you only need to test one character less ahead:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char str[] = "foo;bar;2012";
    char *pch;

    if ((pch = strchr(str, ';')) != NULL)
    {
        if (pch[1] != '\0')
            pch[2] = '\0';
        puts(str);
    }
    return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thanks, I understand now. I wasn't sure if it was safe to check the next char `pch[1]`. – Peter D May 30 '16 at 03:24
  • Given that you start with a (null terminated) string, you know there must be at least one byte after the semicolon that it's safe to read. The code shown checks whether it is safe to go further. It might sometimes overwrite a null byte with another. – Jonathan Leffler May 30 '16 at 03:40