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.
Related
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
Hello guys so I am learning C and I am creating the strcat function and when I print out the values of dest at the index i concatenate a char at I get that char but when I return dest and print it out back in my main function the changes aren't reflected. Can someone please help me out? thanks.
#include <stdio.h>
#include <stdlib.h>
int size_s(char *str) {
int size = 0;
int index = 0;
while (str[index] != '\0') {
size += 1;
index += 1;
}
return (size + 1);
}
/*
* #function: strcat
* #desc: Takes in two char pointers and concatenates them. provided the destination has enough size otherwise undefined behavior can occur. Overwrites the null terminator
*/
char *strcat_s(char *dest, char *source)
{
int index_of_src = 0;
int index_of_dest = size_s(dest);
while (source[index_of_src] != '\0') {
*(dest + index_of_dest) = source[index_of_src];
index_of_src += 1;
index_of_dest += 1;
}
// Add Null terminator
*(dest + (index_of_dest + 1)) = '\0';
return dest;
}
int main(int argc, char **argv) {
char firstname[100];
scanf("%s", firstname);
char lastname[100];
scanf("%s", lastname);
int sizeofFirst = size_s(firstname);
printf("Sizeof first: %d\n", sizeofFirst);
int sizeofSecond = size_s(lastname);
printf("Sizeof second: %d\n", sizeofSecond);
char *concatinated = strcat_s(firstname, lastname);
printf("%s\n", concatinated);
}
The function size_s returns the index of the character after the zero-terminating character '\0' due to this return statement
return (size + 1);
So in this while loop
int index_of_src = 0;
int index_of_dest = size_s(dest);
while(source[index_of_src] != '\0')
{
*(dest + index_of_dest) = source[index_of_src];
index_of_src += 1;
index_of_dest += 1;
}
the array pointed to by the pointer dest is filled after the terminating zero character '\0'.
As a result this call of printf
printf("%s\n", concatinated);
outputs the initially stored string in the array firstname.
Rewrite the function size_s the following way
size_t size_s( const char *s )
{
size_t n = 0;
while ( s[n] != '\0' ) ++n;
return n;
}
In turn the function strcat_s that should be renamed because there is standard function strcat_s can look for example the following way
char * strcat_str( char *dest, const char *source )
{
size_t n = size_s( dest );
while ( ( *( dest + n++ ) = *source++ ) != '\0' );
return dest;
}
There are multiple issues in your code:
the size_s function really computes the size of the string, including the null terminator, but counting the null terminator is not helping for the task at hand, you should instead compute the length of the string, ie: the number of bytes before the null terminator, which is exactly the offset where to copy the second string at the end of the first.
*(dest + (index_of_dest + 1)) = '\0'; does not store the null terminator at the correct place: it places it one step too far. You should write *(dest + index_of_dest) = '\0'; or simply dest[ndex_of_dest] = '\0';
the name strcat_s may conflict with a library function of the same name defined in the infamous Annex K of the C Standard. A different name is preferable.
scanf("%s", firstname); is a security flaw: sufficient long input will cause a buffer overflow and carefully crafted input may allow the user to execute arbitrary code. Use scanf("%99s", firstname); to avoid this.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int my_strlen(const char *str) {
int index = 0;
while (str[index] != '\0') {
index += 1;
}
return index;
}
/*
* #function: strcat
* #desc: Takes in two char pointers and concatenates them. provided the destination has enough size otherwise undefined behavior can occur. Overwrites the null terminator
*/
char *my_strcat(char *dest, const char *source) {
int index_of_src = 0;
int index_of_dest = my_strlen(dest);
while (source[index_of_src] != '\0') {
dest[index_of_dest] = source[index_of_src];
index_of_src += 1;
index_of_dest += 1;
}
// Add the null terminator
dest[index_of_dest] = '\0';
return dest;
}
int main(int argc, char **argv) {
char firstname[200];
char lastname[100];
if (scanf("%99s %99s", firstname, lastname) != 2)
return 1;
printf("length of first: %d\n", my_strlen(firstname));
printf("length of second: %d\n", my_strlen(lastname));
char *concatenated = my_strcat(firstname, lastname);
printf("%s\n", concatenated);
printf("length of concatenation: %d\n", my_strlen(concatenated));
return 0;
}
char* string = "Hello, what's up?";
and I want to just return
"at's up?"
You can write a function. If the function shall not use standard C string functions then it can look for example the following way
char * substr( char *s, size_t pos )
{
size_t i = 0;
while ( i < pos && s[i] ) ++i;
return s + i;
}
As C does not support function overloading then the function above can be also written like
char * substr( const char *s, size_t pos )
{
size_t i = 0;
while ( i < pos && s[i] ) ++i;
return ( char * )( s + i );
}
Here is a demonstrative program.
#include <stdio.h>
char * substr( const char *s, size_t pos )
{
size_t i = 0;
while ( i < pos && s[i] ) ++i;
return ( char * )( s + i );
}
int main(void)
{
char * s = "Hello, what's up?";
puts( substr( s, 9 ) );
return 0;
}
The program output is
at's up?
If you already know the length of the string (and therefore know that going n characters ahead you will not go past the end), you can use string + n or &string[n], which are equivalent ways of "skipping" the first n characters of the string.
#include <stdio.h>
int main(void) {
char *str = "Hello!";
printf("%s\n", str + 1); // ello!
printf("%s\n", str + 3); // lo!
char *str2 = str + 3;
printf("%s\n", str2); // lo!
}
On the other hand, if you do not know the length of the string, you will have to make sure you don't go past the end by using a loop first. You can write a function for this:
#include <stdio.h>
char *skip(char *s, size_t n) {
while (*s && n--)
s++;
return s;
}
int main(void) {
char *str = "Hello!";
printf("%s\n", skip(str, 1)); // ello!
printf("%s\n", skip(str, 3)); // lo!
printf("%s\n", skip(str, 100)); // empty line
char *str2 = skip(str, 3);
printf("%s\n", str2); // lo!
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<stdbool.h>
int compare (const void *a, const void * b){
return ( *(char *)a - *(char *)b ); }
// A utility function two swap two characters a and b
void swap (char* a, char* b)
{
char t = *a;
*a = *b;
*b = t; }
int findCeil (char str[], char first, int l, int h)
{
// initialize index of ceiling element
int ceilIndex = l;
int i;
// Now iterate through rest of the elements and find
// the smallest character greater than 'first'
for (i = l+1; i <= h; i++)
if (str[i] > first && str[i] < str[ceilIndex])
ceilIndex = i;
return ceilIndex;
}
// Print all permutations of str in sorted order
void sortedPermutations ( char str[] )
{
FILE *fp;
fp = fopen("out.txt","w+");
char buffer[100];
memset(buffer,'\0',100);
// Get size of string
int size = strlen(str);
// Sort the string in increasing order
qsort( str, size, sizeof( str[0] ), compare );
// Print permutations one by one
bool isFinished = false;
while ( ! isFinished )
{
// print this permutation
setvbuf(str, buffer, _IONBF, 1024);
printf ("%s \n", str);
fprintf(fp,"%s\n",buffer);
// Find the rightmost character which is smaller than its next
// character. Let us call it 'first char'
int i;
for ( i = size - 2; i >= 0; --i )
if (str[i] < str[i+1])
break;
// If there is no such chracter, all are sorted in decreasing order,
// means we just printed the last permutation and we are done.
if ( i == -1 )
isFinished = true;
else
{
// Find the ceil of 'first char' in right of first character.
// Ceil of a character is the smallest character greater than it
int ceilIndex = findCeil( str, str[i], i + 1, size - 1 );
// Swap first and second characters
swap( &str[i], &str[ceilIndex] );
// Sort the string on right of 'first char'
qsort( str + i + 1, size - i - 1, sizeof(str[0]), compare );
}
fclose(fp);
}
}
int main()
{
char str[] = "ABCD";
sortedPermutations( str );
return 0;
}
Hi ,I am trying jumble solver .I want to store the result of permutation to a buffer and then from buffer to some file,so that I can compare it with dictionary. getting errors for setvbuf.
My C is very rusty,not able to get the desired results.
there are plenty of errors. First you use setvbuf with wrong arguments and do that in cycle. Then you fprintf buffer value instead of str. And also close file in cycle.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare (const void *a, const void * b) {
return ( *(char *)a - *(char *)b );
}
void swap (char* a, char* b) {
char t = *a;
*a = *b;
*b = t;
}
int findCeil (const char str[], char first, int l, int h) {
int ceilIndex = l;
int i;
for (i = l+1; i <= h; i++) {
if (str[i] > first && str[i] < str[ceilIndex]) {
ceilIndex = i;
}
}
return ceilIndex;
}
void sortedPermutations ( char str[] ) {
FILE *fp;
char buffer[1024];
int size = strlen(str);
int isFinished = 0;
fp = fopen("out.txt","w+");
memset(buffer, 0, 100);
qsort( str, size, sizeof( str[0] ), compare );
setvbuf(fp, buffer, _IOFBF, 1024);
while ( !isFinished ) {
int i;
printf("%s \n", str);
fprintf(fp, "%s\n", str);
for ( i = size - 2; i >= 0; --i )
if (str[i] < str[i+1]) {
break;
}
if ( i == -1 ) {
isFinished = 1;
} else {
int ceilIndex = findCeil( str, str[i], i + 1, size - 1 );
swap( &str[i], &str[ceilIndex] );
qsort( str + i + 1, size - i - 1, sizeof(str[0]), compare );
}
}
fclose(fp);
}
int main() {
char str[] = "ABCD";
sortedPermutations( str );
return 0;
}
setvbuf is used to set custom buffer. It is used, for example, to set big buffer and to have direct access to it. fprintf will print to file only when buffer is full, or when you flush, or close file. And you also use _IONBF which means that stream is not buffered at all.
So - it works only, because it is not buffered, as you send buffer [100], and then try to print 1024. So also change size of buffer to 1024 and use _IOFBF.
I'm trying to replace ' ' (space) with '___' (triple underscore) in C.
Here is my code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
char *a = "12 34 56";
int a_l = strlen(a);
printf("str1: \"%s\" (%d)\n", a, a_l);
char *b = "___";
int b_l = strlen(b);
printf("str2: \"%s\" (%d)\n", b, b_l);
for (int i = 0; i < a_l; i++) {
if (a[i] == ' ') {
char *o = malloc(a_l + b_l);
strncpy(o, a, i);
strncpy(o + i, b, a_l);
//strncpy help
printf("out: \"%s\"\n", o);
}
}
return 0;
}
I think that it is right so far, but I need to replace the comment line with correct strncpy (take the rest of string a (excluding space) and append it to string o). So the output should be like this:
str1: "12 34 56" (8)
str2: "___" (3)
out: "12___34 56"
out: "12 34___56"
If there are other mistakes in my code, please tell me.
UPD: This shouldn't replace all spaces in a loop. If the source string contains 8 spaces, there should be 8 lines printed and in each line only one space should be replaced.
You are overcomplicating this so much that I just TL;DR.
Some remarks that you might surely want to read, learn, embrace well and use:
I. int is not for string lengths and stuff. size_t is for string lengths and stuff.
II. String literals cannot be modified, so using the legacy char * type for assigning them to a variable is no good by any means, const-qualify that poor pointer base type.
III. Use VLAs instead of malloc() if dynamic memory management is not really needed (we're not living in 1989 anymore).
IV. NUL-terminate your strings because C stdlib routines expect you to do so.
int main()
{
const char *in = "foo bar baz";
int nspc = 0;
for (const char *p = strchr(in, ' '); p; p = strchr(p + 1, ' '))
nspc++;
char buf[strlen(in) + nspc * 2 + 1];
memset(buf, 0, sizeof(buf));
const char *s = in;
for (const char *p = strchr(s, ' '); p; p = strchr(s, ' ')) {
strncat(buf, s, p - s);
strcat(buf, "___");
s = p + 1;
}
const char *end = in + strlen(in);
strncat(buf, s, end - s);
printf("%s\n", buf);
return 0;
}
You can try this one. The problem comes from the fact that a_l + b_l in your malloc is always the same value. It doesn't affect by number of spaces.
int count = 0, index = 0;
for (int i = 0; i < a_l; ++i) {
if (a[i] == ' ') {
count++;
}
}
const char *o = malloc(a_l + 2 * count + 1); // 2 is because you add 3 new symbols, but remove 1 so 3 - 1 = 2
memset(o, 0, sizeof(o));
for (int i = 0; i < a_l; ++i) {
if (a[i] != ' ')
o[index++] = a[i];
else {
o[index++] = '_';
o[index++] = '_';
o[index++] = '_';
}
}
Without using library function!!!
while(*string)
{
if(*string=='\\')
{
*string++;
while(repl_len--)
*dest++ = *repl_string++;
}
else
{
*dest++ = *string++;
}
repl_string = temp_repl_string;
repl_len = temp_repl_len;
}
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
size_t my_strlen(const char *str, size_t *spc){
size_t len;
*spc = len = 0;
while(*str){
++len;
if(*str++ == ' ')++*spc;
}
return len;
}
int main(void){
char *a = "12 34 56";
size_t spc;
int a_l = my_strlen(a, &spc);
printf("str1: \"%s\" (%d)\n", a, a_l);
char *b = "___";
int b_l = strlen(b);
printf("str2: \"%s\" (%d)\n", b, b_l);
char *p, *o = malloc(a_l - spc + spc * b_l + 1);
p=o;
for (int i = 0; i < a_l; i++) {
if(a[i] == ' ') {
strncpy(p, b, b_l);
p += b_l;
} else {
*p++ = a[i];
}
}
*p = '\0';
printf("out: \"%s\"\n", o);
free(o);
return 0;
}
I see that many answers have been added, but this may have been done very simply with a single loop. Since the string is very short, you can sacrifice memory over CPU and allocate an array 3 times +1 bigger than the original string, and be sure that it won't be overflowed:
const char* string= "12 34 56";
size_t length= strlen(string);
char result[length*3 +1];
unsigned int index= 0;
memset(result, '\0', length*3+1);
for(int i=0; i<length; i++)
{
if(string[i]!= ' ')
{
result[index++]= string[i];
}
else
{
strcat(result,"___");
index+= 3;
}
}
I found another thread and after reading the answers, I figured out that the right line should look like this:
strncpy(o + i + b_l, a + i + 1, a_l - i);
And after few fixes that were suggested in this thread my code looks like this:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
char *a = "12 34 56";
size_t a_l = strlen(a);
printf("str1: \"%s\" (%d)\n", a, a_l);
char *b = "___";
size_t b_l = strlen(b);
printf("str2: \"%s\" (%d)\n", b, b_l);
for (int i = 0; i < a_l; i++) {
if (a[i] == ' ') {
char *o = malloc(a_l + b_l);
strncpy(o, a, i);
strcpy(o + i, b);
strncpy(o + i + b_l, a + i + 1, a_l - i);
printf("out: \"%s\"\n", o);
free(o);
}
}
return 0;
}
And this prints the desired putput.