converted string failed to contain correct values of float - c

I am facing problem in converting float to char*.
I have written a function that will put integer part of float in string and then decimal values. I need it for two places of decimal. But something is horribly wrong. Either it ouputs integer value or just 1 place after decimal. Can someone please guide me?
Below is my attempt
void float_to_str(char *str, float f, char size)
{
char pos; // position in string
char len; // length of decimal part of result
char* curr; // temp holder for next digit
int value, i ; // decimal digit(s) to convert
float temp;
pos = 0; // initialize pos, just to be sure
value = ( int )f; // truncate the floating point number
snprintf( curr, sizeof(curr), "%d", value);
strncmp( str, curr, strlen( curr ) );
// now str array has the digits before the decimal
if (f < 0 ) // handle negative numbers
{
f *= -1;
value *= -1;
}
len = strlen( str );
pos = len; // position the pointer to the end of the integer part
str[pos++] = '.'; // add decimal point to string
f = f -( float ) value + 0.005;
printf( " the value of f = %f\n", f );
for( i = 0; i < size; ++i )
{
temp = f* 10;
value = ( int )temp ;
snprintf( curr, sizeof(curr),"%d", value );
str[ pos++ ] = *curr;
}
str[ pos ] = '/0';
printf(" debug --> the string is %s \n", str ); // prints only 5 instead of 6455.56
}
int main()
{
float test = 555564.5555;
char arr[ 40 ];
memset(arr, 0, 40 );
FloatToStringNew( arr,test, 2 );
printf( " the float to string is %s", arr ); // OUT Put is 5 which is wrong
return 0;
}

The entire float_to_string can be reduced to (as suggested by BLUEPIXY):
void float_to_str(char *str, float f, char size)
{
sprintf(str, "%.*f", size, f);
}
However, if you are interested in the bug in your code, it is in the for loop:
for( i = 0; i < size; ++i )
{
temp = f* 10; // Value of f stays the same in every iteration
value = ( int )temp ;
snprintf( curr, sizeof(curr),"%d", value );
str[ pos++ ] = *curr;
}
Fix:
for( i = 0; i < size; ++i )
{
f = f * 10; // Modify f each iteration
value = ( int )f;
snprintf( curr, sizeof(curr),"%d", value );
str[ pos++ ] = *curr;
f = f - (int)f; // Remove the integer part
}
Edit:
There are a couple of other stuff in the function that needs fixing:
strncmp should be strcpy
pos should be of type int or size_t
curr should be an array instead of a pointer.
The call from main should be to float_to_string, not FloatToStringNew
The compiler helped me locate them when I compiled with warnings (I used -Wall in gcc).

Related

C string is empty after assignment

I was trying to solve a coding problem to covert an integer to a string using C. e.g. if there is an integer 321, then the function should return a string "321". My character assignment seems to be successful based on the output during the assignment. However, once the assignment is complete, my string is completely empty. Not sure why this would be happening. I am guessing it has something to do with the null terminating character?
char * solution(int X) {
printf("x is %d\n", X);
int len = len_num (X); //Returns correct length as tested.
printf("Length is %d\n", len);
char * str = (char*)malloc( (++len * sizeof(char)) ); //one extra space for '\0'
str[len] = '\0'; //Assigning the last character as null terminating character '\0'
int i = len - 1 ;
do
{
int n = X%10;
str[i] = '0' + n;
printf("str[%i]:%c, n:%d.\n", i, str[i], n);
X = X / 10;
i--;
}while (i > 0);
printf("\nstr:%s.\n", str);
return str;
}
Output:
x is 942
Length is 3
str[1]:2, n:2. <---- All assignments are successful
str[2]:4, n:4.
str[3]:9, n:9.
str:. <----This shouldn't be empty!
You have some off-by-one errors.
The first is here:
char * str = (char*)malloc( (++len * sizeof(char)) ); //one extra space for '\0'
str[len] = '\0'; //Assigning the last character as null terminating character '\0'
You allocate enough space, but because len was incremented str[len] is off the end of allocated memory, and writing to caused undefined behavior. You instead want:
char * str = malloc( len + 1 );
Noting that you shouldn't cast the return value of malloc and that sizeof(char) is defined to be 1.
Related to this, at the bottom of the loop you decrement i and then check if it is greater than 0. This means you never write to element 0 of the array. You want:
do
{
...
}while (i >= 0);
For starters this statement
str[len] = '\0';
writes beyond the allocated character array that was allocated in this declaration using the sub-expression ++len.
char * str = (char*)malloc( (++len * sizeof(char)) );
So already the program has undefined behavior.
Also due to the condition of the while loop
while (i > 0);
you never set the element of the array str[0].
As the function parameter has the signed integer type int then the user can pass a negative number. You should process such a situation correctly.
The function can look the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
size_t len_num( int x )
{
const int Base = 10;
size_t n = 0;
do
{
++n;
} while ( x /= Base );
return n;
}
char * solution( int x )
{
const int Base = 10;
size_t len = len_num( x );
int sign = x < 0;
if ( sign ) ++len;
char *s = (char * )malloc( len + 1 );
if ( s )
{
s[len] = '\0';
do
{
s[--len] = ( sign ? -( x % Base ) : ( x % Base ) ) + '0';
} while ( x /= Base );
if ( sign ) s[--len] = '-';
}
return s;
}
int main(void)
{
int x = 12345;
char *s = solution( x );
if ( s ) puts( s );
free( s );
x = -12345;
s = solution( x );
if ( s ) puts( s );
free( s );
return 0;
}
The program output is
12345
-12345

