I've been tried to place each character in the source string between characters in the destination string. It worked with equal length words but it didn't work other situations
For example:
It worked between apple and fruit, result is afprpuliet.
But it didn't work between plane and yes, the result should have been pyleasne.
or fly and train, the result should have been ftlryain.
Here is my code:
#include <stdio.h>
#include <string.h>
#define DESTSIZE 100
#define SOURCESIZE 20
int main(void)
{
char destination [DESTSIZE], source [SOURCESIZE];
printf("enter destinantion string for strinsert: ");
scanf("%s", destination);
printf("enter source string for strinsert: ");
scanf("%s", source);
strinsert(destination, source);
printf("after strinsert, destination string is %s\n", destination);
return 0;
}
void strinsert(char destination[], char source [])
{
int dest_len = strlen(destination);
for (int i = dest_len - 1; i >= 0; i--) {
destination[2 * i] = destination[i];
}
for (int i = 0; i < dest_len; i++) {
destination[2 * i + 1]= source[i];
}
}
To do this "in place" (using an adequately sized destination array) is not hard. The key is to determine the index of the destination element, then start copying, one by one, from the longest of the two strings, right to left.
Subtle is that when the two lengths yet to be copied are the same value, the second array is used as the source, not the first.
#include <stdio.h>
#include <string.h>
char *merge( char s1[], char s2[] ) {
int l1 = strlen( s1 );
int l2 = strlen( s2 );
s1[ l1 + l2 ] = '\0'; // ensure string will be terminated
while( l1 || l2 )
if( l1 > l2 )
l1--, s1[ l1 + l2 ] = s1[ l1 ];
else
l2--, s1[ l1 + l2 ] = s2[ l2 ];
return s1;
}
int main( void ) {
char dest[100];
char *test[] = { "apple", "fruit", "plane", "yes", "fly", "train", };
const int nTest = sizeof test/sizeof test[0];
for( int i = 0; i < nTest; i += 2 ) {
printf( "%s << %s = ", test[i], test[i+1] );
strcpy( dest, test[i] );
puts( merge( dest, test[i+1] ) );
}
return 0;
}
apple << fruit = afprpuliet
plane << yes = pyleasne
fly << train = ftlryain
A more compact version of main() so that it doesn't draw so much attention:
int main( void ) {
char d[100], *t[] = { "apple", "fruit", "plane", "yes", "fly", "train", };
for( int i = 0; i < sizeof t/sizeof t[0]; i += 2 )
printf("%s << %s = %s\n", t[i], t[i+1], merge(strcpy(d, t[i]), t[i+1]));
return 0;
}
EDIT
Although this is more difficult for a human to read, merge() could, likewise, be made more compact. It's up to the reader to decide if this appeals to their taste.
char *merge( char s1[], char s2[] ) {
int l1 = strlen( s1 ), l2 = strlen( s2 );
char *p = s1 + l1 + l2;
*p = '\0';
while( l1 || l2 )
*--p = ( l1 > l2 ) ? s1[ --l1 ] : s2[ --l2 ];
return p;
}
The problem is here
for (int i = 0; i < dest_len; i++) {
destination[2 * i + 1]= source[i];
}
Your source length is only 20 characters but your destination length is 100. So you are reading past the bounds of the source array. You should change the second loop to something like
int src_len = strlen(source);
for (int i = 0; i < src_len; i++) {
destination[2 * i + 1]= source[i];
}
I think you are messing yourself up by trying to do it in-place. Sure, it can be done in-place, but that just adds complexity.
Try doing it with a destination that is not either of the sources.
void interleave_strings( char * dest, const char * src1, const char * src2 )
{
// Interleaves src1 and src2 and stores the result in dest.
// dest must have space for strlen(src1) + strlen(src2) + 1 characters.
}
Usage:
int main(void)
{
char destination[SOURCE_SIZE*2+1] = {0};
char source1[SOURCE_SIZE] = {0};
char source2[SOURCE_SIZE] = {0};
...
interleave_strings( destination, source1, source2 );
printf( "interleaved = \"%s\"\n", destination );
return 0;
}
Once you make sense of doing it that way, then you can totally go back and do it the harder in-place way.
Oh, BTW, functions beginning with “str” are reserved. Hence you should not create them. So I renamed it.
You overwrite existing data in the destination. The easiest way is to use temporary array:
char *merge(char *dest, const char *src)
{
char temp[strlen(dest) + strlen(src) + 1];
char *wrk = dest;
size_t index = 0;
while(*src | *dest)
{
if(*dest) temp[index++] = *dest++;
if(*src) temp[index++] = *src++;
}
memcpy(dest, temp, index);
dest[index] = 0;
return dest;
}
int main(void)
{
char dest[256] = "1234567890";
char *src = "abcdefghijklmno";
puts(merge(dest, src));
}
https://godbolt.org/z/sqznjMf6r
or with your examples:
int main(void)
{
puts(merge((char[128]){"apple"}, "fruit"));
puts(merge((char[128]){"pen"}, "paper"));
puts(merge((char[128]){"plane"}, "yes"));
puts(merge((char[128]){"fly"}, "train"));
}
https://godbolt.org/z/6dc9Kv3dP
Related
This question is mainly based on my past question: to solve this exercise, I needed to ask a standalone question; here's the link: " little question about a thing when it comes to dynamically allocate a string, how can I solve? ". (I said it, because problems are in the heap).
this is the exercise:
write a function that find the longest word in a string, and return another string (dynamically allocated in the heap). (word is defined as: sequence of alphanumeric characters without whitespaces).
this is my code:
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
char* longest_word(const char* sz) {
size_t length = 0;
for (size_t i = 0; sz[i] != 0; i++) {
if (isspace(sz[i])) {
length = 0;
}
else {
length++;
}
}
size_t sum = length + 1;
char* str = malloc(sum);
if (str == NULL) {
return NULL;
}
size_t stringlength = strlen(sz);
size_t sl = stringlength - (sum - 1);
for (size_t i = sl; sz[i] != 0; i++) {
str[i] = sz[i];
}
str[sum - 1] = 0;
return str;
}
int main(void) {
char sz[] = "widdewdw ededudeide sjfsdhiuodsfhuiodfihuodsfihuodsihuodsihuosdihuquesto";
char* str;
str = longest_word(sz);
free(str);
return 0;
}
the final string is the following: "ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍsjfsdhiuodsfhuiodfihuodsfihuodsi".
this is a good sign, because that means that my thinking process was right (although not entirely).
here's a detailed explanation:
find the length of the longest string, if the current character is a whitespace start counting from zero again. this works.
allocate enough space to store each character, plus the zero-terminator. (I've used size_t, because of the accepted answer of the linked question).
here's the critical part: "sz[i]" is the i-th position in the original string (i.e "sz"). I start counting from sz[i].
I have copied each character into str[i] until zero-terminator is reached.
at the end, placed 0 in str[sum-1], (not str[sum], because I've done it and it turned out to be a buffer overflow).
The funtion is incorrect.
This for loop
size_t length = 0;
for (size_t i = 0; sz[i] != 0; i++) {
if (isspace(sz[i])) {
length = 0;
}
else {
length++;
}
}
does not find the maximum length of words in the string. It returns just the last calculated value of the variable length. For example if the string is ended with a space then the value of length after the loop will be equal to 0.
And this for loop
for (size_t i = sl; sz[i] != 0; i++) {
str[i] = sz[i];
}
is trying to copy the tail of the string but not the word with the maximum length.
The function can be defined the following way as it is shown in the demonstration program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * longest_word( const char *s )
{
const char *delim = " \t";
size_t max_n = 0;
const char *max_word = s;
for ( const char *p = s; *p; )
{
p += strspn( p, delim );
if ( *p )
{
const char *q = p;
p += strcspn( p, delim );
size_t n = p - q;
if ( max_n < n )
{
max_n = n;
max_word = q;
}
}
}
char *result = malloc( max_n + 1 );
if ( result != NULL )
{
result[max_n] = '\0';
memcpy( result, max_word, max_n );
}
return result;
}
int main( void )
{
const char *s = "Find the longest word";
char *p = longest_word( s );
if ( p ) puts( p );
free( p );
}
The program output is
longest
I need to insert a character string to another character string.
I'd write my own code and it's work very well until I put SPACE character in insert character string.
I need to find out what is the problem of my code and How I can fix it.
//Insert string in another string
#include <stdio.h>
//Function to count number of characters in a string
int numOfChars(const char string[]);
//Function to insert string to another string
void insertString(char string[], char insert[], int position);
int main()
{
char str[20]= "145";
insertString(str, "23", 1);
printf("%s\n", str);
return 0;
}
int numOfChars(const char string[])
{
int counter = 0;
while(string[counter] != '\0')
counter++;
return counter;
}
void insertString(char string[], char insert[], int position)
{
int i, j;
int lenght1 = numOfChars(string);
int lenght2 = numOfChars(insert);
int finalLenght = lenght1 + lenght2;
for(i=lenght1, j=0; i<finalLenght; i++, position++, j++)
{
string[i] = string[position];
string[position] = insert[j];
}
string[finalLenght] = '\0';
}
Example 1 :
Main string : 145
Insert string : 23
Position : 2
Result : 12345
Example 2 with blank space :
Main string : 145
Insert string : 23[SPACE]
Position : 2
Result : 123 54
This loop
for(i=lenght1, j=0; i<finalLenght; i++, position++, j++)
{
string[i] = string[position];
string[position] = insert[j];
}
is incorrect because independent on the given position all characters from the source string stating at position position are written after the end of the source string.
Also the function insertString should be declared like
char * insertString(char string[], const char insert[], size_t position);
Here is a demonstrative program that shows how the function can be implemented.
#include <stdio.h>
size_t numOfChars( const char s[] )
{
size_t n = 0;
while ( s[n] != '\0' ) ++n;
return n;
}
char * insertString( char s1[], const char s2[], size_t pos )
{
size_t n1 = numOfChars( s1 );
size_t n2 = numOfChars( s2 );
if ( n1 < pos ) pos = n1;
for ( size_t i = 0; i < n1 - pos; i++ )
{
s1[n1 + n2 - i - 1] = s1[n1 - i - 1];
}
for ( size_t i = 0; i < n2; i++)
{
s1[pos+i] = s2[i];
}
s1[n1 + n2] = '\0';
return s1;
}
int main(void)
{
enum { N = 20 };
char s1[N] = "123";
puts( insertString( s1, "AB", 0 ) );
char s2[N] = "123";
puts( insertString( s2, "AB", 1 ) );
char s3[N] = "123";
puts( insertString( s3, "AB", 2 ) );
char s4[N] = "123";
puts( insertString( s4, "AB", 3 ) );
return 0;
}
The program output is
AB123
1AB23
12AB3
123AB
Changing string[i] = string[position]; to string[position+lenght2] = string[position]; should solve the problem.
While copying over the elements of string[i] to their proper places, the length of the string to insert should be considered in addition to the position variable. In other words, you should shift the characters in string by the number of elements that need to be inserted in the middle.
I am getting an incorrect result when adding two binary strings "11" + "11". I am expecting "110" but the answer I am getting is "010". I did add a special case if the carry is still 1.
char *addBinary(char *str1, char *str2)
{
int len1 = strlen(str1); //assume both string lengths are same
char *res = (char *)malloc((len1 + 1) * sizeof(char));
int i, a, b;
int carry = 0;
char result;
for (i = len1 - 1; i >= 0; i--)
{
a = str1[i] - '0';
b = str2[i] - '0';
carry = a + b + carry;
printf("%d %d %d \n", a, b, carry % 2);
result = carry % 2 + '0'; //convert to character
carry = carry / 2;
str1[i] = result; //use the existing string for the result
}
if (carry == 0)
{ //if there is no carry just use the existing string and return
printf("Final without carry %s \n", str1);
return str1;
}
else
{ //there was a carry, so put 1 in the 0th location and copy the string
res[0] = 1;
memcpy(res + 1, str1, sizeof(char) * len1);
printf("Final %s %s %d\n", res, str1,strlen(res));
return res;
}
}
int main()
{
char bin_str1[] = "11";
char bin_str2[] = "11";
printf("%s \n",addBinary(bin_str1, bin_str2));
return 0;
}
You have two main problems:
First when you allocate space for res:
char *res = (char *)malloc((len1 + 1) * sizeof(char));
You need to allocate space for len1+2 (carry and NUL termination), otherwise your memcpy will write out of bounds (you should copy len1+1 elements, otherwise it is not guaranteed that res is NUL terminated). Also note that in the case that you return str1 the memory is leaked.
Second problem occurs when you set the first char of res you do net set it to a printable character:
res[0] = 1;
You should set it to '1' instead.
One more thing to think of is, that if you have something like this:
char bin_str1[] = "10";
char bin_str2[] = "11";
Your addBinary() Function does not returns res, but str1.
Now here is the point, if you assign a pointer to your function so that you can release the memory back to the System, you will have an invalid free().
One approach could be like this:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
char *addBinary(char *str1, char *str2);
int main( void )
{
char bin_str1[] = "11";
char bin_str2[] = "11";
char *ptr = addBinary( bin_str1, bin_str2 );
if ( ptr )
{
printf("%s \n",ptr );
free( ptr );
}
}
char *addBinary(char *str1, char *str2)
{
char *res = calloc( strlen( str1 ) + strlen( str2 ), sizeof( *res ) );
int a, b, carry = 0;
size_t i = strlen( str1 ) - 1;
while ( i > 0 )
{
a = str1[i] - '0';
b = str2[i] - '0';
carry += a + b;
printf("%d %d %d \n", a, b,( carry % 2));
str1[i] = (char)( carry % 2 + '0'); ///convert to character
carry = carry / 2;
i--;
}
if ( carry == 0 )
{ ///if there is no carry RETURN NULL
printf("Final without carry %s \n", str1);
free( res );
return NULL;
}
else
{ //there was a carry, so put 1 in the 0th location and copy the string
res[0] = '1';
strcat( res, str1 );
printf("Final %s %s %zu\n", res, str1,strlen( res ));
return res;
}
}
Or, you can drop malloc and use it like this:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
int addBinary( char *dest, char *const str1, const char *const str2);
int main( void )
{
char bin_str1[] = "11";
char bin_str2[] = "11";
char dest[256] = { 0 };
if ( addBinary( dest, bin_str1, bin_str2 ) )
{
printf("Dest = %s\n", dest );
}
}
int addBinary( char *dest, char *const str1, const char *const str2)
{
int a, b, carry = 0;
size_t i = strlen( str1 ) - 1;
while ( i > 0 )
{
a = str1[i] - '0';
b = str2[i] - '0';
carry += a + b;
str1[i] = (char)( carry % 2 + '0'); ///convert to character
carry = carry / 2;
i--;
}
if ( carry )
{
dest[0] = '1';
strcat( dest, str1 );
return 1;
}
return 0;
}
I made some changes to your code to reduce it for better reading.
I am trying to insert a string by replacing a substring in the (original) string with a new string (toInsert). The start parameter is the starting position of the substring I want to replace. Note: This is part of a larger program but I am just trying to get this function to work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROW 5
#define COLUMN 81
void insertString(char original[], int start, int length, char toInsert[]){
char buffer[COLUMN];
int i = 0;
for (i=0; i<strlen(original); ++i){
if (i>=start){
buffer[i] = toInsert[i];
}
else{
buffer[i] = original[i];
}
}
buffer[strlen(buffer)-1] = '\0';
printf("%s\n", buffer);
return;
}
int main()
{
char rep[COLUMN] = "very";
char sub[COLUMN] = "are";
char buf[ROW][COLUMN] = {
{"How are you doing"}
};
int len = strlen(sub);
int start = 4;
insertString(buf[0], start, len, rep);
return 0;
}
The problem is it only prints "How".
I want it to print "How very you doing"
Also, I have tried using strcpy but that just gives errors/warnings (something to do with pointers and I don't want to deal with pointers because I have not learned about them yet.)
Your function does not make great sense because it neither enlarge or shrink the original string though it has to do this.
And moreover it has undefined behavior due to this if statement because when i is equal to or greater than start you can access the memory beyond the string toInsert using the index i.
if (i>=start){
buffer[i] = toInsert[i];
}
It is simpler to write the function using standard C functions.
Here you are
#include <stdio.h>
#include <string.h>
char * replaceString( char *s1, size_t pos, size_t n, const char *s2 )
{
size_t n1 = strlen( s1 );
if ( pos < n1 )
{
size_t n2 = strlen( s2 );
if ( n != n2 )
{
memmove( s1 + pos + n2, s1 + pos + n, n1 - pos - n + 1 );
}
memcpy( s1 + pos, s2, n2 );
}
return s1;
}
int main(void)
{
{
char s1[100] = "ab1111cd";
const char *s2 = "22";
puts( replaceString( s1, 2, 4 , s2 ) );
}
{
char s1[100] = "ab11cd";
const char *s2 = "2222";
puts( replaceString( s1, 2, 2 , s2 ) );
}
{
char s1[100] = "ab11cd";
const char *s2 = "22";
puts( replaceString( s1, 2, 2 , s2 ) );
}
return 0;
}
The program output is
ab22cd
ab2222cd
ab22cd
If to insert this code block
{
char s1[100] = "How are you doing";
const char *s2 = "very";
puts( replaceString( s1, 4, 3 , s2 ) );
}
in the demonstrative program you will get the output
How very you doing
I'm trying to "translate" an array of uint8_t [uint8_t lets_try[16]] to a string of 16*8+1[null character] elements. For example:
lets_try[0] = 10101010
lets_try[1] = 01010101
...
and I would like to have a string like:
1010101001010101...[\0]
Here the questions: 1) is there a quick way to perform this operation?
I was trying to do it on my own; my idea was starting from translating a single uint8_t variable into a string and obtaining the full array with a loop [I haven't done this last part yet]. At the end I wrote this code:
int main()
{
uint8_t example = 0x14;
uint8_t *pointer;
char *final_string;
pointer = &example;
final_string = convert(pointer);
puts(final_string);
return(0);
}
char *convert (uint8_t *a)
{
int buffer1[9];
char buffer2[9];
int i;
char *buffer_pointer;
buffer1[8]='\0';
for(i=0; i<=7; i++)
buffer1[7-i]=( ((*a)>>i)&(0x01) );
for(i=0; i<=7; i++)
buffer2[i] = buffer1[i] + '0';
buffer2[8] = '\0';
puts(buffer2);
buffer_pointer = buffer2;
return buffer_pointer;
}
Here other few questions:
2) I'm not sure I fully understand the magic in this expression I found online:
buffer2[i] = buffer1[i] + '0'; can somebody explain to me why the following puts(buffer2) is not going to work correctly without the +'0'? is it the null character at the end of the newborn string which makes the puts() work? [because with the null character it knows it's printing a real string?]
3) in the code above puts(buffer2) gives the right output while the puts in main() gives nothing; I'm going mad in looking again and again the code, I can't find what's wrong with that
4) in my solution I manage to convert an uint8_t into a string passing from an array of int:
uint8_t->int array->string; is there a way to shorten this procedure, passing directly from the uint8_t into a string, or improve it? [in forums I found only solutions in C++] it works but I find it a little heavy and not so elegant
Thanks everybody for the support
1.) it's a little bit faster to eliminate the int array.
2.) adding '0' changes the integer values 0 and 1 to their ascii values '0' and '1'.
3.) it's undefined behaviour to return the address of a local variable. You have to malloc memory in the heap.
4.) yes, just cut it out and do the whole operation all in one
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char uint8_t;
char *convert(uint8_t *a)
{
char* buffer2;
int i;
buffer2 = malloc(9);
if (!buffer2)
return NULL;
buffer2[8] = 0;
for (i = 0; i <= 7; i++)
buffer2[7 - i] = (((*a) >> i) & (0x01)) + '0';
puts(buffer2);
return buffer2;
}
int main()
{
uint8_t example = 0x14;
char *final_string;
final_string = convert(&example);
if (final_string)
{
puts(final_string);
free(final_string);
}
return 0;
}
Here's one way ...
char *uint8tob( uint8_t value ) {
static uint8_t base = 2;
static char buffer[8] = {0};
int i = 8;
for( ; i ; --i, value /= base ) {
buffer[i] = "01"[value % base];
}
return &buffer[i+1];
}
char *convert_bytes_to_binary_string( uint8_t *bytes, size_t count ) {
if ( count < 1 ) {
return NULL;
}
size_t buffer_size = 8 * count + 1;
char *buffer = calloc( 1, buffer_size );
if ( buffer == NULL ) {
return NULL;
}
char *output = buffer;
for ( int i = 0 ; i < count ; i++ ) {
memcpy( output, uint8tob( bytes[i] ), 8 );
output += 8;
}
return buffer;
};
int main(int argc, const char * argv[]) {
uint8_t bytes[4] = { 0b10000000, 0b11110000, 0b00001111, 0b11110001 };
char *string = convert_bytes_to_binary_string( bytes, 4 );
if ( string == NULL ) {
printf( "Ooops!\n" );
} else {
printf( "Result: %s\n", string );
free( string );
}
return 0;
}
... just extend for 16 bytes. There are many ways and it also depends on what do you mean with quick. Embedded systems, ...? You can make translation table to make it even faster, ...
UPDATE
char *convert_bytes_to_binary_string( uint8_t *bytes, size_t count ) {
if ( count < 1 ) {
return NULL;
}
const char *table[] = {
"0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111"
};
size_t buffer_size = 8 * count + 1;
char *buffer = malloc( buffer_size );
if ( buffer == NULL ) {
return NULL;
}
char *output = buffer;
for ( int i = 0 ; i < count ; i++ ) {
memcpy( output, table[ bytes[i] >> 4 ], 4 );
output += 4;
memcpy( output, table[ bytes[i] & 0x0F ], 4 );
output += 4;
}
*output = 0;
return buffer;
};
int main(int argc, const char * argv[]) {
uint8_t bytes[4] = { 0b10000000, 0b11110000, 0b00001111, 0b11110001 };
char *string = convert_bytes_to_binary_string( bytes, 4 );
if ( string == NULL ) {
printf( "Ooops!\n" );
} else {
printf( "Result: %s\n", string );
free( string );
}
return 0;
}