Change a character in a string to a string - c

I'm trying to write code in C that will take a string, check each character for a specific character (call it 'x'), and if the character is 'x', change it to multiple characters (like "yz"). Here is my attempt, assuming buffer and replace are defined arrays of characters (i.e. char buffer[400] = jbxyfgextd...; char replace[250];)
int j = 0;
for (j = 0; j < 110; j++) {
if (buffer[j]=='x') {
int len = strlen(replace);
replace[len] = 'y';
replace[len+1] = 'z';
}
else {
replace[j]=buffer[j];
}
}
When I run this I get some y's and z's, but they are not back to back. Is there any procedure/function to do this easily?

Because index in buffer[] and replace[] arrays are not same. Use two indexes separately.
In your code expression: replace[j] = buffer[j]; is wrong. You can correct it like:
else {
int len = strlen(replace);
replace[len]=buffer[j];
}
But to use strlen(), array replace[] should be nul \0 terminated. (declare replace as char replace[250] = {0})
Edit:
To write better code use two septate indexes as I suggested above -- code will be efficient and simplified.
int bi = 0; // buffer index
int ri = 0; // replace index
for (bi = 0; bi < 110; bi++) {
if (buffer[bi] == 'x') {
replace[ri++] = 'y';
replace[ri] = 'z';
}
else {
replace[ri] = buffer[bi];
}
replace[++ri] = '\0'; // terminated with nul to make it string
}

#include <iostream>
#include <string>
#include <cstring>
int main ( int argc, char *argv[])
{
// Pass through the array once counting the number of chars the final string
// will need then allocate the new string
char buffer[] = "this x is a text test";
char replacement[] = "yz";
unsigned int replaceSize = strlen(replacement);
unsigned int bufferSize = 0;
unsigned int newSize = 0;
// calculate the current size and new size strings
// based on the replacement size
char *x = buffer;
while (*x)
{
if ( *x == 'x' )
{
newSize+=replaceSize;
}
else
{
++newSize;
}
++x;
++bufferSize;
}
// allocate the new string with the new size
// and assign the items to it
char *newString = new char[newSize];
unsigned int newIndex = 0;
for ( unsigned int i = 0; i < bufferSize; ++i )
{
if ( buffer[i] == 'x' )
{
for ( unsigned int j = 0; j < replaceSize ; ++j )
{
newString[newIndex++] = replacement[j];
}
}
else
{
newString[newIndex++] = buffer[i];
}
}
std::string originalS ( buffer );
std::string newS ( newString );
std::cout << "Original: " << originalS << std::endl;
std::cout << "New: " << newS << std::endl;
delete newString;
}

Related

adding zeros before string

