Efficiently replace a substring in a string - c

I have made two functions that find a substring index and substitute that substring in the string. I'm glad I jury rigged this at all, given that similar questions previously asked were never answered/marked as closed without any help. Is there a cleaner method?
void destroy_substr(int index, int len)
{
int i;
for (i = index; i < len; i++)
{
string[i] = '~';
}
}
void find_substr_index(char* substr)
{
int i;
int j;
int k;
int count;
int len = strlen(substr);
for (i = 0; i < strlen(string); i++)
{
if (string[i] == substr[0])
{
for(j = i, k = 0; k < len; j++, k++)
{
if (string[j] == substr[k])
{
count++;
}
if (count == len)
destroy_substr((j - len + 1), len);
}
j = 0;
k = 0;
count = 0;
}
}
}

Your code seems like you're trying to re-inventing your own wheel.
By using standard C functions, which is strstr() and memset(), you can achieve the same result as you expected.
#include <stdio.h>
#include <string.h>
char string[] = "foobar foobar foobar";
char substr[] = "foo";
char replace = '~';
int main() {
int substr_size = strlen(substr);
// Make a copy of your `string` pointer.
// This is to ensure we can safely modify this pointer value, without 'touching' the original one.
char *ptr = string;
// while true (infinite loop)
while(1) {
// Find pointer to next substring
ptr = strstr(ptr, substr);
// If no substring found, then break from the loop
if(ptr == NULL) { break; }
// If found, then replace it with your character
memset(ptr, replace, substr_size);
// iIncrement our string pointer, pass replaced substring
ptr += substr_size;
}
printf("%s\n", string);
return 0;
}

How about this:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char string[] = "HELLO hello WORLD world HELLO hello ell";
char substring[] = "ell";
int stringLength = strlen(string);
int substringLength = strlen(substring);
printf("Before: %s\n", string);
if(substringLength <= stringLength)
{
int i;
int j;
for(i = 0, j = stringLength - substringLength + 1; i < j; )
{
if(memcmp(&string[i], substring, substringLength) == 0)
{
memset(&string[i], '~', substringLength);
i += substringLength;
}
else
{
i++;
}
}
}
printf("After: %s\n", string);
return 0;
}
Key ideas are:
You only need to scan the string (stringLength - substringLength) times
You can use functions from string.h to do the comparison and to replace the substring

You can copy the new string in place. If you want to support insertion of longer strings you will need to manage memory with malloc()/realloc(). If you want to support insertion of smaller strings you'll need to advance the pointer to the beginning by the length of the replacement string, copy the rest of the string to that new location, then zero the new end of the string.
#include <stdio.h>
#include <string.h>
#include <err.h>
int main(int argc, char **argv)
{
char *str = strdup("The fox jumps the dog\n");
char *search = "fox";
char *replace = "cat";
size_t replace_len = strlen(replace);
char *begin = strstr(str, search);
if (begin == NULL)
errx(1, "substring not found");
if (strlen(begin) < replace_len)
errx(1, "replacement too long");
printf("%s", str);
memcpy(begin, replace, replace_len);
printf("%s", str);
return 0;
}

Related

Write a C program that sequentially writes two strings into each other?

