strchr implementation in c is it possible to make this work? - c

please help me out , I'm trying to implement strchr and I still get Null when I run this code... what is it wrong with it?
char *ft_strchr(const char *str, int c)
{
int i;
char *temp;
i = 0;
while (str[i])
{
if (str[i] == c)
{
*temp = str[i];
return (temp);
}
else
return (NULL);
i++;
}
return (str);
}

char* ft_strchr(const char *str, int c){
size_t i;
char *temp;
i = 0;
while (str[i])
{
if (str[i] == c)
{
temp = &str[i];
return temp;
}
i++;
}
if(str[i]==c)
{
return &str[i];
}
return NULL;
// You need to return NULL after scanning whole line..
// Or it will send NULL checking after 1st character
}

strchr is supposed to return a pointer to the matching character in the string. You're returning a pointer, but it doesn't point into the string. You never initialized it, so it doesn't point anywhere.
Change
*temp = str[i];
to:
temp = &str[i];

the following code:
makes use of the fact the C passes by value rather than by reference
eliminates the code clutter,
uses a for() statement so the compiler handles all the loop details,
eliminates all the code clutter
Note: this kind of expression: *str evaluates to true, except when the char pointed at is '\0'.
So the below code walks through the passed in char string, terminating on either of two conditions.
1) a matching char is found in the string or
2) end of string is encountered.
The return statement returns NULL if end of string is encountered, else returns the address of where the matching char is first found in the string.
char *ft_strchr(const char *str, int c)
{
for( ; *str && (*str != c); str++ ) ;
return ( *str? str : NULL);
}

Related

removing a char from a string in c by index

how can I remove a certain char from a string in c without using any library
functions? the function i wrote seems to have a run time error and i can not figure out why.
void remove_char(char* s,int index)
{
while(s[index+1] != 0)
{
s[index] = s[index + 1];
index++;
}
s[index] = 0;
}
I was also wondering if there is a way to remove a char in a complexity of 1?
Without seeing how you are calling your function, knowing the exact failure mode is difficult. Calling it with char string[] = "this is a string";, it worked fine. But as the comments suggest, some other forms of input strings may cause a problem.
I have used the following implementation with no problems. It removes all occurrences of a specified character:
int RemoveCharFromString(char *orig, char c, char *newStr)
{
if(!orig) return -1;
if(!newStr) return -1;
int i=0, j=0;
while (*(orig+i) != '\0')
{
if (*(orig+i) != c)
{
*(newStr+j) = *(orig+i);
j++;
i++;
}
else i++;
}
*(newStr+j) = '\0';
return 0;
}
Or, as you requested, this one removes a character at a specified index:
int RemoveCharFromStringByIndex(char *orig, int index, char *newStr)
{
if(!orig) return -1;
if(!newStr) return -1;
int i=0, j=0;
while (*(orig+i) != '\0')
{
if (i != index)
{
*(newStr+j) = *(orig+i);
j++;
i++;
}
else i++;
}
*(newStr+j) = '\0';
return 0;
}
Notice, in this implementation newStr is created by caller and must include space enough to contain the result.
You can certainly adapt these in any way you need to. An improvement would be to change the prototype to:
char * RemoveCharFromString(char *orig, char c);
Or
char * RemoveCharFromStringByIndex(char *orig, int index)
But that will be something you can do, if you wish it so.
I always like this for removing a specific char from a string:
int RemoveCharFromString(const char *src, char *dst, char c)
{
const char *s;
char *d;
if ((char *)0 != src && (char *)0 != dst) {
for (d = dst, s = src; (*d = *s); s++) {
if (c != *d)
d++;
}
return 0;
}
return 1;
}
Only increment the destination pointer if it's not equal to the character being skipped. Sometimes you see this using the passed arguments src and dst directly, but way back when some compilers would produce more efficient code with separate pointers. The "const" simply allows you to pass a constant string as the source without producing a compiler error.

Why malloc can't work with strcpy?

