Replacing several characters in string with one in C - c

I need to replace several characters with one (depending if their count is even or odd). If it's even i should replace + with P, if it's odd with p.
Input: kjlz++zux+++
while(p[i])
{
j=i;
k=i;
length=strlen(p);
if(p[i]=='*')
{
position=i;
}
printf("Position is: %d", position);
while(p[j]=='*')
{
counter++;
j++;
}
}
Output: kjlzPzuxp
Im not sure how to remove several characters I know how to input one.

Basically you can leave the text variable intact until you find a +. In that case you start counting how many consecutive plusses there are. Once you know this, it can be decided if you should add a letter P or p. Keep a separate index to write back to your text variable! Otherwise it would start writing to the wrong index after 2 or 3 plusses are found, try to figure out why ;).
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
char text[] = "kjlz++zux+++";
int len = sizeof(text) / sizeof(text[0]);
int index = 0, count = 0;
for(int i = 0; i < len; i++)
{
if(text[i] == '+')
{
count = 0;
while(text[i] == '+') i++, count++;
i--;
text[index++] = count % 2 ? 'p' : 'P';
}
else
{
text[index++] = text[i];
}
}
text[index] = 0;
printf(text);
}
You could allocate space for the text variable with malloc so that you can use realloc afterwards to shrink the array to the size of the output text. This way some memory is saved, this is especially important when you start working with bigger chunks of data.

If I have understood correctly you do not know how to implement a corresponding function.
It can look the following way as it is shown in the demonstrative program.
#include <stdio.h>
char * replace_pluses( char *s )
{
const char plus = '+';
const char odd_plus = 'p';
const char even_plus = 'P';
char *dsn = s;
for ( char *src = s; *src; )
{
if ( *src == plus )
{
int odd = 1;
while ( *++src == plus ) odd ^= 1;
*dsn++ = odd ? odd_plus : even_plus;
}
else
{
if ( dsn != src ) *dsn = *src;
++dsn;
++src;
}
}
*dsn = '\0';
return s;
}
int main(void)
{
char s[] = "kjlz++zux+++";
puts( s );
puts( replace_pluses( s ) );
return 0;
}
The program output is
kjlz++zux+++
kjlzPzuxp
Or you can write a more generic function like this
#include <stdio.h>
char * replace_odd_even_duplicates( char *s, char c1, char c2, char c3 )
{
char *dsn = s;
for ( char *src = s; *src; )
{
if ( *src == c1 )
{
int odd = 1;
while ( *++src == c1 ) odd ^= 1;
*dsn++ = odd ? c2 : c3;
}
else
{
if ( dsn != src ) *dsn = *src;
++dsn;
++src;
}
}
*dsn = '\0';
return s;
}
int main(void)
{
char s[] = "kjlz++zux+++";
puts( s );
puts( replace_odd_even_duplicates( s, '+', 'p', 'P' ) );
return 0;
}

Related

applying cipher code given as argv to userinput

I am trying to write a function that takes in variables cipher, userinput, alphabet and outputs the replace letters. for example at execution it takes in an argument argv ZYXWVUTSRQPONMLKJIHGFEDCBA. requests a user to input anything then switches only the letters for example input aBc should output zYx
// function that takes in cipher(c), userinput(u) and alphabet(a) and outputs cipher text
void cipher_text(string c, string u, string a)
{
string result = u;
for (int i = 0; i < strlen(u); i++)
{
for (int k = 0; k < strlen(a); k++)
{
if (tolower(u[i]) == a[k])
{
if(islower(u[i]))
{
result[i] = tolower(c[k]);
printf("%s %s\n",result,c);
}
else
{
result[i] = toupper(c[k]);
}
}
}
}
// printf("ciphertext: %s\n", result);
}
with cipher as YUKFRNLBAVMWZTEOGXHCIPJSQD
and userinput as abcd
I was expecting yukf but got qidc
The problem of the function is this inner for loop
for (int k = 0; k < strlen(a); k++)
{
if (tolower(u[i]) == a[k])
{
if(islower(u[i]))
{
result[i] = tolower(c[k]);
printf("%s %s\n",result,c);
}
else
{
result[i] = toupper(c[k]);
}
}
}
You need to break it as soon as a letter is found in the string pointed to by the pointer a. Otherwise there can be a chain of changes.
Also using the function strlen is inefficient and redundant.
Instead of the for loop you could use standard function strchr.
The function can be declared and defined the following way
string cipher_text( string c, string u, string a )
{
for ( string p = u; *p != '\0'; p++ )
{
string pos = strchr( a, tolower( ( unsigned char )*p ) );
if ( pos != NULL )
{
size_t i = pos - a;
*p = islower( ( unsigned char )*p )
? tolower( c[i] )
: c[i];
}
}
return u;
}
Pay attention to that instead of the typedef name string it is better to use its underlaying type char *.
In this case the function can look the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char * cipher_text( const char *c, char *u, const char *a )
{
for (char *p = u; *p != '\0'; p++)
{
const char *pos = strchr( a, tolower( ( unsigned char )*p ) );
if (pos != NULL)
{
size_t i = pos - a;
*p = islower( ( unsigned char )*p )
? tolower( c[i] )
: c[i];
}
}
return u;
}
int main( void )
{
const char *c = "XYZ";
const char *a = "abc";
char u[] = "c_B_a";
puts( cipher_text( c, u, a ) );
}
The program output is
z_Y_x

