Reputation: 115
I need the string "on" to be replaced with "in", strstr() function returns a pointer to a string so i figured assigning the new value to that pointer would work but it didn't
#include <stdio.h>
#include <string.h>
int main(void) {
char *m = "cat on couch";
*strstr(m, "on") = "in";
printf("%s\n", m);
}
Upvotes: 2
Views: 6264
Reputation: 1415
This function performs a generic pattern replace for all instances of a substring with a replacement string. It allocates a buffer of the correct size for the result. Behaviour is well defined for the case of the empty substring corresponding to the javascript replace() semantics. Where possible memcpy is used in place of strcpy.
/*
* strsub : substring and replace substring in strings.
*
* Function to replace a substring with a replacement string. Returns a
* buffer of the correct size containing the input string with all instances
* of the substring replaced by the replacement string.
*
* If the substring is empty the replace string is written before each character
* and at the end of the string.
*
* Returns NULL on error after setting the error number.
*
*/
char * strsub (char *input, char *substring, char *replace)
{
int number_of_matches = 0;
size_t substring_size = strlen(substring), replace_size = strlen(replace), buffer_size;
char *buffer, *bp, *ip;
/*
* Count the number of non overlapping substring occurences in the input string. This
* information is used to calculate the correct buffer size.
*/
if (substring_size)
{
ip = strstr(input, substring);
while (ip != NULL)
{
number_of_matches++;
ip = strstr(ip+substring_size, substring);
}
}
else
number_of_matches = strlen (input) + 1;
/*
* Allocate a buffer of the correct size for the output.
*/
buffer_size = strlen(input) + number_of_matches*(replace_size - substring_size) + 1;
if ((buffer = ((char *) malloc(buffer_size))) == NULL)
{
errno=ENOMEM;
return NULL;
}
/*
* Rescan the string replacing each occurence of a match with the replacement string.
* Take care to copy buffer content between matches or in the case of an empty find
* string one character.
*/
bp = buffer;
ip = strstr(input, substring);
while ((ip != NULL) && (*input != '\0'))
{
if (ip == input)
{
memcpy (bp, replace, replace_size+1);
bp += replace_size;
if (substring_size)
input += substring_size;
else
*(bp++) = *(input++);
ip = strstr(input, substring);
}
else
while (input != ip)
*(bp++) = *(input++);
}
/*
* Write any remaining suffix to the buffer, or in the case of an empty find string
* append the replacement pattern.
*/
if (substring_size)
strcpy (bp, input);
else
memcpy (bp, replace, replace_size+1);
return buffer;
}
For testing purposes I include a main program that uses the replacement function.
#define BUFSIZE 1024
char * read_string (const char * prompt)
{
char *buf, *bp;
if ((buf=(char *)malloc(BUFSIZE))==NULL)
{
error (0, ENOMEM, "Memory allocation failure in read_string");
return NULL;
}
else
bp=buf;
printf ("%s\n> ", prompt);
while ((*bp=getchar()) != '\n')bp++;
*bp = '\0';
return buf;
}
int main ()
{
char * input_string = read_string ("Please enter the input string");
char * pattern_string = read_string ("Please enter the test string");
char * replace_string = read_string ("Please enter the replacement string");
char * output_string = strsub (input_string, pattern_string, replace_string);
printf ("Result :\n> %s\n", output_string);
free (input_string);
free (pattern_string);
free (replace_string);
free (output_string);
exit(0);
}
Upvotes: 2
Reputation: 144715
Replacing a substring with another is easy if both substrings have the same length:
strstr
memcpy
to overwrite it with the new substring.*strstr(m, "on") = "in";
is incorrect and should generate a compiler warning. You would avoid such mistakes with gcc -Wall -Werror
.char
so you can modify it.Here is a corrected version:
#include <stdio.h>
#include <string.h>
int main(void) {
char m[] = "cat on couch";
char *p = strstr(m, "on");
if (p != NULL) {
memcpy(p, "in", 2);
}
printf("%s\n", m);
return 0;
}
If the replacement is shorter, the code is a little more complicated:
#include <stdio.h>
#include <string.h>
int main(void) {
char m[] = "cat is out roaming";
char *p = strstr(m, "out");
if (p != NULL) {
memcpy(p, "in", 2);
memmove(p + 2, p + 3, strlen(p + 3) + 1);
}
printf("%s\n", m);
return 0;
}
In the generic case, it is even more complicated and the array must be large enough to accommodate for the length difference:
#include <stdio.h>
#include <string.h>
int main(void) {
char m[30] = "cat is inside the barn";
char *p = strstr(m, "inside");
if (p != NULL) {
memmove(p + 7, p + 6, strlen(p + 6) + 1);
memcpy(p, "outside", 7);
}
printf("%s\n", m);
return 0;
}
Here is a generic function that handles all cases:
#include <stdio.h>
#include <string.h>
char *strreplace(char *s, const char *s1, const char *s2) {
char *p = strstr(s, s1);
if (p != NULL) {
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
if (len1 != len2)
memmove(p + len2, p + len1, strlen(p + len1) + 1);
memcpy(p, s2, len2);
}
return s;
}
int main(void) {
char m[30] = "cat is inside the barn";
printf("%s\n", m);
printf("%s\n", strreplace(m, "inside", "in"));
printf("%s\n", strreplace(m, "in", "on"));
printf("%s\n", strreplace(m, "on", "outside"));
return 0;
}
Upvotes: 5
Reputation: 21542
There are a few problems with this approach. First, off, m
is pointing to read-only memory, so attempting to overwrite the memory there it is undefined behavior.
Second, the line: strstr(m, "on") = "in"
is not going to change the pointed-to string, but instead reassign the pointer.
Solution:
#include <stdio.h>
#include <string.h>
int main(void)
{
char m[] = "cat on couch";
memcpy(strstr(m, "on"), "in", 2);
printf("%s\n", m);
}
Note that if you had just used plain strcpy
it would null-terminate after "cat in"
, so memcpy
is necessary here. strncpy
will also work, but you should read this discussion before using it.
It should also be known that if you are dealing with strings that are not hard-coded constants in your program, you should always check the return value of strstr
, strchr
, and related functions for NULL
.
Upvotes: 2