I want to compare a String in another String like "ther" in "motherfathersister" and the result would be either null ( no match ) or the remaining characters after the last occurence ( in this example) "thersister".
I have changed the implemantation of strstr from string.h but the result is everytime the same.
Where i have made a mistake?
Thanks
char *stRstr(char *s, char *m)
{
char *last=NULL;
size_t n = strlen(m);
while(*s)
{
if(!memcmp(s++,m,n))
{
last=s-1;
}
}
return last;
}
Thanks Guys
I found my mistake...
i didnt't called my function "stRstr" but "strstr"... And this function is already implemented...
Thanks for your help, without your feedback, in terms of that my functions returns the right result, i would have been lost...
As mentioned in the comments, your code will access s beyond its bounds (consider what memcmp does when s points to the last non-'\0'-character). So I'd get rid of the memcmp-usage and I'd scan the string from backwards.
In analogy to strstr, which quickly scans the string looking for a single-character match and compares then the rest, see the following code that does exactly the same in a backwards manner.
Hope it helps.
const char *stRstr(const char *s, const char *m)
{
const char* ptr = s + strlen(s);
size_t mlen = strlen(m);
while (ptr-- != s) { // until ptr reaches the beginning of s
if (*ptr==*m) { // single character match (first characters of s and m)?
if (strncmp(ptr,m,mlen)==0) // check the remainder
return ptr;
}
}
return NULL;
}
void printLast(const char* s) {
if (s)
printf("last: %s\n", s);
else
printf("string not found.\n");
}
int main() {
const char* s = "this is the first, this is the last";
const char* m = "this";
const char* last = stRstr(s, m);
printLast(last);
last = stRstr(s, "not contained");
printLast(last);
}
Your function should work (the problem is elsewhere) but it has some issues:
using memcmp() is incorrect as it may access s beyond its last element. you should use strncmp() instead or add a test on the lengths.
the posted code would not find the last occurrence of the empty substring and return NULL, where it should return a pointer to the trailing null byte.
for consistency, you should call it strrstr() or my_strrstr().
Here is a faster and safer version:
char *my_strrstr(const char *s, const char *m) {
char *last = NULL;
size_t n = strlen(m);
while ((s = strchr(s, *m)) != NULL) {
if (!strncmp(s, m, n))
last = (char *)s;
if (*s++ == '\0')
break;
}
return last;
}
Related
I am trying to make a function that removes double letters from a string. The function is only supposed to remove double letters next to each other, not in the whole string. e.g 'aabbaa' would become 'aba' (not 'ab'). Im a fairly new to c programming and dont fully understand pointers etc. and need some help. Below is what I have so far. It does not work at all, and I have no idea what to return since when I try and return string[] it has an error:
char doubleletter( char *string[] ) {
char surname[25];
int i;
for((i = 1) ; string[i] != '\0' ; i++) {
if (string[i] == string[(i-1)]) { //Supposed to compare the ith letter in array with one before
string[i] = '\0' ; //Supposed to swap duplicate chars with null
}
}
surname[25] = string;
return surname ;
Try the following. It is a clear simple and professionally-looked code.:)
#include <stdio.h>
char * unique( char *s )
{
for ( char *p = s, *q = s; *q++; )
{
if ( *p != *q ) *++p = *q;
}
return s;
}
int main(void)
{
char s[] = "aabbaa";
puts( unique( s ) );
return 0;
}
The output is
aba
Also the function can be rewritten the following way that to escape unnecassary copying.
char * unique( char *s )
{
for ( char *p = s, *q = s; *q++; )
{
if ( *p != *q )
{
( void )( ( ++p != q ) && ( *p = *q ) );
}
}
return s;
}
Or
char * unique( char *s )
{
for ( char *p = s, *q = s; *q++; )
{
if ( *p != *q && ++p != q ) *p = *q;
}
return s;
}
It seems that the last realization is the best.:)
First of all delete those parenthenses aroung i = 1 in for loop (why you put them there in the first place ?
Secondly if you put \0 in the middle of the string, the string will just get shorter.
\0 terminates array (string) in C so if you have:
ababaabababa
and you replace second 'a' in pair with \0:
ababa\0baba
effectively for compiler it will be like you just cut this string to:
ababa
Third error here is probably that you are passing two-dimensional array to function here:
char *string[]
This is equivalent to passing char **string and essentialy you are passing array of strings while you wanna only to pass a string (which means a pointer, which means an array: char *string or ofc char string[])
Next thing: you are making internal assumption that passed string will have less than 24 chars (+ \0) but you don't check it anywhere.
I guess easiest way (though maybe not the most clever) to remove duplicated chars is to copy in this for loop passed string to another one, omitting repeated characters.
One example, It does not modify input string and returns a new dynamically allocated string. Pretty self explanatory I think:
char *new_string_without_dups(const char *input_str, size_t len)
{
int i = 1;
int j = 0;
char tmpstr[len+1] = {0};
for (; i < len; i++) {
if (input_str[i] == input_str[i-1]) {
continue;
}
tmpstr[j] = input_str[i];
j++;
}
return strdup(tmpstr);
}
Don't forget to free the returned string after usage.
Note that there are several ways to adapt/improve this. One thing now is that it requires C99 std due to array size not being known at compile time. Other things like you can get rid of the len argument if you guarantee a \0 terminated string as input. I'll leave that as excercises.
Your idea behind the code is right, but you are making two fundamental mistakes:
You return a char [] from a function that has char as return type. char [], char * and char are three different types, even though in this case char [] and char * would behave identically. However you would have to return char * from your function to be able to return a string.
You return automatically allocated memory. In other languages where memory is reference counted this is OK. In C this causes undefined behavior. You cannot use automatic memory from within a function outside this very function. The memory is considered empty after the function exits and will be reused, i.e. your value will be overwritten. You have to either pass a buffer in, to hold the result, or do a dynamic allocation within the function with malloc(). Which one you do is a matter of style. You could also reuse the input buffer, but writing the function like that is undesirable in any case where you need to preserve the input, and it will make it impossible for you to pass const char* into the function i.e. you would not be able to do do something like this:
const char *str = "abbc";
... doubleletter(str,...);
If I had to write the function I would probably call it something like this:
int doubleletter (const char *in, size_t inlen, char *out, size_t outlen){
int i;
int j = 0;
if (!inlen) return 0;
if (!outlen) return -1;
out [j++] = in[0];
for (i = 1; i < inlen; ++i){
if (in[i - 1] != in[i]){
if (j > outlen - 1) return -1;
out[j++] = in[i];
}
}
out[j] = '\0';
return j - 1;
}
int main(void) {
const char *str1 = "aabbaa";
char out[25];
int ret = doubleletter(str1, strlen(str1), out, sizeof(out)/sizeof(out[0]));
printf("Result: %s", out);
return 0;
}
I would recommend using 2 indices to modify the string in-place:
void remove_doubles(char *str)
{
// if string is 1 or 0 length do nothing.
if(strlen(str)<=1)return;
int i=0; //index (new string)
int j=1; //index (original string)
// loop until end of string
while(str[j]!=0)
{
// as soon as we find a different letter,
// copy it to our new string and increase the index.
if(str[i]!=str[j])
{
i++;
str[i]=str[j];
}
// increase index on original/old string
j++;
}
// mark new end of string
str[i+1]='\0';
}
Folks, need to search through a character array and replace any occurrence of '+','/',or'=' with '%2B','%2F', and '%2F' respectively
base64output variable looks like
FtCPpza+Z0FASDFvfgtoCZg5zRI=
code
char *signature = replace_char(base64output, "+", "%2B");
signature = replace_char(signature, "/", "%2F");
signature = replace_char(signature, "=", "%3B");
char replace_char (char *s, char find, char replace) {
while (*s != 0) {
if (*s == find)
*s = replace;
s++;
}
return s;
}
(Errors out with)
s.c:266: warning: initialization makes pointer from integer without a cast
What am i doing wrong? Thanks!
If the issue is that you have garbage in your signature variable:
void replace_char(...) is incompatible with signature = replace_char(...)
Edit:
Oh I didn't see... This is not going to work since you're trying to replace a char by an array of chars with no memory allocation whatsoever.
You need to allocate a new memory chunk (malloc) big enough to hold the new string, then copy the source 's' to the destination, replacing 'c' by 'replace' when needed.
The prototype should be:
char *replace_char(char *s, char c, char *replace);
1.
for char use '' single quotes
for char* use "" double quotes
2.
The function does include the return keyword, therefore it does not return what you'd expect
3.
These webpages have examples on string replacement
http://www.cplusplus.com/reference/cstring/strstr/
What is the function to replace string in C?
You could go for some length discussing various ways to do this.
Replacing a single char is simple - loop through, if match, replace old with new, etc.
The problem here is that the length of the "new" part is longer than the length of the old one.
One way would be to determine the length of the new string (by counting chars), and either (1) try to do it in place, or (2) allocate a new string.
Here's an idea for #1:
int replace(char *buffer, size_t size, char old, const char *newstring)
{
size_t newlen = strlen(newstring);
char *p, *q;
size_t targetlen = 0;
// First get the final length
//
p = buffer;
while (*p)
{
if (*p == old)
targetlen += newlen;
else
targetlen++;
++p;
}
// Account for null terminator
//
targetlen++;
// Make sure there's enough space
//
if (targetlen > size)
return -1;
// Now we copy characters. We'll start at the end and
// work our way backwards.
//
p = buffer + strlen(buffer);
q = buffer + targetlen;
while (targetlen)
{
if (*p == old)
{
q -= newlen;
memcpy(q, newstring, newlen);
targetlen -= newlen;
--p;
}
else
{
*--q = *p--;
--targetlen;
}
}
return 0;
}
Then you could use it this way (here's a quick test I did):
char buf[4096] = "hello world";
if (replace(buf, sizeof(buf), 'o', "oooo"))
{
fprintf(stderr, "Not enough space\n");
}
else
{
puts(buf);
}
your replace_char signature returns void
void replace_char (char *s, char find, char replace)
But, when the linker tries to resolve the following
signature = replace_char(signature, "=", '%3B');
It doesn't find any function that's called replace_char and returns int (int is the default if there's no prototype).
Change the replace_char function prototype to match the statement.
EDIT:
The warning states that your function returns char, but you use it as a char *
also, your function doesn't return anything, do you need to return something ?
It looks like you don't really understand the code that you're working with.
Fixing errors and warnings without understanding exactly what you need to do is worthless..
fix like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *replace_char (char *str, char find, char *replace) {
char *ret=str;
char *wk, *s;
wk = s = strdup(str);
while (*s != 0) {
if (*s == find){
while(*replace)
*str++ = *replace++;
++s;
} else
*str++ = *s++;
}
*str = '\0';
free(wk);
return ret;
}
int main(void){
char base64output[4096] = "FtCPpza+Z0FASDFvfgtoCZg5zRI=";
char *signature = replace_char(base64output, '+', "%2B");
signature = replace_char(signature, '/', "%2F");
signature = replace_char(signature, '=', "%3B");
printf("%s\n", base64output);
return 0;
}
below is a code that ACTUALLY WORKS !!!!
Ammar Hourani
char * replace_char(char * input, char find, char replace)
{
char * output = (char*)malloc(strlen(input));
for (int i = 0; i < strlen(input); i++)
{
if (input[i] == find) output[i] = replace;
else output[i] = input[i];
}
output[strlen(input)] = '\0';
return output;
}
So, I have seen this strcpy implementation in C:
void strcpy1(char dest[], const char source[])
{
int i = 0;
while (1)
{
dest[i] = source[i];
if (dest[i] == '\0')
{
break;
}
i++;
}
}
Which to me, it even copies the \0 from source to destination.
And I have also seen this version:
// Move the assignment into the test
void strcpy2(char dest[], const char source[])
{
int i = 0;
while ((dest[i] = source[i]) != '\0')
{
i++;
}
}
Which to me, it will break when trying to assign \0 from source to dest.
What would be the correct option, copying \0 or not?
The code should look like as follows:
char * strcpy(char *strDest, const char *strSrc)
{
assert(strDest!=NULL && strSrc!=NULL);
char *temp = strDest;
while(*strDest++ = *strSrc++); // or while((*strDest++=*strSrc++) != '\0');
return temp;
}
You can NOT delete the second line char *temp = strDest; and directly return strDest. This will cause error for the returned content. For example, it will not return correct value (should be 22) will checking the length of returned char *.
char src_str[] = "C programming language";
char dst_str[100];
printf("dst_str: %d\n", strlen(strcpy(dst_str, src_str)));
Both copy the terminator, thus both are correct.
Note that strcpy2() does the assignment (the copying) first, then the comparison. So it will copy the terminator before realizing it did, and stopping.
Also, note that functions whose names start with str are reserved, so neither of these are actually valid as "user-level" code.
You're wrong. Both copy the \0 (NUL terminator) character. You have to copy the NUL terminator character always or your string will be broken: you'll never know when/where it ends.
Both copy the terminator, thus both are correct.
strcpy2() does the copying first, then the compares. Thus it will copy the terminator and stops.
The functions whose names start with str are reserved, so use any other variables or naming types
It is recommended not to advance the input pointers to the source and destination memory spaces, since the pointers will be used in main right away.
I've mentioned alternate methodical syntax, where in case someone might wonder the code output.
void strcpy1(char * s, char * p)
{
char * temp1 = s;
char * temp2 = p;
while(*temp1 != '\0')
{
*temp2 = *temp1;
temp1++;
temp2++;
}
*temp2 = '\0';
}
void main()
{
char * a = "Hello";
char b[10];
strcpy1(a,b);
printf("%s", b);
return 0;
}
Both strcpy1() and strcpy2() does the same. Both copy the NUL character to the end of the destination array.
Here is full implementation. You do not have to consider the \0 at the end in the first string, it will be copied automatically from the second string as per logic
//str copy function self made
char *strcpynew(char *d, char *s){
char *saved = d;
while ((*d++ = *s++) != '\0');
return saved; //returning starting address of s1
}
//default function that is run by C everytime
int main(){
//FOR STRCPY
char s1[] = "rahul"; //initializing strings
char s2[] = "arora"; //initializing strings
strcpynew(s1, s2);
printf("strcpy: %s\n", s1); //updated string after strcpy
}
You can use this code, the simpler the better !
Inside while() we copy char by char and moving pointer to the next. When the last char \0 will pass and copy while receive 0 and stop.
void StrCopy( char* _dst, const char* _src )
{
while((*_dst++ = *_src++));
}
char * strcpy(char *strDest, const char *strSrc)
{
assert(strDest!=NULL && strSrc!=NULL);
assert(strSrc + strlen(strSrc) < d || strSrc > strDest); // see note
char *temp = strDest;
while(*strDest++ = *strSrc++)
;
return temp;
}
// without the check on line 4, the new string overwrites the old including the null deliminator, causing the copy unable to stop.
Both copy the '\0'. That's what you have to do if you want to fully emulate the original strcpy
I implemented strstr() myself,the code works fine for all strings but when the string lies in the first index of the string,it returns null.
#include<stdio.h>
const char* mystrstr(const char *str1, const char *str2);
int main()
{
const char *str1="chal bhai nikal";
const char *str2="c",*result;
result=mystrstr(str1,str2);
if(*result!=NULL)
printf("found at %d location and the value is %s.",*result, str1+*result);
else
printf("Value not found");
getchar();
printf("\n");
return 0;
}
const char * mystrstr(const char *s1, const char *s2)
{
int i,j,k,len2,count=0;
char *p;
for(len2=0;*(s2+len2)!='\0';len2++); //len2 becomes the length of s2
for(i=0;*(s1+i)!='\0';i++)
{
if(*(s1+i)==*s2)
{
for(j=i,k=0;*(s2+k)!='\0';j++,k++)
{
if(*(s1+j)==*(s2+k))
count++;
else count=0;
if(count==len2)
{
p=(char*)malloc(sizeof(char*));
*p = i;
return p;
}
}
}
}
return NULL;
}
I haven't looked at your mystrstr function, just main.
const char *str2="c",*result;
result=mystrstr(str1,str2);
if(*result!=NULL)
printf("found at %d location and the value is %s.",*result, str1+*result);
else
printf("Value not found");
result is a const char *; *result is a const char.
Are you perhaps mixing NULL pointer and NUL zero-terminator?
result can be NULL; *result can be '\0'
Edit: possible solution
When strstr() fails to find the substring it returns NULL. Supposing your mystrstr() works the same way, you do
/* result=mystrstr(str1,str2); */
result=NULL;
and then
if(*result!=NULL) {/* ... */} else {}
but *result can try to dereference a NULL pointer, which is NOT what you want.
You want to test result itself
if (result != NULL) { /* ... */ } else {}
The problem is that you're returning an index in memory pointed to by a char* (and in this particular case, the matching index is 0, which your code is interpreting as a NULL when it checks the dereferenced result). If you want mystrstr() to have the same behavior as strstr(), you should change:
if(count==len2)
{
p=(char*)malloc(sizeof(char*));
*p = i;
return p;
}
to:
if(count==len2)
{
return s1+i;
}
so a pointer to the substring location is returned.
strstr() doesn't return an index (or a pointer to an index) - it returns a pointer to the character in the string passed as the first parameter where the instance of str2 is found (if it is found). I assume that your intent is for mystrstr() to follow that specification.
So, you'll also need to change the code that checks and deals with the returned value, but I'll leave that as an exercise for the reader.
What the above person said was ok. Because in his way, you don't need to declare a pointer to char p and use malloc to allocate memory for returning pointer to index. It can simplify your code.
But you need to change your main function accordingly.
const char* mystrstr(const char *str1, const char *str2);
int main()
{
const char *str1 = "chal bhai nikal";
const char *str2 = "bh", *result;
result = mystrstr(str1, str2);
if (result != NULL)
{
printf("found at %d location and the value is %s.\n", result - str1, result);
}
else
printf("Value not found");
getchar();
return 0;
}
I'm trying very hard to figure out a way to parse a string and "highlight" the search term in the result by making it uppercase.
I've tried using strstr and moving a pointer along and "toupper"ing the characters, to no avail.
char * highlight( char *str, char *searchstr ) {
char *pnt=str;
int i;
pnt=strstr(str,searchstr);
while(pnt){
printf("ststr retured: %s\n", pnt);
for(i=0;i<strlen(searchstr);i++) {
printf("%c",toupper(pnt[i]));
}
printf("\n");
pnt=pnt+strlen(searchstr);
pnt=strstr(pnt,searchstr);
}
return str;
}
Any advice is greatly appreciated.
Since Schot mentioned every occurrence:
#include <string.h>
char *highlight(char *str, char *searchstr) {
char *pnt = str;
while (pnt = strstr(pnt, searchstr)) {
char *tmp = searchstr;
while(*(tmp++)) { *pnt = toupper(*pnt); pnt++; }
}
return str;
}
int main() {
char s[] = "hello world follow llollo";
char search[] = "llo";
puts(highlight(s, search));
return 0;
}
output is:
$ ./a.out
heLLO world foLLOw LLOLLO
You appreciate that the function takes the string as an argument and then returns that same string, while having -not- modified that string? all the function does is print to stdout the capital characters.
At some point, you would need to change the string itself, e.g.;
pnt[i] = toupper( pnt[i] );
Like Blank Xavier said, you probably want to modify the actual string. toupper does not change the value of the character you supply, but returns a new character that is its uppercase version. You have to explicitly assign it back to the original string.
Some additional tips:
Never do multiple strlen calls on a string that doesn't change, do it once and store the result.
You can express the promise of not changing searchstr by declaring it as const char *.
Below is an example with a (in my opinion) easy method of looping through all strstr matches:
#include <string.h>
#include <ctype.h>
char *highlight(char *s, const char *t)
{
char *p;
size_t i, len = strlen(t);
for (p = s; (p = strstr(p, t)); p += len)
for (i = 0; i < len; i++)
p[i] = toupper(p[i]);
return s;
}