Doubling all occurrences of a specific character in a string

I want to write a C program, that returns a new string allocated on the heap. This string is obtained by doubling all occurrences of “c” in a string (“abcdc” becomes “abccdcc” after doubling “c”).
This is my code and I don't really see where the problem is to fix it!
size_t taille = stringLength(str);
size_t k=0;
size_t q=0;
while (*str!='\0')
{
if (*str == c)
{
k=k+1;
}
++str;
}
char *nouvelle=malloc(taille+1+k);
int i,j= 0;
while(*str !='\0')
{
if (str[i] != c)
{
j=i;
nouvelle[j]=str[i];
}
else
{
j=i;
++q;
nouvelle[j]=str[i];
j=i+q;
nouvelle[j++]=str[i];
}
++i;
}
nouvelle[taille+1+k]='\0';
return nouvelle;
}
There are two problems with your code.
The first one is that after this while loop
while (*str!='\0')
{
if (*str == c)
{
k=k+1;
}
++str;
}
the pointer str points to the end of the string that is to the terminating zero character '\0'.
The second one is that you are using the uninitialized variable i
int i,j= 0;
while(*str !='\0')
{
if (str[i] != c)
{
j=i;
//..
This declaration
int i,j= 0;
is not the same as
int i = 0,j= 0;
That is only the variable j is initialized by 0.
And the statement
j = i;
does not make sense.
Also it is unclear whether c denotes a variable or the character 'c'. If you mean the character 'c' then you need to write at least like
if (*str == 'c')
You could define the function for example the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * duplicate_char( const char *s, char c )
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p == c) ++n;
}
char *nouvelle = malloc( strlen( s ) + n + 1 );
if (nouvelle)
{
if (n == 0)
{
strcpy( nouvelle, s );
}
else
{
char *p = nouvelle;
while (*s)
{
*p++ = *s++;
if (p[-1] == c) *p++ = c;
}
*p = '\0';
}
}
return nouvelle;
}
int main( void )
{
char *nouvelle = duplicate_char( "abcdc", 'c' );
if (nouvelle != NULL) puts( nouvelle );
free( nouvelle );
}
The program output is
abccdcc
If you want to use your own function stringLength instead of the standard C function strlen then it can look like
size_t stringLength( const char *s )
{
const char *p = s;
while ( *p ) ++p;
return p - s;
}

Splitting a string into chunks.

