i want to replace "\ " for every space when copying a string in C.
This is needed for call function system(), it identifies spaces as "\ ".
So every space should be replace by that.
#include <stdio.h>
char *my_strcopy(char *destination,char *source){
char *p;
p=destination;
while(*source != '\0'){
if(*source == ' '){
*p='\\';
*p++='\\';
*p++='\\';
*p++=' ';
}
else{
*p=*source;
}
*p++;
*source++;
}
*p='\0';
return destination;
}
The output of this come as "hello\ �world\ �hi"
how to get the it correctly. need help
I think you are adding too many \ for each space when your requirement is to only have one. You were also incrementing the destination pointer more often than necessary. Finally, it is not necessary to deference the pointers at the bottom of the loop while incrementing them, although it does not hurt.
The following correction seems to produce the output you want.
#include <stdio.h>
char *my_strcopy(char *destination,char *source){
char *p;
p=destination;
while(*source != '\0'){
if(*source == ' '){
*p++='\\';
*p=' ';
}
else{
*p=*source;
}
p++;
source++;
}
*p='\0';
return destination;
}
int main(){
char* src = "foobar bar bar";
char dst[2048];
my_strcopy(dst, src);
printf("%s\n", dst);
}
Output:
foobar\ bar\ bar
If I have understood correctly then the function can look like
char * my_strcopy( char *destination, const char *source )
{
char *p = destination;
do
{
if ( *source == ' ' ) *p++ = '\\';
*p++ = *source;
} while ( *source++ );
return destination;
}
Here is a demonstrative program
#include <stdio.h>
char * my_strcopy( char *destination, const char *source )
{
char *p = destination;
do
{
if ( *source == ' ' ) *p++ = '\\';
*p++ = *source;
} while ( *source++ );
return destination;
}
int main()
{
char s[] = "Hello world hi";
char d[sizeof( s ) + 2];
puts( s );
puts( my_strcopy( d, s ) );
return 0;
}
The program outputs is
Hello world hi
Hello\ world\ hi
I hope the function does not contain any redundant code.:) The body of the function loop contains only two statements.:)
Related
I have to make a function, that will code my sentence like this: I want to code all words with an o, so for example I love ice cream becomes I **** ice cream.
But my function ignores the result of strchr. And I don't know why.
This is my code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define LEN 1000
char *Shift(char *str, char *let) {
const char *limits = " ,-;+.";
char copy[LEN];
strcpy(copy, str);
char *p;
char *ptr;
ptr = strtok(copy, limits);
for (int j = 0; ptr != NULL; ptr = strtok(NULL, limits), ++j) {
int len = 0;
if (strchr(ptr, let) != NULL) {
p = strstr(str, ptr);
for (int i = 0; i < strlen(ptr); i++) {
p[i] = "*";
}
}
}
return str;
}
int main() {
char *s = Shift("I love my cocktail", "o");
puts(s);
}
Expected output is: I **** my ********
but I've got just printed the original string
For starters the function strchr is declared like
char *strchr(const char *s, int c);
that is its second parameter has the type int and the expected argument must represent a character. While you are calling the function passing an object of the type char * that results in undefined behavior
if (strchr(ptr, let) != NULL) {
It seems you mean
if (strchr(ptr, *let) != NULL) {
Also you may not change a string literal. Any attempt to change a string literal results in undefined behavior and this code snippet
p = strstr(str, ptr);
for (int i = 0; i < strlen(ptr); i++) {
p[i] = "*";
}
tries to change the string literal passed to the function
char *s = Shift("I love my cocktail", "o");
And moreover in this statement
p[i] = "*";
you are trying to assign a pointer of the type char * to a character. At least you should write
p[i] = '*';
If you want to change an original string you need to store it in an array and pass to the function the array instead of a string literal. For example
char s[] = "I love my cocktail";
puts( Shift( s, "o" ) );
Pay attention to that there is no great sense to declare the second parameter as having the type char *. Declare its type as char.
Also the function name Shift is confusing. You could name it for example like Hide or something else.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
char * Hide( char *s, char c )
{
const char *delim = " ,-;+.";
for ( char *p = s += strspn( s, delim ); *p; p += strspn( p, delim ) )
{
char *q = p;
p += strcspn( p, delim );
char *tmp = q;
while ( tmp != p && *tmp != c ) ++tmp;
if ( tmp != p )
{
for ( ; q != p; ++q ) *q = '*';
}
}
return s;
}
int main( void )
{
char s[] = "I love my cocktail";
puts(s);
puts( Hide( s, 'o' ) );
}
The program output is
I love my cocktail
I **** my ********
The for loop
for ( ; q != p; ++q ) *q = '*';
within the function can be rewritten as a call of memset
memset( q, '*', p - q );
There are multiple problems:
copying the string to a fixed length local array char copy[LEN] will cause undefined behavior if the string is longer than LEN-1. You should allocate memory from the heap instead.
you work on a copy of the string to use strtok to split the words, but you do not use the correct method to identify the parts of the original string to patch.
you should pass a character to strchr(), not a string.
patching the string with p[i] = "*" does not work: the address of the string literal "*" is converted to a char and stored into p[i]... this conversion is meaningless: you should use p[i] = '*' instead.
attempting to modify a string literal has undefined behavior anyway. You should define a modifiable array in main and pass the to Shift.
Here is a corrected version:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *Shift(char *str, char letter) {
const char *limits = " ,-;+.";
char *copy = strdup(str);
char *ptr = strtok(copy, limits);
while (ptr != NULL) {
if (strchr(ptr, letter)) {
while (*ptr != '\0') {
str[ptr - copy] = '*';
ptr++;
}
}
ptr = strtok(NULL, limits);
}
free(copy);
return str;
}
int main() {
char s[] = "I love my cocktail";
puts(Shift(s, 'o'));
return 0;
}
The above code still has undefined behavior if the memory cannot be allocated. Here is a modified version that operates in place to avoid this problem:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char *Shift(char *str, char letter) {
char *ptr = str;
while ((ptr = strchr(ptr, letter)) != NULL) {
char *p = ptr;
while (p > str && isalpha((unsigned char)p[-1]))
*--p = '*';
while (isalpha((unsigned char)*ptr)
*ptr++ = '*';
}
return str;
}
int main() {
char s[] = "I love my cocktail";
puts(Shift(s, 'o'));
return 0;
}
Note that you can also search for multiple characters at a time use strcspn():
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char *Shift(char *str, const char *letters) {
char *ptr = str;
while (*(ptr += strcspn(ptr, letters)) != '\0') {
char *p = str;
while (p > str && isalpha((unsigned char)p[-1]))
*--p = '*';
while (isalpha((unsigned char)*ptr)
*ptr++ = '*';
}
return str;
}
int main() {
char s[] = "I love my Xtabentun cocktail";
puts(Shift(s, "oOxX"));
return 0;
}
I'm trying to create a recursive function which removes the consecutive duplicate characters from a string. It works fine except the first few characters. For example if my input is MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL or something like this, output is MMuOKLE OL. As you can see except for the first two M's it works fine. How can I make this work for the first part too?
Here is my code:
#include <stdio.h>
char* remove_duplicates (char* str){
if(*(str+1)!='\0'){
if(*str==*(str+1)){
*(str+1)=*(str+2);
remove_duplicates(str+1);
}
remove_duplicates(str+1);
}
return str;
}
int main()
{
char sample[] = "MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL";
printf("OLD: |%s|\n", sample);
printf("NEW: |%s|\n", remove_duplicates(sample));
return 0;
}
Here you are.
#include <stdio.h>
char * remove_duplicates( char *s )
{
if ( *s )
{
if ( *s == *( s + 1 ) )
{
*( s + 1 ) = *( s + 2 );
remove_duplicates( s + 1 );
remove_duplicates( s );
}
else
{
remove_duplicates( s + 1 );
}
}
return s;
}
int main(void)
{
char s[] = "MMMMMuuuuuOOOOOKKKKLLLEE";
remove_duplicates( s );
puts( s );
return 0;
}
The program output is
MuOKLE
I did it this way:
#include <stdio.h>
char* remove_duplicates(char* str)
{
if (*str)
{
char* dest = remove_duplicates(str + 1);
str = (*str == *dest) ? dest : ((*(dest - 1) = *str), (dest - 1));
}
return str;
}
int main()
{
char sample[] = "MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL";
char sample2[] = "AA";
printf("OLD: |%s|\n", sample);
printf("NEW: |%s|\n", remove_duplicates(sample));
printf("OLD: |%s|\n", sample2);
printf("NEW: |%s|\n", remove_duplicates(sample2));
return 0;
}
Output
OLD: |MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL|
NEW: |MuOKLE OL|
OLD: |AA|
NEW: |A|
Thank you all for your help. I walked through my code on paper as you said and realised the problem is it doesn't compare the first and last M.
I add a new if statement if(*str==*(str-1)) *(str)=*(str+1); and it works now.
Now function is:
char* remove_duplicates (char* str){
if(*(str+1)!='\0'){
if(*str==*(str+1)){
*(str+1)=*(str+2);
remove_duplicates(str+1);
}
remove_duplicates(str+1);
}
if(*str==*(str-1)) *(str)=*(str+1);
return str;
}
I am here just adding the recursive function (language: C++) and not the entire code.
void removeConsecutiveDuplicates(char input[]) {
if(input[0] == '\0' || input[1]=='\0') return;
if(input[0]!=input[1]) return removeConsecutiveDuplicates(input+1);
else
{
for(int i=1;i<=strlen(input);i++)
{
input[i-1] = input[i];
}
return removeConsecutiveDuplicates(input);
}
return;
}
Recursion is too complicated I think.
Lets start with 2 cursor at the begining of the str
First a loop on the string.
While we don't reach the end *p of the string look forward p++
while (*p++) {
if (*p == *current)
continue;
If next char is the same as the current continue to search the next different char.
current++;
*current = *p;
When a different char is found just put it after current.
#include <stdio.h>
char* remove_duplicates (char* str){
char *p = str;
char *current = p;
while (*p++) {
if (*p == *current)
continue;
current++;
*current = *p;
}
return str;
}
int main()
{
char sample[] = "MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL";
printf("OLD: |%s|\n", sample);
printf("NEW: |%s|\n", remove_duplicates(sample));
printf("NEW: |%s|\n", remove_duplicates(""));
return 0;
}
OLD: |MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL|
NEW: |MuOKLE OL|
NEW: ||
Detail with AAAB
c for current
p
v
AAAB0
^
c
p
v
AAAB0
^
c
p
v
AAAB0
^
c
p
v
ABAB0
^
c
p
v
ABAB0
^
c
p
v
ABAB0
^
c
p
v
AB0B0
^
c
We get AB
I am trying to remove unnecessary whitespace from my char* for future use. Basically, I want to only have one space between words and remove any additional spaces, tabs, or new line characters in between words. The current code I have almost works I believe, but I am unable to read the memory of the individual characters I am storing in my array. Also any solution must not have a maximum character size so if dynamic memory allocation is needed that would need to be considered as well. Is there a way to get this working? Thanks
EDIT 1: trailing and leading spaces should also be removed. Thanks to #Vlad from Moscow for the clarification
int main()
{
char* fileString1;
fileString1=removeAdditionalWhiteSpace(fileString1);
}
char* removeAdditionalWhiteSpace(char* wordList)
{
char characterHolder;
char* finalList[strlen(wordList)];
char* delimeter = wordList;
int i = 0;
do
{
finalList[i] += characterHolder;
char* hasSpace = NULL;
while (*delimeter == ' ' || *delimeter == '\n' || *delimeter == '\t')
{
if(*delimeter == ' ')
{
if(hasSpace==NULL)
{
hasSpace = delimeter;
characterHolder = *delimeter;
}
else
{
++delimeter;
}
}
else if(*delimeter == '\n' || *delimeter == '\t')
{
*delimeter = ' ';
if(hasSpace==NULL)
{
hasSpace = delimeter;
characterHolder = *delimeter;
}
else
{
++delimeter;
}
}
}
hasSpace=NULL;
characterHolder = *delimeter;
i++;
}
while( (*wordList++ = *delimeter++) );
return *finalList;
}
Your function does not make sense and has undefined behavior.
For example the variable characterHolder was not initialized and it is added to pointer finalList[i]
char characterHolder; // <===
char* finalList[strlen(wordList)];
char* delimeter = wordList;
int i = 0;
do
{
finalList[i] += characterHolder; // <===
//….
If you need to remove redundant white spaces from a string including its leading and trailing white spaces then the function can look as it is shown in the demonstrative program below.
#include <stdio.h>
#include <ctype.h>
char * remove_duplicate_spaces( char *s )
{
char *src = s, *dsn = s;
while ( isspace( ( unsigned char )*src ) ) ++src;
do
{
char c = *src;
if ( isspace( ( unsigned char )c ) ) c = ' ';
if ( c == ' ' )
{
while ( isspace( ( unsigned char ) *++src ) );
if ( *src )
{
*dsn++ = c;
}
}
*dsn++ = *src;
} while ( *src++ );
return s;
}
int main(void)
{
char s[] = "\t\tIt is\t\ta very\nlong\nstring.\t\t";
printf( "\"%s\"\n", s );
printf( "\"%s\"\n", remove_duplicate_spaces( s ) );
return 0;
}
Its output is
" It is a very
long
string. "
"It is a very long string."
Man that looks super complicated.
Here's a simple function to remove whitespace from the string:" This is a test \t of some \n Extra white space. "
#include <stdio.h>
#include <ctype.h>
void removeWS(char* text)
{
char* d = text;
while (isspace(*text)) ++text;
while(*text)
{
*d = isspace(*text)? ' ' : *text;
text++;
while (isspace(*d) && isspace(*text)) ++text;
if (*text) d++;
}
*d = *text;
}
int main(void) {
char text[] = " This is a test \t of some \n Extra white space. ";
removeWS(text);
printf("%s\n", text);
return 0;
}
Sample Output:
Success #stdin #stdout 0s 4284KB
This is a test of some Extra white space.
Minimalistic approach:
size_t delspaces(char * str)
{
size_t src, dst;
size_t cnt;
for (cnt=src=dst=0; str[dst] = str[src++]; ) {
if (isspace(str[dst])) {
if (dst && !cnt++) str[dst++] = ' '
continue;
}
cnt=0;
dst++;
}
// remove trailing spaces
while (dst && isspace(str[dst-1])) str[--dst] = 0;
// return the string length of the resulting string
// (which could be useful for the caller)
return dst;
}
Final note: the last while() could be an if(), since there can be only one trailig space.
Hello and sorry if this questions is already answered (in the way I want to :-) ) but I think I have a memory problem.
Assuming the following C function (yes, this one is very dirty and not optimized):
char *strreplace(char **str, char *dst, char *replace) {
int replacestart = stringcompare(*str, dst), replaceend = strlen(dst), replacelen = strlen(replace);
char *tmp1 = (char *)malloc(sizeof(char) * (replacestart + 1)), *tmp2 = (char *)malloc(sizeof(char) * ((strlen(*str) - replaceend) + 1));
memset(tmp1, 0, sizeof(char) * (replacestart + 1));
memset(tmp2, 0, sizeof(char) * ((strlen(*str) - replaceend) + 1));
strncpy(tmp1, *str, replacestart);
strncpy(tmp2, *str + replacestart + replaceend, (strlen(*str) - (replaceend + replacestart)));
*str = realloc(*str, strlen(tmp1) + replacelen + strlen(tmp2));
memset(*str, 0, strlen(tmp1) + replacelen + strlen(tmp2));
strncpy(*str, tmp1, strlen(tmp1));
strncpy(*str + strlen(tmp1), replace, replacelen);
strncpy(*str + strlen(tmp1) + replacelen, tmp2, strlen(tmp2));
return *str;
}
As seen, it should replace *dst with *replace whithin **str.
This works basically as expected. Here's the problem:
The output (*str) is not cleard out with zeros after memsetting it and has still the wrong length, even after reallocating.
Means, if the string is longer after replacing, the last chars are cutted of *str.
In turn, if the string is shorter, old chars are at the end of the char string are found.
What did I wrong. Mentioned that I don't want to use sprintf and no C++-STL, just want to do this with pointers in C.
Other words, what would be the right way to replace a string in an c char string with pointers.
Thanks alot.
EDIT after reqeuest for more information
I use this function as following:
...open a textfile via FILE type, determining file lengts (fseek)...
char *filecontent = (char *)malloc(sizeof(char) * filesize);
if(filesize != fread(filecontent, sizeof(char), filesize, fd)) {
free(filecontent);
return -1;
}
streplace(&filecontent, "[#TOBEREPLACED#]", "replaced");
...doing other stuff with filecontent...
EDIT 2, adding stringcompare()
int stringcompare(const char *string, const char *substr) {
int i, j, firstOcc;
i = 0, j = 0;
while(string[i] != '\0') {
while(string[i] != substr[0] && string[i] != '\0') {
i++;
}
if(string[i] == '\0') {
return -1;
}
firstOcc = i;
while(string[i] == substr[j] && string[i] != '\0' && substr[j] != '\0') {
i++;
j++;
}
if(substr[j] == '\0') {
return firstOcc;
}
if(string[i] == '\0') {
return -1;
}
i = firstOcc + 1;
j = 0;
}
}
The logic of the function is not simple as it seems at the first glance.
You should decide what action to execute 1) if the source string is empty and 2) if the destination string is empty.
For example if the destination string is empty then the standard function strstr will return the address of the first character of the source string. However logically if dst is an empty string then the source string should not be changed except the case when it is in turn an empty string. In this case the function should just create a new string equal to the string replace.
Take into account that as the strings dst and replace are not changed within the function they should be declared with the qualifier const.
char * strreplace( char **str, const char *dst, const char *replace );
Also the function should report whether a new memory allocation was successful within the function by returning a null pointer in case when the allocation failed.
Taking all this into account the function can look the following way as it is shown in the demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * strreplace( char **str, const char *dst, const char *replace )
{
char *result = *str;
if ( *str[0] == '\0' )
{
if ( dst[0] == '\0' && replace[0] != '\0' )
{
char *result = malloc( strlen( replace ) + 1 );
if ( result )
{
strcpy( result, replace );
free( *str );
*str = result;
}
}
}
else if ( dst[0] != '\0' )
{
char *pos = strstr( *str, dst );
if ( pos != NULL )
{
size_t dst_n = strlen( dst );
size_t replace_n = strlen( replace );
result = ( char * )malloc( strlen( *str ) - dst_n + replace_n + 1 );
if ( result )
{
size_t n = pos - *str;
strncpy( result, *str, n );
strcpy( result + n, replace );
strcpy( result + n + replace_n, *str + n + dst_n );
}
free( *str );
*str = result;
}
}
return result;
}
int main(void)
{
const char *hello = "Hello everybody here";
char *str = malloc( sizeof( char ) );
str[0] = '\0';
if ( strreplace( &str, "", hello ) )
{
puts( str );
}
if ( strreplace( &str, "everybody", "Eurobertics" ) )
{
puts( str );
}
if ( strreplace( &str, "Hello", "Bye" ) )
{
puts( str );
}
if ( strreplace( &str, " here", "" ) )
{
puts( str );
}
if ( strreplace( &str, "Bye ", "" ) )
{
puts( str );
}
free( str );
return 0;
}
The program output is
Hello everybody here
Hello Eurobertics here
Bye Eurobertics here
Bye Eurobertics
Eurobertics
Your function looks overly complex. Here is a simple, working version:
char *strreplace(char **str, char *dst, char *replace) char *strreplace(char **str, char *dst, char *replace)
{
char *start, *tmp;
int n;
if ((start=strstr(*str,dst))==0) return(0);
n= (start-*str) + strlen(start+strlen(dst)) + strlen(replace) + 1;
tmp=malloc(n);
strncpy(tmp,*str,start-*str);
strcpy(tmp+(start-*str),replace);
strcat(tmp,start+strlen(dst));
free(*str);
*str= tmp;
return(tmp);
}
With test function:
void reptest(void)
{
char *src;
char rep[]= "brave new world";
src=malloc(strlen("Hello world of wonders")+1);
strcpy(src,"Hello world of wonders");
strreplace(&src,"world",rep);
printf("%s\n", src);
free(src);
}
Edit: my previous version forgot to copy the remainder. Fixed.
THE MESSAGE:
/usr/local/webide/runners/c_runner.sh: line 54: 20533 Segmentation fault
nice -n 10 valgrind --leak-check=full --log-file="$valgrindout" "$exefile"
I can't understand why I can't use pointer arithmetic when my function type is not void. Take a look at this example:
Let's say I have to write a function that would 'erase' all whitespaces before the first word in a string.
For example, if we had a char array:
" Hi everyone"
it should produce "Hi everyone" after the function's modification.
Here is my code which works fine when instead of
char* EraseWSbeforethefirstword() I have
void EraseWSbeforethefirstword.
When the function returns an object char* it can't even be compiled.
char* EraseWSbeforethefirstword(char *s) {
char *p = s, *q = s;
if (*p == ' ') { /*first let's see if I have a string that begins with a space */
while (*p == ' ') {
p++;
} /*moving forward to the first non-space character*/
while (*p!= '\0') {
*q = *p;
p++;
q++;
} /*copying the text*/
*q = '\0'; /*If I had n spaces at the beginning the new string has n characters less */
}
return s;
}
Here is a function implementation that has the return type char * as you want.
#include <stdio.h>
char * EraseWSbeforethefirstword( char *s )
{
if ( *s == ' ' || *s == '\t' )
{
char *p = s, *q = s;
while ( *p == ' ' || *p == '\t' ) ++p;
while ( ( *q++ = *p++ ) );
}
return s;
}
int main(void)
{
char s[] = "\t Hello World";
printf( "\"%s\"\n", s );
printf( "\"%s\"\n", EraseWSbeforethefirstword( s ) );
return 0;
}
The program output is
" Hello World"
"Hello World"
Take into account that you may not modify string literals. So the program will have undefined behavior if instead of the array
char s[] = "\t Hello World";
there will be declared a pointer to a string literal
char *s = "\t Hello World";
If you want that the function could deal with string literals then the function has to allocate a new array dynamically and to return a pointer to its first element.
If you may not use standard C string functions then the function can look the following way
#include <stdio.h>
#include <stdlib.h>
char * EraseWSbeforethefirstword( const char *s )
{
size_t blanks = 0;
while ( s[blanks] == ' ' || s[blanks] == '\t' ) ++blanks;
size_t length = 0;
while ( s[length + blanks] != '\0' ) ++length;
char *p = malloc( length + 1 );
if ( p != NULL )
{
size_t i = 0;
while ( ( p[i] = s[i + blanks] ) != '\0' ) ++i;
}
return p;
}
int main(void)
{
char *s= "\t Hello World";
printf( "\"%s\"\n", s );
char *p = EraseWSbeforethefirstword( s );
if ( p ) printf( "\"%s\"\n", p );
free( p );
return 0;
}