1
char *strchr( const char *s, int c );

I understand that strchr locates the first occurrence of character c in string s. If c is found, a pointer to c in s is returned. Otherwise, a NULL pointer is returned.

So why does below code outputs num to strlen(string) rather than what its designed to do?

num=0;
   while((strchr(string,letter))!=NULL)
   {
      num++;
      string++;
   }

But this code gives correct output

num=0;
   while((string=strchr(string,letter))!=NULL)
   {
      num++;
      string++;
   }

I fail to see why assigning the pointer that's returned to another qualified pointer even makes a difference. I'm only just testing if return value is a NULL pointer or not.

Leon
  • 346
  • 3
  • 15
  • Other notes about `strchr( const char *s, int c )`: The searched _string_ includes the _null character_ so `strchr(some_strings, 0)` never returns `NULL`. The search is done as if `*s` and `ch` were converted to `unsigned char`. – chux - Reinstate Monica Jan 25 '20 at 05:25
  • This is how I see it: pointer to first `\0` is returned,ie at end of string. Since `(string=strchr(string, letter))!=NULL` will be true at this point, `string++` will occur and string will point beyond its allocated memory. Does this cause some sort of wierd behaviour to never return `NULL`? OR am I winding down the wrong track here? – Leon Jan 25 '20 at 13:36
  • Leon, `letter` with the value of the _null character_ is an unlikely case. But if code does need to handle this, could use `while((string=strchr(string,letter))!=NULL && *string)`. – chux - Reinstate Monica Jan 25 '20 at 17:32

3 Answers3

3
  1. string is a pointer.

  2. In the first example, you just move it right one position, regardless of where (or if!) "letter" was found.

  3. In the second example, every time you find a "letter", you:

    a) update "string" to point to the letter, then

    b) update "string" again to point just past the letter.

FoggyDay
  • 11,962
  • 4
  • 34
  • 48
2

Let me try to put it in different way,

strchr

returns a pointer to the located character, or a null pointer if the character does not occur in the string.

In first part of your snippet return value is not being captured, immediate next position of string from where earlier it was pointing is passed as a argument. In short the snippet is counting total number of character till last appearance of letter

const char* string = "hello"
char letter = 'l'
num=0;
while((strchr(string,letter))!=NULL)
{
    num++;
    string++;
}

Like this,

            +---+---+---+---+---+----+
            |'h'|'e'|'l'|'l'|'o'|'/0,|
            +---+---+---+---+---+----+
              ^
              |
+-------+     |
+string +-----+
+-------+
            +---+---+---+---+---+----+
            |'h'|'e'|'l'|'l'|'o'|'/0,|
            +---+---+---+---+---+----+
                  ^
                  |
+-------+         |
+string +---------+
+-------+

            +---+---+---+---+---+----+
            |'h'|'e'|'l'|'l'|'o'|'/0,|
            +---+---+---+---+---+----+
                      ^
                      |
+-------+             |
+string +-------------+
+-------+



            +---+---+---+---+---+----+
            |'h'|'e'|'l'|'l'|'o'|'/0,|
            +---+---+---+---+---+----+
                              ^
                              |
+-------+                     |
+string +---------------------+
+-------+

In second snippet, return value of strchr is captured back into string and immediate next address is passed as argument in next iteration,

const char* string = "hello"
char letter = 'l'
num=0;
while((string = strchr(string,letter))!=NULL)
{
    num++;
    string++;
}

Something like this,

+-------+     
+string +-----+
+-------+     |
              |
/*input pointer to strchr*/
              |
              v
            +---+---+---+---+---+----+
            |'h'|'e'|'l'|'l'|'o'|'/0,|
            +---+---+---+---+---+----+
                      |
                      |
               /*return pointer from strchr*/
                      |
+-------+             |
+string +<------------+
+-------+     


+-------+                 
+string +-----------------+
+-------+                 |
                          |
            /*input pointer to strchr*/
                          |
                          v
            +---+---+---+---+---+----+
            |'h'|'e'|'l'|'l'|'o'|'/0,|
            +---+---+---+---+---+----+
                          |
                          |
              /*return pointer from strchr*/
+-------+                 |
+string +<----------------+
+-------+     

+-------+                     
+string +---------------------+
+-------+                     |
                              |
                /*input pointer to strchr*/
                              |
                              v
            +---+---+---+---+---+----+
            |'h'|'e'|'l'|'l'|'o'|'/0,|
            +---+---+---+---+---+----+

                   /*NULL return from strchr*/
+-------+                     |
+string +<--------------------+
+-------+
TruthSeeker
  • 1,539
  • 11
  • 24
0

First code snippet:

So why does below code outputs num to strlen(string) rather than what its designed to do?

The output may not be strlen(string) always and will be depend on the input string string and the character letter passed to strchr(). For e.g. if the input is

string = "hello"
letter = 'l'

then the output you will get is 4 which is not equal to the length of string "hello". If the input is

string = "hello"
letter = 'o'

then the output you will get is 5 which is equal to the length of string "hello". If the input is

string = "hello"
letter = 'x'

then the output you will get is 0.
The output is actually depends on the position of last occurrence of the character letter in the input string.

Reason is that there is only one statement which is modifying the position of string pointer and that statement is

      string++;

It is working in this way -
If the character present in the string, the strchr() will return a not null value till the time the input string pointer point to a character on or before the last occurrence of character letter in the string. Once string pointer point to one character after the last occurrence of letter character in the string, the strchr() will return NULL and loop exits and num will be equal to position of the last occurrence of letter character in the string. So, you will get the output within the range from 0 to strlen(string) and not strlen(string) always.

string = "hello", letter = 'e', num = 0
strchr(string, letter) will return not null as 'e' present in input string
num++; string++;

string = "ello", letter = 'e', num = 1
strchr(string, letter) will return not null as 'e' present in input string
num++; string++;

string = "llo", letter = 'e', num = 2
strchr(string, letter) will return null as it does not find 'e' in input string and loop exits

Output will be 2

Second code snippet:

But this code gives correct output

Yes, the reason is the strchr() returned pointer is assigned to string pointer. Take the same example as above, assume the input is

string = "hello"
letter = 'l'

strchr(string, letter) will return the pointer to first occurrence of character l and it is assigned to pointer string. So, now the string pointer pointing first occurrence of l. Which means, now the string is

string = "llo"

and in loop body you are doing

string++;

which will make the string pointer point to next character to the character returned by strchr(). Now the string is

string = "lo"
letter = `l`

and strchr(string, letter) will return the pointer to character which the string is pointing to currently as it is matching to character letter. Due to string++ in the loop body, now the string will point to next character

string = "o"
letter = `l`

and strchr(string, letter) will return NULL and loop will exit. num is incremented as many times as the character letter found in string. Hence the second snippet is giving correct output.

H.S.
  • 11,654
  • 2
  • 15
  • 32