I'm trying to split a string into chunks of 6 using C and I'm having a rough time of it. If you input a 12 character long string it just prints two unusual characters.
#include <stdio.h>
#include <string.h>
void stringSplit(char string[50])
{
int counter = 0;
char chunk[7];
for (unsigned int i = 0; i < strlen(string); i++)
{
if (string[i] == ' ')
{
continue;
}
int lastElement = strlen(chunk) - 1;
chunk[lastElement] = string[i];
counter++;
if (counter == 6)
{
printf(chunk);
memset(chunk, '\0', sizeof chunk);
counter = 0;
}
}
if (chunk != NULL)
{
printf(chunk);
}
}
int main()
{
char string[50];
printf("Input string. \n");
fgets(string, 50, stdin);
stringSplit(string);
return(0);
}
I appreciate any help.
Your problem is at
int lastElement = strlen(chunk) - 1;
Firstly, strlen counts the number of characters up to the NUL character. Your array is initially uninitialized, so this might cause problems.
Assuming your array is filled with NULs, and you have, let's say, 2 characters at the beginning and you are looking to place the third one. Remember that your 2 characters are at positions 0 and 1, respectively. So, strlen will return 2 (your string has 2 characters), you subtract one, so the lastElement variable has the value 1 now. And you place the third character at index 1, thus overwriting the second character you already had.
Also, this is extremely inefficient, since you compute the number of characters each time. But wait, you already know how many characters you have (you count them in counter, don't you?). So why not use counter to compute the index where the new character should be placed? (be careful not to do the same mistake and overwrite something else).
The function is wrong.
This statement
int lastElement = strlen(chunk) - 1;
can result in undefined behavior of the function because firstly the array chunk is not initially initialized
char chunk[7];
and secondly after this statement
memset(chunk, '\0', sizeof chunk);
the value of the variable lastElement will be equal to -1.
This if statement
if (chunk != NULL)
{
printf(chunk);
}
does not make sense because the address of the first character of the array chunk is always unequal to NULL.
It seems that what you mean is the following.
#include <stdio.h>
#include <ctype.h>
void stringSplit( const char s[] )
{
const size_t N = 6;
char chunk[N + 1];
size_t i = 0;
for ( ; *s; ++s )
{
if ( !isspace( ( unsigned char )*s ) )
{
chunk[i++] = *s;
if ( i == N )
{
chunk[i] = '\0';
i = 0;
puts( chunk );
}
}
}
if ( i != 0 )
{
chunk[i] = '\0';
puts( chunk );
}
}
int main(void)
{
char s[] = " You and I are beginners in C ";
stringSplit( s );
}
The program output is
Youand
Iarebe
ginner
sinC
You can modify the function such a way that the length of the chunk was specified as a function parameter.
For example
#include <stdio.h>
#include <ctype.h>
void stringSplit( const char s[], size_t n )
{
if ( n )
{
char chunk[n + 1];
size_t i = 0;
for ( ; *s; ++s )
{
if ( !isspace( ( unsigned char )*s ) )
{
chunk[i++] = *s;
if ( i == n )
{
chunk[i] = '\0';
i = 0;
puts( chunk );
}
}
}
if ( i != 0 )
{
chunk[i] = '\0';
puts( chunk );
}
}
}
int main(void)
{
char s[] = " You and I are beginners in C ";
for ( size_t i = 3; i < 10; i++ )
{
stringSplit( s, i );
puts( "" );
}
}
The program output will be
You
and
Iar
ebe
gin
ner
sin
C
Youa
ndIa
rebe
ginn
ersi
nC
Youan
dIare
begin
nersi
nC
Youand
Iarebe
ginner
sinC
YouandI
arebegi
nnersin
C
YouandIa
rebeginn
ersinC
YouandIar
ebeginner
sinC

Add character at given position using pointers in C

Running into an issue with setting character at a specific position using pointers in C.
The code is accurately placing the character in the correct position, but the current character in that position is not being moved over.
The issue is that the current letter is being skipped over when position is found, but adding *dest++ = *string within the IF block when position is found causes the program to halt.
Example:
the string is "bigmoney". Letter to add is 'X'. The position is 3.
Output should be "bigXmoney"
Current output is "bigXoney" using the code below.
Any suggestions would be appreciated. Thanks!
Updated code:
void addLetter(char string[STRING_LENGTH], char letterToAdd, int pos)
{
// store array in pointer
char *stringHolder = string;
char *dest = string;
int posCounter = 0;
// loop through string while not null
while (*stringHolder) {
// position found, add the character
if (posCounter == pos) {
*dest++ = letterToAdd;
} else {
*dest++ = *stringHolder;
}
// increment position counter
posCounter++;
// move the pointer position
stringHolder++;
}
//reset stringholder pointer;
*dest = '\0';
}
If you don't want to use standard C string functions then the function can look the following way
char * addLetter( char s[], char c, size_t pos )
{
size_t i = 0;
while ( i < pos && s[i] ) ++i;
if ( i == pos )
{
do
{
char tmp = s[i];
s[i++] = c;
c = tmp;
} while ( c );
s[i] = c;
}
return s;
}
If you need to use only pointers inside the function then it can look like
char * addLetter( char s[], char c, size_t pos )
{
char *p = s;
while ( *p && p != s + pos ) ++p;
if ( p == s + pos )
{
do
{
char tmp = *p;
*p++ = c;
c = tmp;
} while ( c );
*p = c;
}
return s;
}
Here is a demonstrative program
#include <iostream>
char * addLetter( char s[], char c, size_t pos )
{
char *p = s;
while ( *p && p != s + pos ) ++p;
if ( p == s + pos )
{
do
{
char tmp = *p;
*p++ = c;
c = tmp;
} while ( c );
*p = c;
}
return s;
}
int main()
{
const size_t STRING_LENGTH = 10;
char s[STRING_LENGTH] = "bigmoney";
std::cout << s << std::endl;
std::cout << addLetter( s, 'X', 3 ) << std::endl;
return 0;
}
Its output is
bigmoney
bigXmoney
The easy way: Use std::string::insert.
Assuming std::string is forbidden in this assignment, start at the end of the string and work backward until you pass pos moving each character (including the null terminator) up one slot. Now you have an empty spot at pos and can safely write in the new value.
shorter if memcpy is allowed.
char * addLetter(char s[], char c, size_t pos)
{
int len = strlen(s);
if (pos > len || len + 1 >= STRING_LENGTH)
return NULL;
else
{
**memcpy(s + pos + 1, s + pos, len - pos);
s[pos] = c;**
return s;
}
}

While loop error while implementing 'strend'

I keep getting errors when I run the program I wrote for 'strlen'. (strlen returns 1 when one string appears at the end of another). I guess it's the first while loop that gives the error, because when I put printf("%c\n", *s); instead of empty ;, it just works fine. Is there something wrong with the syntax???
#include <stdio.h>
int strend(char *s, char *t)
{
int len;
int dummy;
while ( *s++ )
; // why error???
while ( *t++ )
len++;
for ( ; len>0 ; len--)
{
if ( *(s-len) != *(t-len) )
return 0;
}
return 1;
}
int main() {
char one[] = "I 0dont like youa";
char two[] = "ke youa";
printf("%d\n", strend(one, two));
}
First of all you forgot to initialize len, you should initialize it with 0.
int len=0;
Secondly use this:
while ( *s )
s++; // s should be incremented only if *s is not 0.
while ( *t )
{
t++; //Same issue here.
len++;
}
First of all local variable len was not initialized
int len;
So the function already has undefined behaviour.
Second after the loops
while ( *s++ );
while ( *t++ ) len++;
the both pointers point to beyond the terminating zeroes of each strings. As result this comparison (along with the for loop itself)
if ( *(s-len) != *(t-len) )
is not valid.
Indeed let's assume that we have
char s[] = { 'a', '\0' };
char t[] = { 'a', '\0' };
After the above loops len will be equal to 1 (provided that initially you initialized len with 0 ). At the same time t and s will point to the memory after the terminating zero. So *( s - len ) and *( t - len ) will represent elements '\0' and you will compare only these terminating zeroes while the elements with 'a' will not be compared because the condition of the for loop is len>0. That means that there will be only one iteration of the loop when len is equal to 1.
A correct function can be written simpler and more clear
int strend( const char *s, const char *t )
{
const char *p = s;
const char *q = t;
while ( *s++ );
while ( *t++ );
while ( s != p && t != q && *( s - 1 ) == *( t - 1 ) ) --s, --t;
return t == q;
}
If it is unimportant which one string appears at the end of another string then simply substitute this return statement
return t == q;
for the following one
return s == p || t == q;
In this case this program
//...
int main( void ) {
char one[] = "I 0dont like youa";
char two[] = "ke youa";
printf("%d\n", strend(one, two));
printf("%d\n", strend(two, one));
}
will output
1
1
While if to use use the first return statement return t == q; then the program
//...
int main( void ) {
char one[] = "I 0dont like youa";
char two[] = "ke youa";
printf("%d\n", strend(one, two));
printf("%d\n", strend(two, one));
}
will output
1
0
The error should come because of the missing initialization int len = 0;. I recommend using while always with embraces like this while { /*your code*/ };.
Your 1st while loop should be fine anyway. I made some modifications with two separated loops.
#include <stdio.h>
int strend(char *s, char *t)
{
int len = 0; // init 0
int i = 0,
j = 0;
while (*s++) { i++; } // get both string lengths
while (*t++) { j++; }
if (i > j) // compare and use shorter one
len = j;
else
len = i;
len++; // offset: start from 1st character
// [fix-issue: 2015-06-28 12:41]
for ( ; len>0 ; len--)
{
//printf("%d: \"%c\" \"%c\"\n", len, *(s-len), *(t-len)); // test-out
if ( *(s-len) != *(t-len) )
return 0;
}
return 1;
}
int main()
{
char one[] = "ABCDE";
char two[] = "CDE";
printf("test case 1: [%s][%s] %d\n", one, two, strend(one, two));
two[1] = '_';
printf("test case 2: [%s][%s] %d\n", one, two, strend(one, two));
two[0] = '?';
two[1] = 'D';
printf("test case 3: [%s][%s] %d\n", one, two, strend(one, two));
two[0] = 'C';
two[2] = '#';
printf("test case 4: [%s][%s] %d\n", one, two, strend(one, two));
}
The output goes like this:
test case 1: [ABCDE][CDE] 1
test case 2: [ABCDE][C_E] 0
test case 3: [ABCDE][?DE] 0
test case 4: [ABCDE][CD#] 0

Resources