char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}else{
printf("Error");
}
return copy;
}
int main(int argc, char * argv[]){
char str[] = "Input string";
char * input;
input = removeChar(str,'g');
printf("%s\n", input);
free(input);
return 0;
}
I don't know why every time I try to run it ,it always says uninitialized variable and sticks in the strcpy line and printf line.
Basically this function is to take a string, and a character and removes the that character from the string (because I am learning malloc so that's why I wrote the function like this).
After the while loop do:
copy[j] = '\0';
to NULL-terminate your string; that way it can work with methods coming from <string.h>, which assume that the string is nul-terminated.
PS: One warning you should see is about not returning copy in your function in any case, because now if the condition of the if statement is wrong, your function won't return something valid, so add this:
return copy;
at the end of your function (which is now corrected with your edit).
Other than that, the only warning you should still get are for the unused arguments of main(), nothing else:
prog.c: In function 'main':
prog.c:32:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
prog.c:32:27: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
While you copy over bytes from str to copy, you don't add a terminating null byte at the end. As a result, strcmp reads past the copied characters into unitialized memory, possibly past the end of the allocated memory block. This invokes undefined behavior.
After your while loop, add a terminating null byte to copy.
Also, you never return a value if the if block at the end is false. You need to return something for that, probably the copied string.
char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
// add terminating null byte
copy[j] = '\0';
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}
// always return copy
return copy;
}
You never initialised input and the some compilers don't notice,
that the the value is never used before the line
input = removeChar(str, 'g');
in your code. So they emit the diagnostic just to be sure.
strcpy(str, copy)
gets stuck in your code, as copy never got a closing 0 byte and
so depends on the nondeterministic content of your memory at the
moment of the allocation of the memory backing copy, how long strcpy
will run and if you get eventually a SIGSEGV (or similar).
strcpy will loop until it finds a 0 byte in your memory.
For starters to remove a character from a string there is no need to create dynamically a character array and then copy this array into the original string.
Either you should write a function that indeed removes the specified character from a string or a function that creates a new string based on the source string excluding the specified character.
It is just a bad design that only confuses users. That is the function is too complicated and uses redundant functions like malloc, strlen, strcmp and strcpy. And in fact it has a side effect that is not obvious. Moreover there is used incorrect type int for the length of a string instead of the type size_t.
As for your function implementation then you forgot to append the terminating zero '\0' to the string built in the dynamically allocated array.
If you indeed want to remove a character from a string then the function can look as it is shown in the demonstrative program.
#include <stdio.h>
char * remove_char(char *s, char c)
{
char *p = s;
while (*p && *p != c) ++p;
for ( char *q = p; *p++; )
{
if (*p != c) *q++ = *p;
}
return s;
}
int main( void )
{
char str[] = "Input string";
puts(str);
puts(remove_char(str, 'g'));
return 0;
}
The program output is
Input string
Input strin
If you are learning the function malloc and want to use it you in any case should try to implement a correct design.
To use malloc you could write a function that creates a new string based on the source string excluding the specified character. For example
#include <stdio.h>
#include <stdlib.h>
char * remove_copy_char(const char *s, char c)
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p != c) ++n;
}
char *result = malloc(n + 1);
if (result)
{
char *q = result;
for (; *s; ++s)
{
if (*s != c) *q++ = *s;
}
*q = '\0';
}
return result;
}
int main( void )
{
char *str = "Input string";
puts(str);
char *p = remove_copy_char(str, 'g');
if ( p ) puts(p );
free(p);
return 0;
}
The program output will be the same as above.
Input string
Input strin
Pay attention to the function declaration
char * remove_copy_char(const char *s, char c);
^^^^^^
In this case the source string can be a string literal.
char *str = "Input string";

C code to reverse a string - including NULL character at the end of string