zfill algorithm is supposed to work as follows:
zfill function accepts two parameters, a string and a number,
if string length is >= the number, then it doesn't have to add anything, and it returns a copy to the string,
else, malloc enough space and add zeros before the string.
I'm trying to understand why is this solution not correct, it has two warnings:
1st warning:
for (i; i < zeros; i++) {
s[i] = "0";
}
"=": char differs in level of indirection from char[2]
2nd warning:
for (i; i < n; i++) {
s[i] = str[i];
}
buffer overrun while writing to s
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = "0";
}
for (i; i < n; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
return s;
}
int main(void) {
char str[] = "hello, world!";
size_t n = 40;
char* s = zfill(str, n);
free(s);
return 0;
}
EDIT: I've solved the problem this way:
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum-1] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = '0';
}
for (size_t j = 0; i < n; j++) {
s[i++] = str[j];
}
s[sum-1] = 0;
}
return s;
}
and it works, but I don't know why I have this warning:
for (i; i < zeros; i++) {}
statement with no effect
but when I've debugged I've noticed that this statement has an effect, because it correctly copies the correct number of zeros. I don't know why I have this warning
SO is a place of learning.
When first dealing with a coding challenge, it's best to take time to work out what's needed before starting to write code.
Below is a working version of zfill() (along with a main() that tests it.)
Read through the comments. The only thing new here is memset().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// A trivial "helper function" determines the max of two values
int max( int a, int b ) { return a > b ? a : b; }
char *zfill( char *str, int minLen ) {
// Determine length of arbitrary string
int len = strlen( str );
// Determine max of length v. minimum desired
int allocSize = max( minLen, len );
// allocate buffer to store resulting string (with '\0')
char *obuf = (char*)malloc( allocSize + 1 );
/* omitting test for failure */
// determine start location at which to copy str
int loc = len <= minLen ? minLen - len : 0;
if( loc > 0 )
// fill buffer with enough 'zeros'
memset( obuf, '0', allocSize ); // ASCII zero!
// copy str to that location in buffer
strcpy( obuf + loc, str );
// return buffer to calling function
return obuf;
}
int main() {
// collection of strings of arbitrary length
char *strs[] = { "abc", "abcdefghijkl", "abcde", "a", "" };
// pass each one to zfill, print, then free the alloc'd buffer.
for( int i = 0; i < sizeof strs/sizeof strs[0]; i++ ) {
char *cp = zfill( strs[i], 10 );
puts( cp );
free( cp );
}
return 0;
}
Output:
0000000abc
abcdefghijkl
00000abcde
000000000a
0000000000
Here's zfill() without the comments:
char *zfill( char *str, int minLen ) {
int len = strlen( str );
int allocSize = max( minLen, len );
char *obuf = (char*)malloc( allocSize + 1 );
/* omitting test for failure */
int loc = len <= minLen ? minLen - len : 0;
if( loc > 0 )
memset( obuf, '0', loc ); // ASCII zero!
strcpy( obuf + loc, str );
return obuf;
}
You don't want to spend your time staring at lines and lines of code.
Fill your quiver with arrows that are (proven!) standard library functions and use them.
I've omitted, too, the test for zfill being passed a NULL pointer.
This code snippet
size_t sum = length + 1u;
s = malloc(sum);
//...
s[sum] = 0;
accesses memory outside the allocated character array because the valid range of indices is [0, sum). You need to write at least like
s[length] = 0;
In this code snippet
for (i; i < zeros; ++) {
s[i] = "0";
}
the expression s[i] represents a single object of the type char while on the right-hand side there is a string literal that as an expression has the type char *. You need to write at least
s[i] = '0';
using the integer character constant instead of the string literal.
In this code snippet
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = "0";
}
for (i; i < n; i++) {
s[i] = str[i];
}
as the length of the string str can be less than n then this for loop
for (i; i < n; i++) {
s[i] = str[i];
}
accesses memory outside the string str.
Pay attention to that your function has redundant code. It can be written simpler.
The function can look for example the following way as shown in the demonstration program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * zfill( const char *s, size_t n )
{
char *result = NULL;
if ( s != NULL )
{
size_t len = strlen( s );
n = len < n ? n : len;
result = malloc( n + 1 );
if ( result )
{
size_t i = 0;
size_t m = len < n ? n - len : 0;
for ( ; i < m; i++ )
{
result[i] = '0';
}
for ( ; i < n; i++ )
{
result[i] = s[i - m];
}
result[i] = '\0';
}
}
return result;
}
int main( void )
{
const char *s = "Hello";
size_t n = 10;
char *result = zfill( s, n );
if ( result ) puts( result );
free( result );
}
The program output is
00000Hello
Or as #Some programmer dude pointed to in his comment you can use the standard C function snprintf that alone performs the task. For example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * zfill( const char *s, size_t n )
{
char *result = NULL;
if ( s != NULL )
{
size_t len = strlen( s );
n = len < n ? n : len;
result = malloc( n + 1 );
if ( result )
{
int m = len < n ? n - len : 0;
snprintf( result, n + 1, "%.*d%s", m, 0, s );
}
}
return result;
}
int main( void )
{
char *p = zfill( "Hello", 5 );
if ( p ) puts( p );
free( p );
p = zfill( "Hello", 10 );
if ( p ) puts( p );
free( p );
}
The program output is
Hello
00000Hello
so you have 3 major problems in your code :
it's s[i] = '0'; not s[i] = "0";
it's s[i] = str[i - zeros]; not s[i] = str[i]; as the value of the i will be 27 in your test case : so it make sense to say s[27] because its size is about 41 but it doesn't make sense to say str[27] as its size is only about 13 in your test case , so you had to map the value 27 of i to the value 0 to be convenient to use with str
i is deprecated in first part here for (i; i < zeros; i++) , so use for (; i < zeros; i++)instead of for (i; i < zeros; i++) , but it will not cause any problem if you keep it.
and here is the full edited code :
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (; i < zeros; i++) {
s[i] = '0';
}
for (; i < n; i++) {
s[i] = str[i - zeros];
}
s[sum] = 0;
}
return s;
}
int main(void) {
char str[] = "hello, world!";
size_t n = 40;
char* s = zfill(str, n);
printf("%s\n", s);
free(s);
return 0;
}

Replacing several characters in string with one in 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;
}

How to reverse the words in a sentence without using inbuilt function

