This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the function to replace string in C?
I am trying to replace a certain character in my string with multiple characters. Here is an example of what I am trying to do.
Say I have the string "aaabaa"
I want to replace all occurrences of the character "b" with 5 "c"s.
So when I am done, "aaabaa" becomes "aaacccccaa"
I have written the following code:
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[20] = "aaabaa";
int i, j;
for (i=0; s[i]!= '\0'; i++)
{
if (s[i] == 'b')
{
for (j=0; j<5; j++)
{
s[i+j] = 'c';
}
}
}
printf("%s\n", s);
}
My output from this function is "aaaccccc". It appears that it just overwrites the last two a's with the c's. Is there any way I would have it so that these last couple of a's dont get overwritten?
If you want to do this in general, without worrying about trying to size your buffers, you should malloc a new string just large enough to hold the result:
/* return a new string with every instance of ch replaced by repl */
char *replace(const char *s, char ch, const char *repl) {
int count = 0;
const char *t;
for(t=s; *t; t++)
count += (*t == ch);
size_t rlen = strlen(repl);
char *res = malloc(strlen(s) + (rlen-1)*count + 1);
char *ptr = res;
for(t=s; *t; t++) {
if(*t == ch) {
memcpy(ptr, repl, rlen);
ptr += rlen;
} else {
*ptr++ = *t;
}
}
*ptr = 0;
return res;
}
Usage:
int main() {
char *s = replace("aaabaa", 'b', "ccccc");
printf("%s\n", s);
free(s);
return 0;
}
Your problem is that you replace the "ccccc" into the original string thus overwriting the remaining characters after what you wish to replace... You should copy into a new string and keep track of two indices - one in each.
And be happy that you declared char s[20] larger than the size of your original string plus the replace values, as otherwise you'd have created a buffer overflow vulnerability in your critical login system :-)
Cheers,
It is necessary to declare a second char array. In below code it just copies content of array s to s1 when condition fails.
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[20] = "aaabaa";
char s1[1024];
int i, j, n;
for (i=0, n = 0; s[i]!= '\0'; i++)
{
if (s[i] == 'b')
{
for (j=0; j<5; j++)
{
s1[n] = 'c';
n++;
}
}
else
{
s1[n] = s[i];
n++;
}
}
s1[n] = '\0';
printf("%s\n", s1);
}
You can use a different variable
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[20] = "aaabaa";
char temp[20]="";
int i, j,k;
k=0;
for (i=0; s[i]!= '\0'; i++)
{
if (s[i] == 'b')
{
for (j=0; j<5; j++)
{
temp[k] = 'c';
k++;
}
}
else
{
temp[k]=s[i];
k++
}
}
printf("%s\n", temp);
}
#include <stdio.h>
#include <string.h>
int main(void)
{
char temp[20];
char s[20] = "aaabaa";
int i, j;
for (i=0; s[i]!= '\0'; i++)
{
if (s[i] == 'b')
{
strcpy(temp,s[i+1]); //copy rest of the string in this case 'aa'
for (j=0; j<5; j++)
{
s[i+j] = 'c';
}
s[i+j] = '\0'; // here we get s = "aaaccccc"
strcat(s,temp); // concat rest of the string (temp = "aa") after job is done.
// to this point s becomes s = "aaacccccaa"
}
}
printf("%s\n", s); //s = "aaacccccaa".
}
here we are using a buffer (temp) to store the rest of the string after our to be replaced character.
after the replacement is done we append it to the end.
so we get s = "aaacccccaa"
Well, if you're going to dynamically allocate the array, you will probably have to allocate a second array. This is necessary because your string s only has a fixed amount of memory allocated.
So, instead of tryig to overwrite the characters in your for loop, I would suggest incrementing a counter that told you how big your new array has to be. Your counter should start off as the size of your original string and increment by 4 each time an instance of 'b' is found. You should then be able to write a function that appropriately copies the modified string over to a new char buffer of size[counter], inserting 5 c's every time a 'b' is being found.
Use this function :
char *replace(char *st, char *orig, char *repl) {
static char buffer[4096];
char *ch;
if (!(ch = strstr(st, orig)))
return st;
strncpy(buffer, st, ch-st);
buffer[ch-st] = 0;
sprintf(buffer+(ch-st), "%s%s", repl, ch+strlen(orig));
return buffer;
}
for your case : printf("%s\n", replace(s,"b","ccccc"));
Related
I'm trying to remove consecutive repeated characters from a given string.
Example:
bssdffFdcrrrtttii ***#
output is supposed to be:
bsdfFdcrti *#
This code doesn't work and only prints the first char (b), I want to learn about my mistake.
when I'm doing a printf test, it works but not for spaces.
I think the problem might be with the new char array.
void Ex6() {
char* string[80];
scanf("%s", &string);
puts(removeDup(string));
}
char* removeDup(char *string) {
int i, c = 0;
char* newString[80];
for (i = 0; i < strlen(string); i++) {
if (string[i] != string[i + 1]) {
newString[c++] = string[i];
}
}
return newString;
}
There are several problems with your program:
The declaration of newString should be char newString[80], i.e., an array of characters and not an array of pointers-to-characters, and likewise for the declaration in Ex6.
The call to scanf should then be scanf("%s", string), since string is already the address of an array of characters, but...
Use fgets to read a string from the user to ensure that you read whitespace, if it's important, and that the buffer is not exceeded.
newString is allocated on the stack and so should not be returned to the caller. It is better to do a char *newString = strdup(string), or, slightly less sloppy, char *newString = malloc(strlen(string)+1), which will call malloc for a block of memory sufficient to hold the original string, and thus the version without duplicates -- the comments rightly point out that this could be optimized. In principle, the caller, i.e., Ex6, must free the returned pointer to avoid a memory leak but it hardly matters in such a short program.
The result needs a null terminator: newString[c] = '\0'.
Otherwise, the removeDup function seems to work correctly.
So, putting all of that together:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* removeDup(const char *string)
{
size_t i, c = 0;
size_t string_len = strlen(string);
char *newString = malloc(string_len + 1);
for (i = 0; i < string_len; i++) {
if (string[i] != string[i + 1]) {
newString[c++] = string[i];
}
}
newString[c] = '\0';
return newString;
}
#define MAX_STRING_LEN 80
void Ex6() {
char string[MAX_STRING_LEN];
char* result;
if (fgets(string, MAX_STRING_LEN, stdin) != NULL) {
result = removeDup(string);
printf("%s", result);
free(result);
}
}
Finally, I agree with #tadman's comment. Since the input string must anyway be traversed to calculate the length, we may as well optimize the size of the result string:
char* removeDup(const char *string)
{
size_t i, c = 0;
char *newString;
for (i = 0; string[i] != '\0'; i++)
c += (string[i] != string[i + 1]);
newString = malloc(c + 1);
for (i = c = 0; string[i] != '\0'; i++) {
if (string[i] != string[i + 1]) {
newString[c++] = string[i];
}
}
newString[c] = '\0';
return newString;
}
There are quite a few issues in your program. It wouldn't even compile let alone run. Also, the most problematic issue is that you are returning a pointer to a local variable from a function that ceases its scope upon completion. A simplified version of your program is as follows:
void Ex6()
{
char string[80];
scanf("%s", string);
int i, c = 0;
char newString[80];
for (i = 0; i < strlen(string); i++) {
if (string[i] != string[i + 1]) {
newString[c++] = string[i];
}
}
newString[c] = '\0';
puts(newString);
}
You can do it with O(n) time and O(1) space, by modifying existing string:
#include <stdio.h>
char* removeDup(char* input) {
char* newTail = input, *oldTail = input;
while (*oldTail) {
if (*newTail == *oldTail) {
++oldTail;
} else {
*++newTail = *oldTail++;
}
}
return newTail;
}
int main() {
char string[] = "bssdffFdcrrrtttii ***#";
char* newEnd = removeDup(string);
char* tmp = string;
while (tmp != newEnd) {
printf("%c", *tmp++);
}
//Print the last char if string had any duplicates
if(*tmp) {
printf("%c", *tmp++);
}
return 0;
}
I was asked this question in an interview but I was not able to answer.
Question was: To remove a specific characters from a given string by traversing string only once.
e.g. Given string is: "aaabbcdabe"
remove all 'b'
output: ""aaacdae"
I made this logic but it was traversing string more than once:
for(int i=0; str[i]!='\0'; i++)
{
if(str[i] == 'b')
{
for(j=i; str[j]!='\0'; j++)
{
str[j] = str[j+1];
}
}
}
With this logic, string is getting traversed more than once, once in outer for loop and many times in shifting operation.
Is there any other way to do this?
Keep a pointer to the read location and a pointer to the write location. Each time the read-pointer is advanced, only write through the write-pointer if the character is not being removed. Advance the write-pointer only when a character is written:
#include <stdio.h>
void remove_chars(char *str, const char c);
int main(void)
{
char test_str[] = "aaabbcdabe";
puts(test_str);
remove_chars(test_str, 'b');
puts(test_str);
return 0;
}
void remove_chars(char *str, const char c)
{
char *write_ptr = str;
while (*str) {
if (*str != c) {
*write_ptr = *str;
++write_ptr;
}
++str;
}
*write_ptr = '\0';
}
Program output:
λ> ./a.out
aaabbcdabe
aaacdae
This should work. It's pretty short and sweet.
int newLen = 0;
int oldLen = strlen(str);
for(int i=0; i<oldLen; i++){
if(str[i] != 'b'){
str[newLen] = str[i];
newLen++;
}
}
str[newLen] = '\0';
I am trying to have this output:
Comparing results of concat and strcat ...
strcmp("Plain old stringTroy", "Plain old stringTroy") says: 0
The strcmp returns 0 if the two string arguments are identical. If the result is 0, then the concat behaves exactly like the library function strcat.
this is what I have for concat method.
#define MAXSIZE 32
void concat(char dest[], char src[])
{
int i=length(src);
int j=0;
for(j; j<src[j] !='\0'; j++) {
dest[i+j] = src[j];
}
dest[i+j] = '\0';
}
length method is:
int length(char str[])
{
// Add code here to return the length of the
// string str without using the strlen function
// Do not count the null character '\0'
// in computing the length of the string
int len=0;
int i;
for(i=0;i<str[i];i++) {
len++;
}
return len;
}
This is my main
int main()
{
// Variable declarations for all parts
char str2[] = "Troy";
char str4[] = "Plain old string";
char str6[MAXSIZE];
// Part 6
printf("\n----- Part 6 -----\n");
// Make a copy of the destination string first, to be reused later
strcpy(str6, str4);
concat(str4, str2);
strcat(str6, str2);
printf("Comparing results of concat and strcat ...\n");
printf("strcmp(\"%s\", \"%s\") says: %d\n",
str4, str6, strcmp(str4, str6)
);
return 0;
}
This is my output when I run it:
----- Part 6 -----
Comparing results of concat and strcat ...
strcmp("PlaiTroy", "Plain old stringTroy") says: -1
The first string is not the same as the second string which is why I am getting a -1. My problem is in my concat method but I can't seem to understand why it won't execute well. Is it because of the spaces? Is 0 and '\0' not executing well?
There are multiple problems in your code:
The loop test in the length function is incorrect: instead of i < str[i], it should be:
for (i = 0; str[i] != '\0'; i++)
the same problem in the concat function. Change the loop to:
for (j = 0; src[j] != '\0'; j++) {
also in the concat function, i should be the length of dst, not that of src. You might use len instead of i for this variable.
The array str4 in function main does not have any space available at the end for concat to append anything. Define it with a larger size this way:
char str4[MAXSIZE] = "Plain old string";
Here is the corrected version:
#include <stdio.h>
#include <string.h>
#define MAXSIZE 32
void concat(char dest[], char src[]) {
int len = length(dest);
int j;
for (j = 0; src[j] != '\0'; j++) {
dest[len + j] = src[j];
}
dest[len + j] = '\0';
}
int length(char str[]) {
int len = 0;
int i;
for (i = 0; i < str[i]; i++) {
len++;
}
return len;
}
int main(void) {
// Variable declarations for all parts
char str2[MAXSIZE] = "Troy";
char str4[MAXSIZE] = "Plain old string";
char str6[MAXSIZE];
// Part 6
printf("\n----- Part 6 -----\n");
// Make a copy of the destination string first, to be reused later
strcpy(str6, str4);
concat(str4, str2);
strcat(str6, str2);
printf("Comparing results of concat and strcat ...\n");
printf("strcmp(\"%s\", \"%s\") says: %d\n",
str4, str6, strcmp(str4, str6));
return 0;
}
You have several problems in both functions:
concat
for(j; j<src[j] !='\0'; j++) {
What is the for exit condition here?, src[j] != '\0' is enough.
dest[i+j] = src[j];
Here you add data with an offset of i, but I is the length of src, not dst.
So the corrected function could be:
void concat(char dest[], char src[])
{
/* descriptive variable name */
int len_dst = length(dst);
int j=0;
/* clear exit condition */
for(; src[j] != '\0'; j++) {
dest[len_dst+j] = src[j];
}
dest[len_dst+j] = '\0';
}
length
for(i=0;i<str[i];i++) {
Same remark, what is this exit condition? src[i] != '\0' is enough
So the corrected function could be:
int length(char str[])
{
int len=0;
int i;
/* clear exit condition */
for ( i=0; str[i] != '\0'; i++) {
len++;
}
return len;
}
main
And warning in main function:
char str4[] = "Plain old string";
concat(str4, str2); /* <- erases what is after str4 */
You do not have enough space to store result. Write something like:
char str2[] = "Troy";
char str4[MAXSIZE] = "Plain old string"; /* <-- reserve spaces after str4*/
/* ... */
concat(str4, str2);
What I'm trying to achieve -
Input: (String literal assumed.) This is a string
Output: string a is This
My naive solution:
Copy the string literal to an char array.
Current contents of the char array str[sizeofstring] : This is a string
Reverse the array word by word and store it in another array.
char reverse[sizeofstring]: sihT si a gnirts
Traverse array reverse from the last to the 0th position. Store it in char array solution.
char solution[sizeofstring]: string a is This
strcpy(pointertoachar, solution). - Because the function needs to return a pointer to char.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverse(char *input) {
int n = strlen(input);
char str[n];
char reverse[n];
char solution[n];
char *solutionp = malloc(sizeof(char) * n);
strcpy(str, input);
int last = 0;
int i = 0;
int q = 0;
while (str[i] != '\0') {
if (str[i] == ' ') {
printf("i : %d\n", i);
printf("LAST:%d\n", last);
for (int t = (i - 1); t >= last; t--) {
reverse[q] = str[t];
q++;
}
last = i + 1;
reverse[q] = ' ';
q++;
}
i++;
}
// for the last word.
for (int cc = i - 1; cc >= last; cc--) {
reverse[q] = str[cc];
q++;
}
// Traversing from the last index to the first.
int ii;
int bb = 0;
for (ii = n - 1; ii >= 0; ii--) {
solution[bb] = reverse[ii];
bb++;
}
// This prints the right output.
// printf("%s\n",solution);
// Copying from a char array to pointer pointing to a char array.
strcpy(solutionp, solution);
return solutionp;
}
int main() {
char *str = "This is a string";
char *answer;
answer = reverse(str);
printf("%s\n", answer);
printf("\n");
return 0;
}
The problem:
Steps 1 to 3 are working as intended. For debugging purpose, I tried printing the output of the array which contains the solution and it worked, but when I copy it to char array pointed by a pointer using strcpy and return the pointer, it prints garbage values along with partially right output.
OUTPUT:
string a is This??Z??
There seems to be some problem in step 4. What am I doing wrong?
The major problem in your code is you allocate your temporary buffers one byte too short. You must make enough room for the final '\0' byte at the end of the strings.
You can simplify the code by using an auxiliary function to copy a block in reverse order:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverse_block(char *dest, const char *src, int len) {
for (int i = 0; i < len; i++) {
dest[i] = src[len - i - 1];
}
dest[len] = '\0';
return dest;
}
char *reverse_words(const char *string) {
int i, last;
int len = strlen(string);
char temp[len + 1];
for (i = last = 0; i < len; i++) {
if (string[i] == ' ') {
// copy the word in reverse
reverse_block(temp + last, string + last, i - last);
temp[i] = ' ';
last = i + 1;
}
}
// copy the last word in reverse
reverse_block(temp + last, string + last, len - last);
// allocate an array, reverse the temp array into it and return it.
return reverse_block(malloc(len + 1), temp, len);
}
int main(void) {
const char *string = "This is a string";
printf("%s\n", string);
char *solution = reverse_words(string);
printf("%s\n", solution);
free(solution);
return 0;
}
Now you can improve the code further by implementing a function that reverses a block in place. With this, you no longer need a temporary buffer, you can work on the string copy directly and it simplifies the code.
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
}
}