1.) Is it possible to reverse a string including the NULL character
(which means that “abcd” is represented as five characters, including the null character.)
2.) In my current implementation, that doesn't take 1.) into account,
I am getting segmentation error during swapping. ie while assigning: *str = *end;
void reverse(char *str)
{
char * end = str;
char tmp;
if (str)
{ // to handle null string
while (*end)
{ // find the end character
++end;
}
--end; // last meaningful element
while (str < end) // terminal condition: str and end meets in the middle
{ tmp = *str; // normal swap subroutine
*str = *end; // str advance one step
*end = tmp; // end back one step
str++;
end-- ;
}
}
return;
}
Your function is correct. It seems that the problem is that you are trying to reverse a string literal. You may not change string literals. They are immutable. Any attemp to change a string literal results in undefined behaviour of the program.
From the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined
Only take into account that it would be better to write
if ( *str )
instead of
if (str)
Or if you want to check that the poinetr is not NULL then
if ( str && *str )
In this case this decrement
--end;
will be valid even if the original string is empty.
Nevertheless the function itself could be defined the following way as it is shown in the demonstrative program
#include <stdio.h>
char * reverse( char *s )
{
char *last = s;
while ( *last ) ++last;
if ( last != s )
{
for ( char *first = s; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main( void )
{
char s[] = "Hello arshdeep kaur";
puts( s );
puts( reverse( s ) );
}
The program output is
Hello arshdeep kaur
ruak peedhsra olleH
Calling your code like this:
int main()
{
char a[]="abcd";
int i;
reverse(a);
for (i=0;i<5;i++) {
printf("a[%d]=%02x\n",i,a[i]);
}
}
Outputs this:
a[0]=64
a[1]=63
a[2]=62
a[3]=61
a[4]=00
So you're probably passing in a string literal (i.e. char *a="abcd";). These literals are commonly stored in a read-only section of memory, which is likely why it is core dumping.
That being said, doing a reversal including the null character is not of much practical usage when you're dealing with strings.
I'm quite certain you can. You just need the length of the string and be aware to test NUL.
Strings can and probably should be thought of as character arrays. In particular, trying to direction assign a string literal to an already initialized string is an invalid operation.
An Example:
Here is one way to reverse a string:
void reverse(char *str) {
// First calculate the length
unsigned int length = 0;
int i = 0;
for (; str[i] != '\0'; i++) {
++length;
}
++length;
// Allocate temporary storage
char tmp = malloc(length);
int x = 0;
// Loop through starting at the end and go backwards
// It is perfectly legal to change the characters themselves, just not the pointer
for (i = length - 1; i >= 0; i++, x++) {
if (str[i] != '\0') {
tmp[x] = str[i];
}
}
tmp[length - 1] = '\0';
// Reassign to the given argument
for (i = 0; i < length; i++) {
str[i] = tmp[i];
}
// Free memory
free(tmp);
}
Like the other answer stated, you're trying to do something that is left as undefined behavior in the standard.
You can try this :
void reverse(char *str) {
char *end = str;
char tmp;
if (str) {
while (*end){
++end;
}
--end;
while (str < end) {
tmp = *str;
*str++ = *end;
*end-- = tmp;
}
}
}

How can I check if an element of an array is the terminating element and return a new line?

I need to check an array like 'Hello' and check when the terminating element is and then return a new line due to it. I've been trying code like this:
char * my_strchr(const char * string, int ch)
{
int count;
int length = strlen(string);
for(count = 0; count < length; count++)
{
if(string[count] == '\0')
{
return '\n' ;
}
}
My compiler does not like when I use these for some reason. In the function declaration for string it reads const char * string
The strlen function returns the string length without the NULL terminator. What this means is that your function does not return a char pointer, because your code will never get to the condition string[count] == '\0'.
Further, even if you did reach that condition, you are returning a char, not a char *, which is an error. Your function agreed to return a char * so some kind of char * needs to be returned, even if it points to NULL.
It also isn't clear from your function code, because it lacks a terminating bracket, but your function may never return anything.
Kind of guessing from your description, but perhaps something like this?
char * my_strchr(const char * string, int ch) {
int i;
int c;
for (i = 0; (c = string[i]) != '\0'; ++i) {
if (c == ch) return string + i; /* aka &string[i] */
}
return "\n"; /* got to the end w/o finding ch in string */
}
char *my_strchr(const char *string, int ch){
if(*string == '\0')
putchar('\n');//side effect
while(*string){
if(*string == ch)
return (char*)string;
++string;
}
return *string == ch ? (char*)string : NULL;
}

implementation of strstr() function

The code says at many places "invalid indirection".Please help.
int main()
{
char *s1,*s2,*position;
printf("Enter string:\n");
gets(s1);
printf("Enter word to find:\n");
gets(s2);
*position=ststr(*s1,*s1);
if(*position)
printf("word is found at %c loc\n",*position);
else
printf("word not found");
getch();
return 0;
}
char *strstr(char *s1,char *s2)
{
int flag=1;
char i,j;
for(i=0; ;i++)
{
if(*s1[i]==*s2[0])
for(j=i;*s2;j++)
{
if(*s1[j]!=*s2[j])
flag=0;
}
}
if(flag)
return i;
else
return 0;
}
First, s1 and s2 in main have not been initialized to point anywhere meaningful. Either declare them as static arrays, or allocate memory to them at runtime using malloc() or calloc():
#define SIZE 20 // or some number big enough to hold your input
...
char s1[SIZE], s2[SIZE], *position; // s1 and s2 declared statically
Second, NEVER NEVER NEVER NEVER NEVER use gets(); it will introduce a point of failure in your program. Use fgets() instead:
if (fgets(s1, sizeof s1, stdin) != NULL)
// process s1
else
// check for EOF or error on read
EDIT
And like everyone else has pointed out, your comparison in the strstr() function needs to be either
*s1 == *s2
or
s1[i] == s2[i]
but first you need to deal with allocating your buffers in main properly.
One of the problems I'm noticing is whenever you do *s1[j]. The asterisk is dereferencing the array, and so is the [] notation.
s[i] really means *(s + i), so you don't have to dereference it again. The way you have it would read **(s + i), and since it's a single pointer you can't do that.
if(*s1[i]==*s2[0])
is such an example where my gcc complains:
error: invalid type argument of ‘unary *’ (have ‘int’)
if s1 is a pointer to char, s1[i] is a char. So you can't dereference it any more (with the *), i.e. s1[i] does not point to anything any more.
Try
if(s1[i]==s2[0])
instead.
You should also change the return value of strstr: you return an integer where you declare to return a pointer to a character. So try returning s1+i instead.
This here:
for(j=i;*s2;j++)
probably does not what you want. You're not advancing the pointer s2 anywhere in the loop, in fact you're just testing whether s2[0] (which is the same as *s2) is zero for each iteration. If s2 isn't the empty string, this loop will never terminate.
#include "stdio.h"
char *strstr(char *str, char *substr)
{
int len = strlen(substr);
char *ref = substr;
while(*str && *ref)
{
if (*str++ == *ref)
{
ref++;
}
if(!*ref)
{
return (str - len);
}
if (len == (ref - substr))
{
ref = substr;
}
}
return NULL;
}
int main(int argc, char *argv[])
{
printf("%s \n", strstr("TEST IS NOT DONE", "IS NOT"));
}
if(*s1[j]!=*s2[j])
*s1 means "the character where s1 is pointing".
s1[j] means "*(s1+j)" or "the character j positions after where s1 is pointing"
You have to use one or the other; not both.
#include <stdio.h>
char* my_strstr(char *s2, char *s1)
{
int i, j;
int flag = 0;
if ((s2 == NULL || s1 == NULL)) return NULL;
for( i = 0; s2[i] != '\0'; i++)
{
if (s2[i] == s1[0])
{
for (j = i; ; j++)
{
if (s1[j-i] == '\0'){ flag = 1; break;}
if (s2[j] == s1[j-i]) continue;
else break;
}
}
if (flag == 1) break;
}
if (flag) return (s2+i);
else return NULL;
}
int main()
{
char s2[] = "This is the statement";
char s1[] = "the";
char *temp;
temp = my_strstr(s2,s1);
printf("%s\n",temp);
return 0;
}

Resources