I got given this assignment:
Write a C program that sequentially writes two strings into each other as shown in the figure below. Start with a string
consisting of “X”-es and with each iteration, the first and last X characters must be rewritten until the entire string is
rewritten and the final message is displayed.
Hint: Make use a function in the library, strlen(), to determine the length of a string.
It should output like this:
XXXXXXXXXXXXXXXXXXXXX
IXXXXXXXXXXXXXXXXXXX!
I XXXXXXXXXXXXXXXXXg!
I lXXXXXXXXXXXXXXXng!
I loXXXXXXXXXXXXXing!
I lovXXXXXXXXXXXming!
I loveXXXXXXXXXmming!
I love XXXXXXXamming!
I love CXXXXXramming!
I love C-XXXgramming!
I love C-PXogramming!
I love C-Programming!
Final String= I love C-Programming!
This is what I have so far:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
//data
char str[] = "I love C-Programming!";
int rows;
int columns;
int length = strlen(str);
int format =5;
//process
{
rows = 0;
while (rows <= length)
{
rows++;
}
while (rows > 0)
{
int count = length;
columns = rows - 1;
while (columns > 0)
{
printf("X");
columns--;
count --;
}
if (rows <= length)
{
printf("%.*s", count, str);
}
printf("\n");
rows-=2;
}
printf("%s", str);
}
//output
printf("\n");
printf("\n");
printf("Final String = %s\n", str);
return 0;
}
It doesn't display properly. Please help!
Thanks.
#include <stdio.h>
#include <string.h>
int main()
{
char s1[] = "XXXXXXXXXXXXXXXXXXXXX";
const char s2[] = "I love C-Programming!";
const int n = strlen(s1);
const int h = n / 2;
int i;
int j;
puts(s1);
for (i = 0, j = n - 1; i <= h; ++i, --j) {
s1[i] = s2[i];
s1[j] = s2[j];
puts(s1);
}
return 0;
}
Hi this is indeed a very simple program. Actually your teacher want you to write a program like below:-
int main(int argc, char **argv)
{
//data
char str1[] = "I love C-Programming!";
char str2[strlen(str1)];
memset(str2, 'X', sizeof(str2));//Set all the character to X
str2[strlen(str1)-1]=0;//end of string character value of '\0'
//int rows;
//int columns;
int length = strlen(str1);
//int format =5;
int i = 0;
int j = length - 1;
do
{
printf("%s\n", str2);//Print the second string first
str2[i]=str1[i];//copy from first character from str1
str2[j]=str1[j];//copy from last character from str1
//so in each iteration we are coping two characters from str1 to str2
}while(i++ != j-- );//once I and j are equal break the loop
printf("%s", str2);
/*
//process
{
rows = 0;
while (rows <= length)
{
rows++;
}
while (rows > 0)
{
int count = length;
columns = rows - 1;
while (columns > 0)
{
printf("X");
columns--;
count --;
}
if (rows <= length)
{
printf("%.*s", count, str);
}
printf("\n");
rows-=2;
}
printf("%s", str);
}
*/
//output
printf("\n");
printf("\n");
printf("Final String = %s\n", str2);
return 0;
}
It will out put like below:-
XXXXXXXXXXXXXXXXXXXX
IXXXXXXXXXXXXXXXXXXX!
I XXXXXXXXXXXXXXXXXg!
I lXXXXXXXXXXXXXXXng!
I loXXXXXXXXXXXXXing!
I lovXXXXXXXXXXXming!
I loveXXXXXXXXXmming!
I love XXXXXXXamming!
I love CXXXXXramming!
I love C-XXXgramming!
I love C-PXogramming!
I love C-Programming!
Final String = I love C-Programming!

Reversing String in C for loop error