I have a string "this is a test". I want to reverse it to "test a is this". We will take one string as "This is a test". After reversing it string should be "test a is this"
#include <stdio.h>
char *reverse(char *p);
void main() {
char p[100] = "this is a test";
char *s = reverse(p);
printf("%s", s);
}
output - test a is this.
I would do it like this:
#include <boost/regex.hpp>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char*argv[]){
string xStr;
cin >> xStr;
boost::regex xRegEx("(\\S+)");
vector<string> words;
boost::sregex_iterator xIt(xStr.begin(), xStr.end(), xRegEx);
boost::sregex_iterator xInvalidIt;
while(xIt != xInvalidIt)
words.push_back( *xIt++ );
for(std::vector<string>::iterator it = words.rbegin(); it != words.rend(); ++it) {
cout << *it << " ";
}
return 0;
}
Here's a simple strategy to reverse the order of words in a string.
Reverse the string (sentence)
Reverse back each word in the string
Let's break down the task into the following functions:
int mystrlen(char *s); // find the length of the string
char *rev_substr(char *s, int len); // reverse the substring s of length len
char *rev_sentence(char *s); // reverse the order of words in the string s
Here are the function definitions:
int mystrlen(char *s) {
int i = 0;
while(*s) {
i++;
s++;
}
return i;
}
char *rev_substr(char *s, int len) {
int i = 0;
int j = len - 1;
char temp;
while(i < j) {
temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
return s;
}
char *rev_sentence(char *s) {
int i, j = 0;
int len = mystrlen(s);
rev_substr(s, len); // reverse the whole string
for(i = 0; i <= len; i++) {
// a word is delimited by a space or the null character
if(s[i] == ' ' || s[i] == '\0') {
rev_substr(s+j, i-j); // reverse back each word
j = i + 1; // j is the index of the first letter of the next word
}
}
return s;
}
A sample implementation:
int main(void) {
char s[] = "this is a test";
printf("%s\n", rev_sentence(s));
return 0;
}
You can use the following algorithm:
Split the string into words in an array of strings (let's say A).
Print A in reverse order.
One way could be to split the sentence using a stringstream, and later just copy the words in reverse order:
std::string get_reversed( const std::string& str )
{
std::stringstream input( ss );
std::vector<std::string> temp;
std::stringstream output;
std::copy( std::istream_iterator<std::string>( input , " " ) ,
std::istream_iterator<std::string>() ,
std::back_inserter( temp )
);
std::reverse_copy( std::begin( temp ) ,
std::end( temp ) ,
std::ostream_iterator<std::string>( output , " " )
);
return output.str();
}
No regular expressions, no Boost: Only Standard Library containers and algorithms ;)
Try this:
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
char* reverseString(char* inStr)
{
int numChars = strlen(inStr); // Length of input string
char* outStr = (char*)malloc(numChars+1); // Allocate 1 + string length so there is space to fit '\0'
char* wordStart = &inStr[numChars]; // Pointer to the start of a word. Initialized to '\0' character of the input
char* wordEnd = wordStart-1; // Pointer to the end of word. Initialized to the last character of the input
char* destination = outStr; // Pointer to the start of a new word in the reversed string
char* srcStart; // Temporary pointer
char delimiter; // Word delimiter set to '\0' when the first word of input is copied, set to ' ' for
// all other words in the input string
while (--wordStart >= inStr)
{
if (*wordStart == ' ')
{
srcStart = wordStart+1; // start at the first letter following the space
delimiter = ' '; // add a space at the end of the copied word
}
else if (wordStart == inStr)
{
srcStart = wordStart; // start at the first letter of the input string
delimiter = '\0'; // add the null terminator to mark the end of the string
}
else
{
srcStart = NULL; // not at word boundary, mark NULL so the logic below skips the copy operation
}
if (srcStart)
{
for (char* src = srcStart; src <= wordEnd; ++src, ++destination)
{
*destination = *src;
}
*destination = delimiter;
destination++;
wordEnd = wordStart-1;
}
}
return outStr;
}
int main(int argc, char** argv)
{
if (argc < 2)
{
cout << "Please provide an input string!..." << endl;
return -1;
}
cout << "Original String = " << argv[1] << endl
<< "Reversed String = " << reverseString(argv[1]) << endl;
return 0;
}
This does incur the cost of creating a new string, so it's not the most efficient route, but it gets the job done.
A program that uses recursive calling.
int count=0;
void w_rev(char *p)
{
if((*p)!= '\0')
{
if((*p) !=' ')
{
w_rev(p+1);
printf("%c",*p);
}
count++;
}
}
void w_rev_call(char * p)
{
while(*(p+count) != '\0' )
{
w_rev(p+count);
printf(" ");
}
}
If arr is the name of the array, then the statement w_rev_call(arr) will give desired output.

How to write a getline function in C?

I know that getline is C++ standard but I need to read a line of digits:
123856
and save it to an array. But how to do this without spaces between given (as input) digits? I want a user input to be:
123856 (with no spaces) and then save it to an array (n element array) and after that, I want my array to look like this:
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 8;
array[4] = 5;
array[5] = 6;
But how to make it in C, without a getline?
This is NOT what I want:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
int main(int argc, char **argv)
{
int t[4];
int i;
for(i=0; i<4; i++)
scanf("%d", &t[i]);
for(i=0; i<4; i++)
printf("%d\n", t[i]);
return 0;
}
If I understood you correct, the following should do it:
read the whole line
loop through the string as long as you get digits or the string ends
for every digit, place it's value in your array and increase the index by 1
while( ( c = getchar()) != EOF && c != '\n' && i < max ) {
/* If desired, add check for value outside of 0-9 */
array[ i++ ] = c - '0';
...
}
char arr[] = "1234567";
int intarr[10];
int count = 0;
for (char* ptr = arr; *ptr; ptr++) {
intarr[count] = *ptr - '0';
count++;
}
try this
#include <stdio.h>
#include <string.h>
main (int argc, char *argv[])
{
FILE *f;
int i=0;
int j=0;
char output[100];
char* output1[100];
char string[100];
char delims1[] = " ";
char delims2[] = "*";
char* result = NULL;
char* result3 = NULL;
int num;
//for (j=0; j<2; j++)
//{
//printf("%s",delims9[6]);
//}
f = fopen("text.txt","r");
//
while( fgets(string,sizeof(string),f) )
{
result = strtok( string, delims1 );
while( result != NULL )
{
output1[i]=result;
printf("%s\n",output1[i]);
result = strtok( NULL, delims1 );
i++;
}
for (num = 0; num < 100; i++ ) //
{ // Error On this array
printf("%s\n", output1[i]); //
} //
}
printf("\n%d",i/3+1);
return 0 ;
}
Ok, without using any string.
int digits = 123856;
int numofdigits = 1 + floor(log10(digits));
int digits_arr[numofdigits];
int i;
for(i = numofdigits-1; i >= 0; i--) {
digits_arr[i] = (int)floor(digits / pow(10, i)) % 10;
}
Try the below link... Same question asked here and get solution....
convert an integer number into an array
char * convertNumberIntoArray(unsigned int number) {
unsigned int length = (int)(log10((float)number)) + 1;
char * arr = (char *) malloc(length * sizeof(char)), * curr = arr;
do {
*curr++ = number % 10;
number /= 10;
} while (number != 0);
return arr;
}

How can I trim and pass an array of strings into a function?

How can I trim a string into pieces of N numbers of characters and then pass them as an array of strings into a function?
This in a part of my program that converts binary<->hex.
I tried doing the same thing with strings but it did not work.
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <String.h>
#define MAXDIGITS 8 // 8bits
int main()
{
int y;
printf("Binary-Hex convertor\n");
printf("Enter the Binary value : ");
scanf("%d", &y);
int i = MAXDIGITS - 1;
int array[MAXDIGITS];
while(y > 0)
{
array[i--] = y % 10;
y /= 10;
}
printf("%s", "-----------------\n");
printf("%s", "HEX:");
int x = array[0];
int x1 = array[1];
int x2 = array[2];
int x3 = array[3];
int x4 = array[4];
int x5 = array[5];
int x6 = array[6];
int x7 = array[7];
char buffer[50];
char buffer2[50];
char buffer3[50];
}
If its just binary to hex from a string then this is much easier....
char *input_string = "1001010101001010";
int count = 0;
int value = 0;
while ( *input_string != '\0' )
{
// Might be worth checking for only 0 and 1 in input string
value <<= 1;
value |= (int)((*input_string--) - '0');
if ( ++count == 8 || *input_string == '\0' )
{
// USE value to print etc, if you want to display use
// the following else you could store this in an array etc.
printf("%x ", value);
count = 0;
value = 0;
}
}
Do you have to null terminate the strings, do you have a limit on this memory used. Do you need to allocate the memory correctly etc? A bit more info would be useful
const char *input_string = "HELLO THIS IS SOME INPUT STRING";
int N = 4; // The number to split on
// Work out how many strings we will end up in
int number_of_strings = (strlen(input_string) + (N - 1)) / N;
// ALlow for an extra string if you want to null terminate the list
int memory_needed = ((number_of_strings + 1) * sizeof(char *)) + (number_of_strings * (N + 1));
char *buffer = malloc(memory_needed);
char **pointers = (char **)buffer;
char *string_start = (buffer + ((number_of_strings + 1) * sizeof(char *));
int count = 0;
while ( *input_string != '\0' )
{
// Fresh string
if ( count == 0 )
{
*pointers++ = string_start;
*pointers = NULL; // Lazy null terminate
}
// Copy a character
*string_start++ = *input_string++;
*string_start = '\0'; // Again lazy terminat
count++;
if ( count == N )
{
count = 0;
string_start++; // Move past the null terminated string
}
}
You can then pass (char **)buffer; to a routine. I havent actually tried this, ive been lazy in the terminating of the strings. You could just terminate at the end of a count run and the end of the while loop. This isnt exactly pretty code, but it should do the job. Bit more info on the other requirements might be good.

Resources