Related
So what i have is a string(str) that i get from fgets(str, x, stdin);.
If i write for example "Hello World" i want to be able to add a character infront of each word in the string.
To get this "Hello? World?" as an example. I think i've made it alot harder for myself by trying to solve it this way:
add(char *s, char o, char c){
int i, j = 0;
for (i = 0; s[i] != '\0'; i++) {
if (s[i] != o) {
s[j] = s[i];
}
else {
s[j] = c;
}
j++;
}
}
add(str, ' ','?');
printf("\n%s", str);
This will read out "Hello?World" without the spaces. Now the only way i see this working is if i move everything after the first "?" one to the right while also making the positon of the "W" to a space and a "?" at the end. But for much longer strings i can't see myself doing that.
You can't safely extend a string with more characters without insuring the buffer that holds the string is big enough. So let's devise a solution that counts how many additional characters are needed, allocate a buffer big enough to hold a string of that length, then do the copy loop. Then return the new string back to the caller.
char* add(const char* s, char o, char c)
{
size_t len = strlen(s);
const char* str = s;
char* result = NULL;
char* newstring = NULL;
// count how many characters are needed for the new string
while (*str)
{
len += (*str== o) ? 2 : 1;
str++;
}
// allocate a result buffer big enough to hold the new string
result = malloc(len + 1); // +1 for null char
// now copy the string and insert the "c" parameter whenever "o" is seen
newstring = result;
str = s;
while (*str)
{
*newstring++ = *str;
if (*str == o)
{
*newstring++ = c;
}
str++;
}
*newString = '\0';
return result;
}
Then your code to invoke is as follows:
char* newstring g= add(str, ' ','?');
printf("\n%s", newstring);
free(newstring);
#include <stdio.h>
#include <string.h>
int main(void) {
char text[] = "Hello World";
for(char* word = strtok(text, " .,?!"); word; word = strtok(NULL, " .,?!"))
printf("%s? ", word);
return 0;
}
Example Output
Success #stdin #stdout 0s 4228KB
Hello? World?
IDEOne Link
Knowing the amount of storage available when you reach a position where the new character will be inserted, you can check whether the new character will fit in the available storage, move from the current character through end-of-string to the right by one and insert the new character, e.g.
#include <stdio.h>
#include <string.h>
#define MAXC 1024
char *add (char *s, const char find, const char replace)
{
char *p = s; /* pointer to string */
while (*p) { /* for each char */
if (*p == find) {
size_t remain = strlen (p); /* get remaining length */
if ((p - s + remain < MAXC - 1)) { /* if space remains for char */
memmove (p + 1, p, remain + 1); /* move chars to right by 1 */
*p++ = replace; /* replace char, advance ptr */
}
else { /* warn if string full */
fputs ("error: replacement will exceed storage.\n", stderr);
break;
}
}
p++; /* advance to next char */
}
return s; /* return pointer to beginning of string */
}
...
(note: the string must be mutable, not a string-literal, and have additional storage for the inserted character. If you need to pass a string-literal or you have no additional storage in the current string, make a copy as shown by #Selbie in his answer)
Putting together a short example with a 1024-char buffer for storage, you can do something like:
#include <stdio.h>
#include <string.h>
#define MAXC 1024
char *add (char *s, const char find, const char replace)
{
char *p = s; /* pointer to string */
while (*p) { /* for each char */
if (*p == find) {
size_t remain = strlen (p); /* get remaining length */
if ((p - s + remain < MAXC - 1)) { /* if space remains for char */
memmove (p + 1, p, remain + 1); /* move chars to right by 1 */
*p++ = replace; /* replace char, advance ptr */
}
else { /* warn if string full */
fputs ("error: replacement will exceed storage.\n", stderr);
break;
}
}
p++; /* advance to next char */
}
return s; /* return pointer to beginning of string */
}
int main (void) {
char buf[MAXC];
if (!fgets (buf, MAXC, stdin))
return 1;
buf[strcspn(buf, "\n")] = 0;
puts (add (buf, ' ', '?'));
}
Example Use/Output
$ ./bin/str_replace_c
Hello World?
Hello? World?
Look things over and let me know if you have questions.
Just for fun, here's my implementation. It modifies the string in-place and in O(n) time. It assumes that the char-buffer is large enough to hold the additional characters, so it's up to the calling code to ensure that.
#include <stdio.h>
void add(char *s, char o, char c)
{
int num_words = 0;
char * p = s;
while(*p) if (*p++ == o) num_words++;
char * readFrom = p;
char * writeTo = p+num_words;
char * nulByte = writeTo;
// Insert c-chars, iterating backwards to avoid overwriting chars we have yet to read
while(readFrom >= s)
{
*writeTo = *readFrom;
if (*writeTo == o)
{
--writeTo;
*writeTo = c;
}
writeTo--;
readFrom--;
}
// If our string doesn't end in a 'c' char, append one
if ((nulByte > s)&&(*(nulByte-1) != c))
{
*nulByte++ = c;
*nulByte = '\0';
}
}
int main(int argc, char ** argv)
{
char test_string[1000] = "Hello World";
add(test_string, ' ','?');
printf("%s\n", test_string);
return 0;
}
The program's output is:
$ ./a.out
Hello? World?
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);
}
Replacing a substring with another is easy if both substrings have the same length:
locate the position of the substring with strstr
if it is present, use memcpy to overwrite it with the new substring.
assigning the pointer with *strstr(m, "on") = "in"; is incorrect and should generate a compiler warning. You would avoid such mistakes with gcc -Wall -Werror.
note however that you cannot modify a string literal, you need to define an initialized array of 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;
}
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.
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);
}
I have the following string abcd1234 and I want to find a way to break this string into two different strings, abcd and 1234. I have tried the following code:
char buf[100],*str1,*str2;
int x;
fgets(buf,sizeof(buf),stdin);
str1=strtok(buf,"0123456789 \t\n");
str2=strtok(NULL," \n\t\0");
puts(str1);
puts(str2);
x=atoi(str2);
printf("x=%d", x);
but output is abcd 234. And if I try it with one letter and one number, e.g a2 I take only e on output and x is 0.
As per the man page of strtok()
Each call to strtok() returns a pointer to a null-terminated string containing the next token. This string does not include the delimiting byte. [...]
So, while using "0123456789 \t\n" as the delimiter for the first time, 1 will be treated as the actual delimiter and will not be considered in the subsequent parsing.
You may want to use strcspn() and/or strpbrk() to find out the index for the required sub-strings and parse accordingly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
size_t extract(const char **sp, char *out, int (*test)(int ch));
int main(void){
char buf[100], str1[100], str2[100];
int x;
const char *p = buf;
//size_t len;
fgets(buf, sizeof(buf), stdin);
while(*p){
if(isalpha((unsigned char)*p)){
extract(&p, str1, isalpha);
puts(str1);
} else if(isdigit((unsigned char)*p)){
extract(&p, str2, isdigit);
x = atoi(str2);
printf("%s, x=%d\n", str2, x);
} else {
++p;//skip one char
}
}
return 0;
}
size_t extract(const char **sp, char *out, int (*test)(int ch)){
const char *p = *sp;
while(*p && test((unsigned char)*p)){
*out++ = *p++;
}
*out = '\0';
size_t len = p - *sp;
*sp = p;
return len;
}
Try below code.Hope this will help you.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
char string[]="abcd1234";
char digitStr[10];
char charStr[10];
int i,j = 0,k = 0;
for(i=0;string[i];i++)
{
if(isdigit(string[i]))
{
charStr[j++]=string[i];
}
else
{
digitStr[k++]=string[i];
}
}
charStr[j] = '\0';
digitStr[k] = '\0';
printf("%s %s\n",digitStr,charStr);
}
I realize I'm very late on this one, but this is for if anyone has a similar case
Assuming all input strings are like your example, this method will work.
char buf[100];
fgets(buf, sizeof(buf), stdin);
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
int x = atoi(strpbrk(buf, "0123456789"));
char letters[number - buf + 1];
memcpy(letters, sizeof(letters) - 1, buf);
letters[sizeof(letters) - 1] = '\0';
//letters is the word
//x is the number as an int, not a string
• Note the if statement after the fgets. This checks that the newline character was read by fgets, and turns it into a NUL character. (essentially truncating the string).
• As for strpbrk(), that's just a function that returns a pointer to the first occurence of any character in the second string inside the first string. I use it here to find the start of the digit sequence.
• I would also drop the atoi() for strtol() for safety.
• The letters[] array size is the return of strpbrk() (the address of the first number), minus the start of the array (giving the length of the letter string in bytes), plus one for the NUL character I add later.
I'm quite new to C programming, used to only use C++ with the String class, but I'm wondering how I would go about doing a recursive replacement of a string with another string.
My code is like this, but it doesn't seem to work correctly and I cannot quite pin down where it fails. It works fine on one replacement, but more than one and it fails.
#include <stdio.h>
#include <string.h>
char *replace_str(char *str, char *orig, char *rep)
{
int current_index = 0;
static char buffer[10000];
if (!strstr(str, orig)) // Is 'orig' even in 'str'?
{
return str;
}
while (1)
{
char *p;
if (!(p = strstr(str + current_index, orig))) // Is 'orig' even in 'str'?
{
return buffer;
}
strncpy(buffer, str, p-str); // Copy characters from 'str' start to 'orig' st$
buffer[p-str] = '\0';
sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));
printf("%d -> %s\n", current_index, buffer);
current_index = (p - str) + strlen(rep);
str = buffer;
}
return buffer;
}
int main(void)
{
puts(replace_str("hello world world", "world", "world2"));
return 0;
}
With this example, it prints this:
0 -> hello world2 world
12 -> hello world2 world22
hello world2 world22
It could be not the best implementation, but here you find a stringReplace function that does the task.
About your code. First, it is better the caller supplies its dest buffer instead of having a static buffer into the function. Then, you do not check for buffer overflow.
Your
strncpy(buffer, str, p-str); // Copy characters from 'str' start to 'orig' st$
will copy from A to A except in the first iteration. This is not good, the buffer shouldn't overlap. Use memmove instead.
But the whole idea is not clean since you update the same buffer you use as source to catch other occurrences.
At some point you overwrite the input (when str and buffer points to the same thing) loosing information since your replacing word is longer than the original to be replaced so you do not preserve the "original next character". (If you try with "work" instead of "world2", it should work)...
So your current_index should index the original string str (and you'll never do str = buffer), and you will append to your internal buffer the part you need (up to an occurence of "world" if found then append "world2", update current_index by the length of "world" and go on).
I would do (trying to keep you original idea, more or less)
#include <stdio.h>
#include <string.h>
char *replace_str(char *str, const char *orig, const char *rep)
{
size_t buf_index = 0;
static char buffer[10000];
if (!strstr(str, orig)) // Is 'orig' even in 'str'?
{
return str;
}
buffer[0] = 0;
for(;;)
{
char *p;
if (!(p = strstr(str, orig)))
{
strcpy(buffer + buf_index, str);
return buffer;
}
strncpy(buffer + buf_index, str, p - str);
strcpy(buffer + buf_index + (p - str), rep);
buf_index += (p-str) + strlen(rep);
str = p + strlen(orig);
}
return buffer;
}
int main(void)
{
puts(replace_str("hello world world world", "wor", "world2"));
return 0;
}
The problem is str = buffer; . You are effectively changing the source pointer, and that screwing up your code.
Use the below code before the start of the while loop
char bk[100]
strcpy(bk,str);
and replace all str occurrences in the while loop with bk.It will work.
use this recursive function rplcStr (), it's coded as simple replace c++.
string rplcStr(string x, string y, string z){
// Done by Raafat Maurice in 29 Feb 2012
// this function will replace all string (y) found in string (x) by the string (z).
if (x.find(y.c_str(),0) != -1 ) {
return (rplcStr (x.substr(0, x.find(y.c_str(),0) ) + z + x.substr( x.find(y.c_str(),0) + y.size() ) ,y,z));
}
else {
return (x);
}
}
I'm stuck at yet another C problem. How can I concatenate two strings with the second string being inserted before the first string?
This is what I came up with. Unfortunately I'm stuck at all these pointer to chars, char arrays et cetera.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[] )
{
char* output;
int i;
for(i = 9; i > 0; i--)
{
unsigned int value = (unsigned int)i;
char buffer[20];
sprintf(buffer, "%u", value);
// strcat(ouput, buffer); // append before the string.
// first loop: 9
// second loop: 89
// third loop: 789
}
printf("%s", output);
}
How must I correct my code to make it work? I guess I have to somehow set the output variable to empty. When do I need fixed widths for the char array or the pointer? 20 was just a random guess from me.
I'm very confused, as your posted code has absolutely nothing to do with the problem you state. (Well, they both use strings, but that's about it)
char* src = "Hello, ";
char* dest = "World!";
char* temp;
temp = malloc(strlen(src) +strlen(dest) + 1);
strcpy(temp, src);
strcat(temp, dest);
dest = temp;
Unless dest is a fixed buffer of adequate size for the combined string. If so, then replace the last line with:
strcpy(dest, temp);
free(temp);
Now, if you want to specifically build the list of digits backwards, let's try a different tack:
char buffer[10];
buffer[9] = '\0'; // null terminate our string.
char* output;
int i;
for(i = 9; i > 0; i--)
{
// this is a fast way of saying, sprintf("%u", i);
// works only for single digits
char d = (char)('0' + i);
buffer[i-1] = d;
output = &buffer[i-1];
printf("%s", output);
}
Usually, you should just avoid the situation to start with. The most obvious solution for your example would be to simply count upward to start with. When that's not suitable, a recursive solution to reverse the order in which the string is built can still allow you to generate the string from beginning to end:
int build_string(int value, char *string) {
char temp[10];
if (value > -1)
build_string(value-1, string);
sprintf(temp, "%d", value); // use snprintf if available.
strcat(string, temp);
return string;
}
int main() {
char result[20] = {0};
build_string(9, result);
printf("%s", result);
return 0;
}
You can append the integer at the end of the string as:
int i;
char buffer[20];
for(i = 0; i < 10; i++) {
sprintf(buffer+i, "%u", i);
}
printf("%s", buffer); // prints 0123456789
For your stated problem (insert one string in front of another), this code will do the job - but has no error checking. It assumes there is enough space in the target buffer for the existing string and the new prefix:
/* Insert string t in front of string s in string s */
char *strinsert(char *s, const char *t)
{
char *p = s + strlen(s);
char *q = p + strlen(t);
char *r = s;
while (p >= s)
*q-- = *p--;
while (*t)
*s++ = *t++;
return(r);
}
What it does is copy the existing string up by the correct number of places so that there is space for the new string at the beginning.
Assuming that the destination buffer is big enough and that the source and destination do not overlap:
// not sure what order to put the params - the usual C way is destination
// followed by source, but it's also potentially confusing that the result of
// prepend(foo,bar) is "<bar><foo>".
char* prepend(char *restrict dest, const char *restrict src) {
size_t len = strlen(src);
memmove(dest + len, dest, strlen(dest));
return memcpy(dest, src, len);
}
If the buffers may overlap (for example, if src is the second half of dest), this approach doesn't work.
If the destination buffer is not big enough, then someone has to allocate new memory for the result, in which case the question of which is the "source" and which the "destination" disappears - they're both "source" and neither is "destination".