I have an array of strings and am trying to reverse each string in the array to see if that string is a palindrome. I am using a for loop to increment an int i (the index). However after the I call the reverse function, the value of i becomes some really large number and I cant figure out why this is happening.
#include <stdio.h>
#include <string.h>
void revString(char *dest, const char *source);
int main() {
const char *strs[] = {
"racecar",
"radar",
"hello",
"world"
};
int i;
char res[] = "";
for (i = 0; i < strlen(*strs); i++) {
printf("i is %d\n", i);
revString(&res[0], strs[i]); //reversing string
printf("i is now %d\n", i);
//comparing string and reversed string
if (strcmp(res, strs[i]) == 0) {
printf("Is a palindrome");
} else {
printf("Not a palindrome");
}
}
return 0;
}
void revString(char *dest, const char *source) {
printf("%s\n", source);
int len = strlen(source);
printf("%d\n", len);
const char *p;
char s;
for (p = (source + (len - 1)); p >= source; p--) {
s = *p;
*(dest) = s;
dest += 1;
}
*dest = '\0';
}
This is the output showing the value of i before and after the revString function is called.
i is 0
i is now 1667588961
Illegal instruction: 4
There are multiple problems in your code:
You pass a destination array char res[] = ""; that is much too small for the strings you want to reverse. It's size is 1. This causes buffer overflow, resulting in undefined behavior.
Use char res[20]; instead.
You enumerate the array of string with an incorrect upper bound. Use this instead:
for (i = 0; i < sizeof(strs) / sizeof(*strs); i++)
The termination test for the loop in revString() is incorrect too: decrementing p when is equal to source has undefined behavior, although it is unlikely to have an consequences. You can simplify this function this way:
void revString(char *dest, const char *source) {
size_t len = strlen(source);
for (size_t i = 0; i < len; i++) {
dest[i] = source[len - i - 1];
}
dest[len] = '\0';
}
Here is the resulting code:
#include <stdio.h>
#include <string.h>
void revString(char *dest, const char *source) {
size_t len = strlen(source);
for (size_t i = 0; i < len; i++) {
dest[i] = source[len - i - 1];
}
dest[len] = '\0';
}
int main(void) {
const char *strs[] = { "racecar", "radar", "hello", "world" };
char res[20];
for (size_t i = 0; i < sizeof(strs) / sizeof(*strs); i++) {
revString(res, strs[i]);
//comparing string and reversed string
if (strcmp(res, strs[i]) == 0) {
printf("Is a palindrome\n");
} else {
printf("Not a palindrome\n");
}
}
return 0;
}
Here is Final Code with some change
#include <stdio.h>
#include <string.h>
void revString(char* dest, const char* source);
int main(){
const char* strs[] = {
"racecar",
"radar",
"hello",
"world"
};
static int i;
char res[] = "";
int length = (int) sizeof(strs)/sizeof(char*);
for(i = 0; i < length; i++)
{
printf("i is %d\n", i);
revString(&res[0], strs[i]); //reversing string
printf("i is now %d\n", i);
//comparing string and reversed string
if(strcmp(res, strs[i]) == 0){
printf("Is a palindrome");
}else{
printf("Not a palindrome");
}
}
return 0;
}
void revString(char* dest, const char* source){
printf("%s\n", source);
int len = (int) strlen(source);
printf("%d\n", len);
const char* p;
char s;
for(p = (source + (len - 1)); p >= source; p--){
s = *p;
*(dest) = s;
dest += 1;
}
*dest = '\0';
}
Change 1 :-
int i; to static int i; (Reason:- i is local variable you are calling
function so when function call the value of i will remove and after
that it will assign garbage value.)
change 2 :-
strlen(*strs) to length of array (because strlen(*strs) will give the
length of first string)

Reverse string function not working properly