C: Trying to insert a struct into a struct array

in my code I have student profiles with name, age, and GPA. I also have an array with each profile. I'm trying to create an insert function that inserts another student profile into the array and display an error if the index is not valid. I'm trying to do so by moving adding another space in the array for the new student, then moving over the places of students occupying the wrong space by one space to the right.
Ex. If I want to put a student in index 2, the function would move the student occupying that space to 3, and the student in 3 would be moved to space 4.
Here's what I have so far, but I'm getting an error on array[i+1] = isaying "incompatible types when assigning to type Student from type type int." I tried changing i to type Student, I got several more errors all over the loop saying that it was an invalid initializer and that I couldn't use >=, and that i was the "wrong type to decrement
For starters it is unclear why the parameter index has the signed type int instead of the unsigned type size_t. The unsigned type allows to avoid this redundant check
if (index < 0 || index > *size) {
^^^^^^^^^
Also if the value of index is greater than the current value of *size then it is enough just to append the passed item to the array.
So in general this check
if (index < 0 || index > *size) {
is redundant.
The function declaration is too complicated. There is no need to return pointer to the first element of the passed array. The function declaration will look more simpler if to write it like
size_t insert( Student a[], size_t n, size_t i, const Student *student );
That is the function returns the new size of the updated array.
This statement
array[i+1] = i;
does not make any sense because the left operand has the type Student while the right operand has the type int. Moreover it has a logical error because instead of the index i + 1 you have to use the index i.
And instead of the manually written loop you could use the standard C function memmove.
Here is a demonstrative program that shows how the function can be defined.
#include <stdio.h>
#include <string.h>
#define MAX_LEN 10
typedef struct Student
{
char name[MAX_LEN];
unsigned int age;
} Student;
size_t insert( Student a[], size_t n, size_t i, const Student *student )
{
if ( n < i ) i = n;
if ( i < n )
{
memmove( a + i + 1, a + i, ( n - i ) * ( sizeof( Student ) ) );
}
a[i] = *student;
return ++n;
}
int main(void)
{
enum { N = 10 };
Student a[N] = { 0 };
Student student = { "A", 20 };
size_t n = insert( a, 0, 0, &student );
for ( size_t i = 0; i < n; i++ )
{
printf( "{ %s, %u } ", a[i].name, a[i].age );
}
putchar( '\n' );
strcpy( student.name, "B" );
++student.age;
n = insert( a, n, 0, &student );
for ( size_t i = 0; i < n; i++ )
{
printf( "{ %s, %u } ", a[i].name, a[i].age );
}
putchar( '\n' );
strcpy( student.name, "C" );
++student.age;
n = insert( a, n, 2, &student );
for ( size_t i = 0; i < n; i++ )
{
printf( "{ %s, %u } ", a[i].name, a[i].age );
}
putchar( '\n' );
strcpy( student.name, "E" );
++student.age;
n = insert( a, n, 1, &student );
for ( size_t i = 0; i < n; i++ )
{
printf( "{ %s, %u } ", a[i].name, a[i].age );
}
putchar( '\n' );
return 0;
}
The program output is
{ A, 20 }
{ B, 21 } { A, 20 }
{ B, 21 } { A, 20 } { C, 22 }
{ B, 21 } { E, 23 } { A, 20 } { C, 22 }
The used indentation style makes it difficult to easily see if the parenthesis are correctly closed. Please use an automatic formatter, example: clang-format
Your function is not very safe. It should take another parameter max_size so the assigned memory is known
If a return is used in if branch, the else branch does not have to be explicitly declared.
A for loop already has a condition, if the only functionality in the loop is an if, it can be hoisted up into that condition.
To move students from a place in an array a "copy" of the student has to be made to the new location - not just it's index.
Fixed:
Student* insert(Student* array, int max_size, int* size, int index, Student s)
{
//error message and return NULL if space is - or > array size
if (index < 0 || index > *size || *size + 1 > max_size)
{
printf("ERROR\n");
array = NULL;
return array;
}
for (int i = *size; i > index && i > 0; --i)
{
//move students at index or > over to make open space
array[i] = array[i - 1];
}
//put new student in correct location
array[index] = s;
*size += 1;
return array;
}

odd or even number using pointer in C

I have an array, the elements inside this array should be assigned randomly
then I create two more arrays one for odd and one for even numbers
using pointers I want to put the odd numbers inside the odd array, and the even numbers in the even one.
how can I assign it using pointers?
I came up with this:
int main()
{
int array[10];
int *arrayPtr = &array;
int arrayEven[10];
int *pEven = &arrayEven;
int arrayOdd[10];
int * pOdd = &arrayOdd;
int i, j;
for(i=0; i<10; i++)
{
array[i] =rand()%100 ;
if(array[i] %2 ==0)
{
printf("%d\n", array[i]);
printf("Even number");
}
else
{
printf("%d\n", array[i]);
printf("Odd number");
}
}
These declarations of pointers
int *arrayPtr = &array;
int *pEven = &arrayEven;
int * pOdd = &arrayOdd;
are incorrect. The initializers have the type int( * )[10] according to the declarations of the arrays as for example of the variable array
int array[10];
while the declared pointers has incompatible type int *.
What you need is declarations like this
int *arrayPtr = array;
There is no great sense to define arrays of the same size as the source array because for example the source array can have no odd or even numbers. You should deal with arrays depending on the number of odd and even numbers in the source array. If your compiler supports variable length arrays then you can use them. Or you should dynamically allocate arrays.
Here is a demonstrative program that shows how the assignment can be done using variable length arrays and pointers.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void copy_if( const int a1[], size_t n, int *a2, int *a3, int predicate( int ) )
{
for ( const int *p = a1; p != a1 + n; ++p )
{
if ( predicate( *p ) )
{
*a2++ = *p;
}
else
{
*a3++ = *p;
}
}
}
size_t count_if( const int a[], size_t n, int predicate( int ) )
{
size_t cnt = 0;
for ( const int *p = a; p != a + n; ++p )
{
if ( predicate( *p ) ) ++cnt;
}
return cnt;
}
int is_even( int x )
{
return x % 2 == 0;
}
int main(void)
{
enum { N = 10 };
int a1[N];
srand( ( unsigned int )time( NULL ) );
for ( int *p = a1; p != a1 + N; ++p )
{
*p = rand() % N;
}
for ( const int *p = a1; p != a1 + N; ++p )
{
printf( "%d ", *p );
}
putchar( '\n' );
size_t cnt = count_if( a1, N, is_even );
if ( cnt != 0 && cnt != N )
{
int a2[cnt];
int a3[N-cnt];
copy_if( a1, N, a2, a3, is_even );
for ( const int *p = a2; p != a2 + cnt; ++p )
{
printf( "%d ", *p );
}
putchar( '\n' );
for ( const int *p = a3; p != a3 + N - cnt; ++p )
{
printf( "%d ", *p );
}
putchar( '\n' );
}
return 0;
}
The program output might look like
6 3 3 8 3 0 5 5 3 2
6 8 0 2
3 3 3 5 5 3
If to use your straightforward approach then the program can look the following way
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
enum { N = 10 };
int array[N];
int *arrayPtr = array;
srand( ( unsigned int )time( NULL ) );
for ( int *p = arrayPtr; p != arrayPtr + N; ++p )
{
*p = rand() % N;
}
for ( const int *p = arrayPtr; p != arrayPtr + N; ++p )
{
printf( "%d ", *p );
}
putchar( '\n' );
int arrayEven[10];
int *pEven = arrayEven;
int arrayOdd[10];
int *pOdd = arrayOdd;
int *pEvenEnd = pEven;
int *pOddEnd = pOdd;
for ( const int *p = array; p != arrayPtr + N; ++p )
{
if ( *p % 2 == 0 )
{
*pEvenEnd++ = *p;
}
else
{
*pOddEnd++ = *p;
}
}
for ( const int *p = pEven; p != pEvenEnd; ++p )
{
printf( "%d ", *p );
}
putchar( '\n' );
for ( const int *p = pOdd; p != pOddEnd; ++p )
{
printf( "%d ", *p );
}
putchar( '\n' );
return 0;
}
Its output might look for example like
1 0 0 3 4 5 2 1 9 5
0 0 4 2
1 3 5 1 9 5
For it to work you need two additional coutner variables
int oddCount, evenCount;
these need to be initialized to be 0 (i.e. how many odd/even number you have inserted so far). Then while iterating your first array you increment the respective coutner if you encounter an even/odd number. Also you can just use these variables to know where you need to put the next even/odd number in their respective array.
You can use binary comparison since all odd finish by 1 in binary mode :
If( a & 1)
//Odd
Else
//Even

Concatenating a char in a recursive function in C

Even though I have more experience with higher level languages, I am having a lot of troubles understanding how memory allocation and how strings really work in C.
I am trying to implement a very simple base converter that works recursively. The only thing is that it should return a char* instead of an int
Here is my code. I already tested the recursive calls and it works if I use integers. So, the problem is definitely with the string part. It gives me an infinite loop.
char* baseConversion(int num, int baseIn, int baseOut){
//convert num to base ten
int quotient = num / baseOut;
int remainder = num % baseOut;
char rem = (char)(((int)'0') + remainder);
char *result = malloc(strlen(output) + 1);
strcpy(result, rem);
if (quotient == 0)
return result;
else
return strcat(result, baseConversion(quotient, baseIn, baseOut));
}
Many thanks
Change:
strcpy(result, rem);
to:
result[0] = rem;
result[1] = 0;
This will create a single-character string containing the character in rem.
You also may need to fix:
malloc(strlen(output)+1)
as there's no variable named output in your function.
If I have understood correctly what you are saying about then what you need is the following
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * baseConversion( unsigned int x, unsigned int base )
{
unsigned int digit;
char *p = NULL;
size_t n = 2;
if ( base > 10 || base < 2 ) base = 10;
digit = x % base;
if ( x / base ) p = baseConversion( x / base, base );
if ( p ) n += strlen( p );
p = realloc( p, n );
*( p + n - 2 ) = digit + '0';
*( p + n - 1 ) = '\0';
return p;
}
int main(void)
{
unsigned int x = 255;
char *p = baseConversion( x, 10 );
printf( "%s\n", p );
free( p );
p = baseConversion( x, 8 );
printf( "%s\n", p );
free( p );
p = baseConversion( x, 2 );
printf( "%s\n", p );
free( p );
return 0;
}
The output is
255
377
11111111
P.S. It is funny when one answer is marked as the best but the code will be used from other answer.:)

C - Printing combinations in an array or list

I made a program that takes a string of characters, and prints out all the possible combinations of them. However, is there a way to record each combo in a list or an array instead of just printing them on screen? Because I need to be able to manipulate some of the combos rather than just looking at them.
void swap( char *a, char *b ){
char tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void permutation( char *c, int d, int e ){
int f;
if( d == e )
printf( "%s\n", c );
else{
for( f = d; f <= e; f++ ){
swap( ( c + d ), ( c + f ) );
permutation( c, d + 1, e );
swap( ( c + d ), ( c + f ) );
}
}
}
int main(){
char wordInput[25];
int len, arrLen, f;
printf( "\nEnter text: " );
gets( wordInput );
len = strlen( wordInput );
arrLen = len - 1;
permutation( wordInput, 0, arrLen );
return 0;
}
Just change permuation() to the following:
int permutation( char *c, int d, int e, int n, char **permuted_strings)
where n is the index of the next unused element in your array permuted_strings. permuted_strings should be an array of k! elements if your string has length k, as indicated in a comment. If your condition (d == e) is met, then you should save the string at permuted_strings[n] and increment n by 1 and return this value as the new value for n. The permutation() function should always return the current value of n, and n should be reset to the return value of permutation() when it is called, so that subsequent calls to permutation() know the correct value of n, i.e. where to store the next string.

Resources