I need to read a file and look for a word and replace with a new word but it's not working as it should:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE * f = fopen("text" , "rb" );
if(f == NULL ){
perror("error ");
return 1;
}
char chain[100];
while(!feof(f)){
fgets(chain, 100 , f);
}
printf("%s", chain);
fclose(f);
printf("\n \n ;D \n");
return 0;
}
And this is how I replace the old word:
char str[] ="This is a hiall samplesss friends string";
char * pch;
pch = strstr (str,"hiall");
strncpy (pch,"sam",5);
puts (str);
thanks
That strncpy is copying 5 chars from "sam" into pch. Note however that "sam" has only 3 characters, so it is copying the three characters plus the \0 terminator. That's why it is "deleting" the rest of the string: it is adding a terminator right after "sam", so you are getting This is a sam in the output.
If you strncpy only 3 characters, you'll get this:
This is a samll samplesss friends string
If what you want is something like find-and-replace (i.e. replacing "hiall" with "sam" and getting This is a sam samplesss friends string), you need to move the rest of the string backwards. A simple strncpy won't work because the destination memory overlaps with the target. For this, you can either use memmove, or use an auxiliary buffer:
char str[] = "This is a hiall samplesss friends string";
char* pch;
char* old_word = "hiall";
char* new_word = "sam";
size_t len_old = strlen(old_word);
size_t len_new = strlen(new_word);
pch = strstr(str, old_word);
assert(len_new <= len_old);
if (pch) {
char* rest = pch + len_old;
size_t len_rest = strlen(rest);
char* aux = malloc(len_rest + 1);
strncpy(aux, rest, len_rest + 1);
strncpy(pch, new_word, len_new);
strncpy(pch + len_new, aux, len_rest + 1);
free(aux);
puts(str);
}
Note that this will only work if new_word is the same size or shorter than old_word. If new_word is longer, you won't be able to edit in-place (in the string str itself), unless the original string has extra memory for it (e.g. if you declared it with str[1000] to guarantee you can increase its size enough — then the code above would work). The safest approach if you can't plan ahead what size new_word is going to be would be to allocate a new string:
char str[] ="This is a hiall samplesss friends string";
char* pch;
char* old_word = "hiall";
char* new_word = "sam";
pch = strstr(str, old_word);
size_t len_str = strlen(str);
size_t len_new = strlen(new_word);
size_t len_old = strlen(old_word);
if (pch) {
char* new_str = malloc(len_str - len_old + len_new + 1);
ptrdiff_t pos_word = pch - str;
strncpy(new_str, str, pos_word);
strncpy(new_str + pos_word, new_word, len_new);
strncpy(new_str + pos_word + len_new, pch + len_old,
len_str - pos_word - len_old + 1);
puts(new_str);
}
(Edit: addressed issues pointed out by David Bowling in the comments.)
Related
I'm basically just taking a string and appending / concatting with another string. The first run through produces the desired results, but the 2nd, 3rd and so on results seem to be doubling the src string. Combining things with jQuery is super simple, not sure whats going on here in C. Should I be using memset? or calloc?
#include <stdio.h>
#include <string.h>
int main(void) {
const char* name = "Michelle";
char *ptr;
char dest[30];
char yourName[30];
char dots[] = "..";
int i;
for (i=0;i<4;i++)
{
if (strlen(name) > 5)
{
sprintf(yourName, "%s", name);
strncpy(dest, yourName, 3);
ptr = strcat(dest, dots);
sprintf(yourName, "%s", ptr);
printf("%s\n", yourName);
}
}
return 0;
}
I'm expecting to see results such as
Michelle becomes Mic..
This works, however if my name structure has 4 names and they were all Michelle the results are...
Mic..
Mic....
Mic......
Mic........
You didn't heed the following warning:
The strncpy() function is similar, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
Replace
ptr = strncpy(dest, yourName, 3);
strcat(dest, dots);
sprintf(yourName, "%s", ptr);
with
ptr = strncpy(dest, yourName, 3);
dest[3] = '\0';
strcat(dest, dots);
sprintf(yourName, "%s", ptr);
or just
yourName[3] = '.';
yourName[4] = '.';
yourName[5] = '\0';
I have not been able to find any information with a web-search. Where should I be looking?
char myString[256]; // Input string
char dest[256]; // Destination string
strncpy(dest, myString, 10);
dest[10] = 0; // null terminate destination
char source[] = "abcdefthijklmn";
char target[100];
strncpy(target, source, 10);
target[10] = '\0'; // IMPORTANT!
Adding to the above answers:
char* someString = "your string goes here";
int main()
{
int n = 10;
printf("(%.*s)\n", n, someString);
return 0;
}
There are many different ways to achieve your goal:
You can use snprintf (safest):
char source[] = "abcdefthijklmn";
char target[100];
snprintf(target, sizeof target, "%.10s", source);
You can use strncat if you know the destination has at least 11 elements:
char source[] = "abcdefthijklmn";
char target[100];
*target = '\0';
strncat(target, source, 10);
You can use strlen and memcpy (same assumption about the size of destination):
char source[] = "abcdefthijklmn";
char target[100];
size_t len = strlen(source);
if (len > 10)
len = 10;
memcpy(target, source, len);
target[len] = '\0';
You can use a loop (same assumption about the size of destination):
char source[] = "abcdefthijklmn";
char target[100];
size_t i;
for (i = 0; i < 10; i++) {
target[i] = source[i];
}
target[i] = '\0';
You could but should not use strncpy()
If you're looking for a good source, here's an example of an online man page you can use:
http://linux.die.net/man/3/strncpy
Important to note: you could also use memcpy instead of strncpy, but it requires you to add your own null-terminating byte.
Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
Hence, memcpy and strncpy work almost the same here, and memcpy is more efficient and less prone to error.
I got it to work like this.
# include <stdio.h>
# include <string.h>
//Strings. String lenght terminator.
//KHO2016.no1. mingw (TDM-GCC-32) . c-ansi .
int main ()
{
//declare
char src_str[20],dst_str[10];
//valuate
printf ("Enter a sentance of 20 letters\n");
gets (src_str);
strcpy (dst_str,src_str);
//calculate
dst_str [10] ='\0'; // from the "www.stack overflow"
printf ("%s",dst_str);
printf ("\n");
//terminate
return 0;
}
You can also use sprintf with .10 precision format:
#include <stdio.h>
#include <string.h>
int main(void)
{
char source[] = "abcdefghijklmnopqrstuvwxyz";
char dest[11];
memset(dest, '\0', sizeof(dest));
sprintf(dest, "%.10s", source);
printf("%s", dest); // abcdefghij
return 0;
}
Here is my code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char f[] = "First";
char s[] = "Second";
char *tmp = malloc(strlen(f) + strlen(s) + 2);
strcpy(tmp, f);
strcpy(tmp, s);
printf("%s", tmp);
free(tmp);
return 0;
}
I'm trying to concatenate f and s. The problem is that tmp contains only "Second" as a array.
What I miss here
strcpy copies the string to the beginning of the destination, you want strcat instead.
The second strcpy overwrites the previous one. Both copy its content to the tmp pointer (at the start of it). You should use tmp+strlen(f).
Or even better use strcat.
And even better use more secure methods like: strncpy, strncat, etc..
If you insist on using strcpy, your code should be slightly modified:
int main() {
const char *f = "First";
const char *s = "Second";
char *tmp = malloc(strlen(f) + strlen(s) + 1);
strcpy(tmp, f);
strcpy(tmp+strlen(f), s);
printf("%s", tmp);
free(tmp);
return 0;
}
You should consider using strncpy instead of strcpy for safety reasons. Also, strcat is a more conventional function for concatenating C string.
EDIT Here is an example of using strncpy instead of strcpy
#define MAX 1024
int main() {
const char *f = "First";
const char *s = "Second";
size_t len_f = min(strlen(f), MAX);
size_t len_s = min(strlen(s), MAX);
size_t len_total = len_f + len_s;
char *tmp = malloc(len_total + 1);
strncpy(tmp, f, len_f);
strncpy(tmp+len_f, s, len_s);
tmp[len_total] = '\0';
printf("%s", tmp);
free(tmp);
return 0;
}
You may want to use strcat instead of your second strcpy call, like this:
strcpy(tmp, f);
strcat(tmp, s);
Note also that allocating strlen(f) + strlen(s) + 1 bytes for tmp is sufficient no need to allocate strlen(f) + strlen(s) + 2 bytes. After concatenation, you'll get only one string, so only one null character is required.
using strcat() instead, which means append a string accroding to the MSDN doc.strcpy() just means copy a string. If you don't want to use strcat(), you should point out the position by using strncpy() or strcpy_s(). Please refer to the document.
The problem is that you copy the second string in place of the first one (the first parameter of strcpy() is where to copy the string) and this effectively overwrites the first string. Here's an idea of what you need:
size_t firstLen = strlen( f );
size_t secondLen = strlen( s );
char *tmp = malloc(firstLen + secondLen + 1);
strcpy(tmp, f);
strcpy(tmp + firstLen, s);
This can be achieved by using strcat(), although that would lead to an extra scan along the copied string.
Here is the correct idiomatic safe way to do what you want:
size_t l = strlen(f);
char *tmp = malloc(l + strlen(s) + 1);
strcpy(tmp, f);
strcpy(tmp+l, s);
or:
size_t l = strlen(f) + strlen(s) + 1;
char *tmp = malloc(l);
snprintf(tmp, l, "%s%s", f, s);
I tend to prefer the latter unless you're writing embedded systems code where you want to avoid pulling in printf dependency.
Finally, note that you should be testing malloc for failure, and that it's useless and harmful to allocate memory and copy the strings if all you want to do is print them - you could just do the following:
printf("%s%s", f, s);
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);
}
}
How can I strip a string with all \n and \t in C?
This works in my quick and dirty tests. Does it in place:
#include <stdio.h>
void strip(char *s) {
char *p2 = s;
while(*s != '\0') {
if(*s != '\t' && *s != '\n') {
*p2++ = *s++;
} else {
++s;
}
}
*p2 = '\0';
}
int main() {
char buf[] = "this\t is\n a\t test\n test";
strip(buf);
printf("%s\n", buf);
}
And to appease Chris, here is a version which will make a place the result in a newly malloced buffer and return it (thus it'll work on literals). You will need to free the result.
char *strip_copy(const char *s) {
char *p = malloc(strlen(s) + 1);
if(p) {
char *p2 = p;
while(*s != '\0') {
if(*s != '\t' && *s != '\n') {
*p2++ = *s++;
} else {
++s;
}
}
*p2 = '\0';
}
return p;
}
If you want to replace \n or \t with something else, you can use the function strstr(). It returns a pointer to the first place in a function that has a certain string. For example:
// Find the first "\n".
char new_char = 't';
char* pFirstN = strstr(szMyString, "\n");
*pFirstN = new_char;
You can run that in a loop to find all \n's and \t's.
If you want to "strip" them, i.e. remove them from the string, you'll need to actually use the same method as above, but copy the contents of the string "back" every time you find a \n or \t, so that "this i\ns a test" becomes: "this is a test".
You can do that with memmove (not memcpy, since the src and dst are pointing to overlapping memory), like so:
char* temp = strstr(str, "\t");
// Remove \n.
while ((temp = strstr(str, "\n")) != NULL) {
// Len is the length of the string, from the ampersand \n, including the \n.
int len = strlen(str);
memmove(temp, temp + 1, len);
}
You'll need to repeat this loop again to remove the \t's.
Note: Both of these methods work in-place. This might not be safe! (read Evan Teran's comments for details.. Also, these methods are not very efficient, although they do utilize a library function for some of the code instead of rolling your own.
Basically, you have two ways to do this: you can create a copy of the original string, minus all '\t' and '\n' characters, or you can strip the string "in-place." However, I bet money that the first option will be faster, and I promise you it will be safer.
So we'll make a function:
char *strip(const char *str, const char *d);
We want to use strlen() and malloc() to allocate a new char * buffer the same size as our str buffer. Then we go through str character by character. If the character is not contained in d, we copy it into our new buffer. We can use something like strchr() to see if each character is in the string d. Once we're done, we have a new buffer, with the contents of our old buffer minus characters in the string d, so we just return that. I won't give you sample code, because this might be homework, but here's the sample usage to show you how it solves your problem:
char *string = "some\n text\t to strip";
char *stripped = strip(string, "\t\n");
This is a c string function that will find any character in accept and return a pointer to that position or NULL if it is not found.
#include <string.h>
char *strpbrk(const char *s, const char *accept);
Example:
char search[] = "a string with \t and \n";
char *first_occ = strpbrk( search, "\t\n" );
first_occ will point to the \t, or the 15 character in search. You can replace then call again to loop through until all have been replaced.
I like to make the standard library do as much of the work as possible, so I would use something similar to Evan's solution but with strspn() and strcspn().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SPACE " \t\r\n"
static void strip(char *s);
static char *strip_copy(char const *s);
int main(int ac, char **av)
{
char s[] = "this\t is\n a\t test\n test";
char *s1 = strip_copy(s);
strip(s);
printf("%s\n%s\n", s, s1);
return 0;
}
static void strip(char *s)
{
char *p = s;
int n;
while (*s)
{
n = strcspn(s, SPACE);
strncpy(p, s, n);
p += n;
s += n + strspn(s+n, SPACE);
}
*p = 0;
}
static char *strip_copy(char const *s)
{
char *buf = malloc(1 + strlen(s));
if (buf)
{
char *p = buf;
char const *q;
int n;
for (q = s; *q; q += n + strspn(q+n, SPACE))
{
n = strcspn(q, SPACE);
strncpy(p, q, n);
p += n;
}
*p++ = '\0';
buf = realloc(buf, p - buf);
}
return buf;
}