1

Ok, so I have an assignment here from my professor. Here it is:


Write a function called strchr406. It is passed 2 parameters: a string and a char Here is the prototype for the function: char *strchr406(char str[], char ch); The function should return a pointer to the first instance of ch in str. For example:

char s[ ] = "abcbc";
strchr406(s, 'b');   // returns s + 1 (i.e., a pointer to the first 'b' in s)
strchr406(s, 'c');   // returns s + 2
strchr406(s, 'd');   // returns 0

He is asking us to write our own version of strchr using pointers. I looked up online for resources but none of it matches what he is asking us to do. I'm working with a group of other students, and none of us could figure this out.

How do we RETURN "s + 1"?

So far, I have this: (I also put it online if that's easier: https://repl.it/FVK8)

#include <stdio.h>
#include "string_problems.h"

int main() {
  char s[ ] = "abcbc";
  strchr406(s, 'b');   // returns s + 1 (i.e., a pointer to the first 'b' in s)
  strchr406(s, 'c');   // returns s + 2
  strchr406(s, 'd');   // returns 0
  printf("this should return %s\n", strchr406(s, 'c'));
  return 0;
}

char *strchr406(char str[], char ch) {
  char *p = str;
  int index = 0;
  while (*str != ch) {
    ++str;
    ++index;
  }
  if (*str == ch) {
    return p + index;
  } else {
    return 0;
  }

}

I'm getting weird outputs. Any help is appreciated.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
nastypluto
  • 119
  • 4
  • 13
  • 1
    Not clear what your problem is. `strchr` is quite a simple function. However, you cannot return a pointer or an integer from your function, that assignment is nonsense as given (and teaching to use `0` as null pointer constant is bad style; use the `NULL` macro). Maybe your prof means a _null pointer_, which is not the same as the integer `0`? But then you cannot print this like a string, but test explicitly and print something different (that's trhe idea of null pointers). – too honest for this site Jan 25 '17 at 23:41
  • 3
    And don't post images of text. You should at least paste it as text. – too honest for this site Jan 25 '17 at 23:45
  • I will edit it now. – nastypluto Jan 25 '17 at 23:48
  • Yeah, I am not sure what he is asking here. I don't know how that "s+1" and "s+2" works here. – nastypluto Jan 25 '17 at 23:58
  • the posted code is using a header file: `stringproblems.h` but the contents of that file is not posted. Do you expect us to guess as to the contents of that file? – user3629249 Jan 26 '17 at 13:13

3 Answers3

6

From the manual:

  • char *strchr(const char *s, int c); --> the 2nd argument is an int
  • The strchr() and strrchr() functions return a pointer to the matched character or NULL if the character is not found.
  • The terminating null byte is considered part of the string, so that if c is specified as '\0', these functions return a pointer to the terminator.
  • [there is no defined behaviour if the first argument happens to be NULL]

char *strchr42(char *str, int ch)
{
for (;; str++) {
        if (*str == ch) return str;
        if (!*str) return NULL;
        }
return NULL;
}

or even shorter:


char *strchr42a(char *str, int ch)
{
do      {
        if (*str == ch) return str;
        } while (*str++) ;
return NULL;
}
wildplasser
  • 43,142
  • 8
  • 66
  • 109
3

There are a couple of small things you should add or re-organize in your code to make it work.

First, this piece of code

  while (*str != ch) {
    ++str;
    ++index;
  }

will not stop at the end of your string and will continue looping until it finds your char somewhere after the string in the virtual memory of the process.

So you should probably have a condition for stopping that checks for the end of the string (strings in C ends with the char \0, ASCII code = 0):

while (*str != '\0')

Second thing, you are comparing ch with the current char of the string after the loop. You should probably move this code inside the loop: you need to check every character of the string against ch. Also, you don't need to use both an index and increment the pointer str. So you can get rid of the index variable. If at anytime in your loop you find the correct ch then you can directly return the pointer to it using str. If you get out of your loop, it means that you did not find the ch inside str and then you can return NULL (cf man strchr for more on return values).

char *strchr406(char str[], char ch)
{
     while (*str != '\0')
     {
          if (*str == ch)
          {
               return (str);
          }
          str++;
     }
     return (NULL);
}

Note that in this context, even though NULL is 0, it's better to use NULL since you are supposed to return a pointer.

Last thing, if you want to do exactly like strchr, then if ch is '\0' you should return the pointer to the '\0' at the end of the string str. From the man: The terminating null byte is considered part of the string, so that if c is specified as '\0', these functions return a pointer to the terminator. So your code becomes:

char *strchr406(char str[], char ch)
{
     while (*str != '\0')
     {
          if (*str == ch)
          {
               return (str);
          }
          str++;
     }
     /**                                                                                                                    
      * if ch is '\0', you should return                                                                                    
      * the pointer to the `\0` of the string str                                                                           
      */                                                                                                                    
     if (*str == ch)                                                                                                        
     {                                                                                                                      
          return (str);
     }
     return (NULL);
}

Note: Thanks to @chux for pointing this last thing out.

Note 2: You don't need to check if str is NULL in this context.

Note 3: The "official" prototype for strchr is char *strchr(const char *s, int c); so depending on your project requirements you might want to update your prototype to match to this one.

Julien
  • 31
  • 2
  • 1
    Note: `return` is **not** a function. `return (NULL);` -->> `return NULL;` – wildplasser Jan 26 '17 at 00:48
  • "Note that in this context, even though NULL is 0" - err, that's wrong for many implementations. Typically the `NULL` **macro** is `(void *)0`. Even iff it was `0` for a particular implementation, you cannot and shall not rely on it. – too honest for this site Jan 26 '17 at 02:08
  • Thanks @wildplasser. Yes return is not a function, but this is the C style I am using :) – Julien Jan 28 '17 at 00:25
3

Here you are

#include <stdio.h>

char * strchr406( const char str[], char ch ) 
{
    while ( *str && *str != ch ) ++str;

    return ( char * )( ch == *str ? str : NULL );  
}

int main(void) 
{
    char s[ ] = "abcbc";

    printf( "strchr406(s, 'b') == s + 1 is %d\n", strchr406(s, 'b') == s + 1 );
    printf( "strchr406(s, 'c') == s + 2 is %d\n", strchr406(s, 'c') == s + 2 );
    printf( "strchr406(s, 'd') == 0 is %d\n", strchr406(s, 'd') == 0 );
    printf( "this should return %s\n", strchr406(s, 'c'));

    return 0;
}

The program output is

strchr406(s, 'b') == s + 1 is 1
strchr406(s, 'c') == s + 2 is 1
strchr406(s, 'd') == 0 is 1
this should return cbc

Say your professor that it will be correct to declare the function like

char * strchr406( const char str[], char ch );
                  ^^^^^ 

Moreover the standard function has the following declaration

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

because character literals in C have the type int. So you could write the function even the following way

char * strchr406( const char str[], int ch ) 
{
    unsigned char c = ch;

    while ( *str && ( unsigned char )*str != c ) ++str;

    return ( char * )( c == ( unsigned char )*str ? str : NULL );  
}

As for your function then there is no sense to use the variable index because the pointer str is increased itself.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    And tell your professor that the type of the 2nd argument to strchr() is `int`, not `char` – wildplasser Jan 26 '17 at 00:03
  • Yeah, I'm coming from other languages, and still have some problems with pointers. BTW, what are your print statements actually doing? I mean How is strchr406(s, 'b') equals (s+1) ? – nastypluto Jan 26 '17 at 00:09
  • @nastypluto The result of comparisons in C has type int. So if for example two pointers are equal each other then the result of their comparison will be equal to 1. In this statement printf( "strchr406(s, 'b') == s + 1 is %d\n", strchr406(s, 'b') == s + 1 ); I show that indeed the returned pointer is equal to s + 1. – Vlad from Moscow Jan 26 '17 at 00:12
  • Hmm, On 2nd thought, I appear to be wrong about `(unsigned char)` bit. Spec says "The `strchr` function locates the first occurrence of `int` c (converted to a `char`) in the string pointed to by s. " so `*str != (char) ch` is right. Sorry about mis-leading with `unsigned char`. – chux - Reinstate Monica Jan 26 '17 at 00:29
  • @chux Compare with "3 For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char ":) – Vlad from Moscow Jan 26 '17 at 00:34
  • @VladfromMoscow Fair enough. Combining those 2 does that mean we need the equivalent of `(unsigned char )*str != (unsigned char )(char)ch` or `(unsigned char )*str !=(char)ch` or what? Hmmm? – chux - Reinstate Monica Jan 26 '17 at 02:12