Here is my code. I just can't seem to figure it out. Sometimes i get no output, and sometimes i just get 3 random characters, regardless of how long the entered string is.
#include <stdio.h>
#include <math.h>
#include <string.h>
void reverse(char* array, int numberOfChars);
int main()
{
char string[250];
int length;
printf("Enter a string: ");
gets(string);
printf("How long is the string:");
scanf("%d", &length);
reverse(string, length);
printf("Reversed string is: %s\n"), string;
return 0;
}
void reverse(char *userArray, int numberOfChars)
{
char temp;
int fromEnd = 0, fromStart = 0;
fromEnd = numberOfChars;
while (fromStart < fromEnd)
{
temp = userArray[fromStart];
userArray[fromStart] = userArray[fromEnd];
userArray[fromEnd] = temp;
fromStart++;
fromEnd--;
}
}
I really dread asking these questions here but I can't seem to fix it...
Any help appreciated
Conceptually you need to swap the ends until you are left with a string of length 0 or 1. You don't need to test for the length of the remaining portion of the string after each iteration however, because it can be shown that exactly length/2 swaps will be needed.
void reverse (char *s)
{
size_t length = strlen (s);
for (size_t i = 0; i < length / 2; i++) {
char tmp;
tmp = s[i];
s[i] = s[length - 1 - i];
s[length - 1 - i] = tmp;
}
}
There is no need to complicate things like that, try this:
#include <stdio.h>
int main(void){
char *src = "Michi";
char dest[256];
int i=-1,j=0;
while(src[++i]!='\0');
while(i>=0){
dest[j++] = src[--i];
}
dest[j]='\0';
printf("Your new string is: %s",dest);
return 0;
}
Output:
Your new string is: ihciM
This is probably what you need:
#include<stdio.h>
#include<string.h>
void reverse(char *ptr);
int main(void) {
char src[256] = "Michi";
reverse(src);
printf("Your new string is: %s",src);
return (0);
}
void reverse(char *src){
char dest;
size_t i, j = 0;
i = 0;
j = strlen(src) - 1;
while (i < j) {
dest = src[i];
src[i] = src[j];
src[j] = dest;
i++;
j--;
}
}
don't use gets(),use fgets().To reverse strings,you don't need to pass number of characters,since strings in C are null-terminated.check this very simple function:
#include <stdio.h>
void reverse(char *_Str);
int main(void)
{
char str[] = "Hello Buddy";
reverse(str);
printf("%s\n",str);
return 0;
}
void reverse(char *_Str)
{
char tmp,*_b,*_e;
_b = _e = _Str;
while(*_e) _e++;
_e--;
while(_b < _e)
{
tmp = *_b;
*_b++ = *_e;
*_e-- = tmp;
}
}
Well the very important line you missed is assigning the null character. And do not take the length of your string as an input from the user. use the function some_integer=strlen(stringname); This will return the length of your stringname and assign it to some_integer. Your function to reverse the string should be as
void reverse(char *userarray) // no need of a second argument. Do not trust your users.
{
char temp;
int fromEnd,fromStart = 0; /
fromEnd = strlen(userarray)-1; // here the length of your string is assigned to fromEnd.
while (fromStart < fromEnd)
{
temp = userArray[fromStart];
userArray[fromStart] = userArray[fromEnd];
userArray[fromEnd] = temp;
fromStart++;
fromEnd--;
}
userarray[strlen(userarray)-1]='\0'; //You missed this line (very important)
}
And chek your printf statement.
It should be
printf("Your reversed string is %s \n",string);
not
printf("Your reversed string is %s \n"),string;
I belive this will work. Check it and let me know if it works for you.
Incorrect code. The needed string for the printf() is not in the function. #M Oehm
/// printf("Reversed string is: %s\n"), string;
printf("Reversed string is: %s\n", string);
Also original code can easily wipe out the string terminating null character '\0'. Better to use strlen(string) rather than ask the user for the length.
Likely should use - 1 as commented by #WalterM. It is unclear what values OP is using.
// fromEnd = numberOfChars;
if (numberOfChars <= 0) return;
fromEnd = numberOfChars - 1;
Answers I have seen so far depend on int well addressing all elements of a string. size_t is the right approach as int may be too small.
Many answers would fail on a string such as "".
So here is another contribution without those restrictions.
#include <string.h>
#include <stdio.h>
char *str_revese_inplace(char *s) {
char *left = s;
char *right = s + strlen(s);
while (right > left) {
right--;
char t = *right;
*right = *left;
*left = t;
left++;
}
return s;
}
void stest(const char *s) {
char t[strlen(s) + 1];
// or char t[100];
strcpy(t, s);
printf("'%s' --> '%s'\n", s, str_revese_inplace(t));
}
int main(void) {
stest("123");
stest("12");
stest("1");
stest("");
return 0;
}
Output
'123' --> '321'
'12' --> '21'
'1' --> '1'
'' --> ''

Reverse characters word in array

for exemple i need to invers "Paris" to "siraP"...
My main:
int main(void)
{
char w1[] = "Paris";
ReverseWord(w1);
printf("The new word is: %s",w1);
return0;
}
and my function:
void ReverseWord(char *Str)
{
int counter=0;
for(int i=0; *(Str+i)!='\0'; i++)
counter++;
int length = counter-1;
char temp[length];
for(int j=0; temp[j]=='\0'; j++)
temp[j]=Str[length-j];
}
Now I have my renverse word in temp[].
I need to put it in my pointer *Str.
How can I do it??
Thanks
If you want use temp must then your function like this
void ReverseWord(char *Str)
{
int i,j;
if(str)
{
int length=strlen(Str);
char temp[length+1];
for( j=0; j<length; j++)
temp[j]=Str[length-1-j];
temp[j]='\0';
strcpy(Str,temp);
}
}
Without using temp as follows
void ReverseWord(char *Str)
{
int end= strlen(Str)-1;
int start = 0;
while( start<end )
{
Str[start] ^= Str[end];
Str[end] ^= Str[start];
Str[start]^= Str[end];
++start;
--end;
}
}
void ReverseWord(char *Str)
{
size_t len;
char temp, *end;
len = strlen(Str);
if (len < 2)
return;
end = Str + len - 1;
while (end > Str)
{
temp = *end;
*end-- = *Str;
*Str++ = temp;
}
}
One more option, this time with dangerous malloc(3).
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *rev(char s[]) {
char *buf = (char *)malloc(sizeof(char) * strlen(s));
int i, j;
if(buf != NULL)
for(i = 0, j = strlen(s) - 1; j >= 0; i++, j--)
buf[i] = s[j];
return buf;
}
int main(int argc, char **argv) {
printf("%s\n", rev(argv[1]));
return 0;
}
Run with "foo bar foobar baz" and get zab raboof rab oof back:
~/tmp$ ./a.out "foo bar foobar baz"
zab raboof rab oof
Here I think you can study two algorithms:
C string length calculate: the end of the c string is '\0'
How to reverse a c string in place
And if you need to test the code, you should alloc testing strings in heap or strack. If you write a literal string, you may meet a bus error because of the literal string being saved in text-area which is a read only memory.
And the following is the demo:
#include <stdio.h>
#include <stdlib.h>
void reverse_string(char* str)
{
size_t len;
char tmp, *s;
//Get the length of string, in C the last char of one string is \0
for(s=str;*s;++s) ;
len = s - str;
//Here we use the algorithm for reverse the char inplace.
//We only need a char tmp place for swap each char
s = str + len - 1;
while(s>str){
tmp = *s;
*s = *str;
*str = tmp;
s--;
str++;
}
}
int main()
{
char* a = "abcd";
//Here "abcd" will be saved in READ Only Memory. If you test code, you will get a bus error.
char* b = (char*)calloc(1,10);
strcpy(b,a);
reverse_string(b);
printf("%s\n",b);
a = "abcde";
strcpy(b,a);
reverse_string(b);
printf("%s\n",b);
}
you can do it simply by following code
for(int k=0;k<strlen(temp);k++)
{
Str[k]=temp[k];
}

Printing Array of Strings

I'm parsing a text file:
Hello, this is a text file.
and creating by turning the file into a char[]. Now I want to take the array, iterate through it, and create an array of arrays that splits the file into words:
string[0] = Hello
string[1] = this
string[2] = is
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "TextReader.h"
#include <ctype.h>
void printWord(char *string) {
int i;
for (i = 0; i < strlen(string); i ++)
printf("%c", string[i]);
printf("\n");
}
void getWord(char *string) {
char sentences[5][4];
int i;
int letter_counter = 0;
int word_counter = 0;
for (i = 0; i < strlen(string); i ++) {
// Checks if the character is a letter
if (isalpha(string[i])) {
sentences[word_counter][letter_counter] = string[i];
letter_counter++;
} else {
sentences[word_counter][letter_counter + 1] = '\0';
word_counter++;
letter_counter = 0;
}
}
// This is the code to see what it returns:
i = 0;
for (i; i < 5; i ++) {
int a = 0;
for (a; a < 4; a++) {
printf("%c", sentences[i][a]);
}
printf("\n");
}
}
int main() {
// This just returns the character array. No errors or problems here.
char *string = readFile("test.txt");
getWord(string);
return 0;
}
This is what it returns:
Hell
o
this
is
a) w
I suspect this has something to do with pointers and stuff. I come from a strong Java background so I'm still getting used to C.
With sentences[5][4] you're limiting the number of sentences to 5 and the length of each word to 4. You'll need to make it bigger in order to process more and longer words. Try sentences[10][10]. You're also not checking if your input words aren't longer than what sentences can handle. With bigger inputs this can lead to heap-overflows & acces violations, remember that C does not check your pointers for you!
Of course, if you're going to use this method for bigger files with bigger words you'll need to make it bigger or allocate it dymanically.
sample that do not use strtok:
void getWord(char *string){
char buff[32];
int letter_counter = 0;
int word_counter = 0;
int i=0;
char ch;
while(!isalpha(string[i]))++i;//skip
while(ch=string[i]){
if(isalpha(ch)){
buff[letter_counter++] = ch;
++i;
} else {
buff[letter_counter] = '\0';
printf("string[%d] = %s\n", word_counter++, buff);//copy to dynamic allocate array
letter_counter = 0;
while(string[++i] && !isalpha(string[i]));//skip
}
}
}
use strtok version:
void getWord(const char *string){
char buff[1024];//Unnecessary if possible change
char *p;
int word_counter = 0;
strcpy(buff, string);
for(p=buff;NULL!=(p=strtok(p, " ,."));p=NULL){//delimiter != (not isaplha(ch))
printf("string[%d] = %s\n", word_counter++, p);//copy to dynamic allocate array
}
}

Resources