2

I am trying to convert a decimal number (329.39062) to binary (exponent, mentissa). I keep getting segmentation fault. on running the gdb test, It shows me feof. I have changed alot but it keeps showing me the segmentation fault at the same point. Where am i going wrong? Thank you for all the help.

#include <stdio.h>
#include <stdlib.h>

char* valueToConvert(int value);

int main(int argc, char *argv[])
{
        FILE* input;
        FILE* output;

        input = fopen(argv[1],"r");
        output = fopen(argv[2],"w");

    float value;
    unsigned char *charValue = (unsigned char *) &value;
    int exponentValue;
    long mantissaValue;

    while(!feof(input))
    {
        fread(&charValue, sizeof(float),1, input);
        exponentValue = ((charValue[0] & 0x7F) << 1)|((charValue[1] & 0x80) >> 7);  
        mantissaValue = ((charValue[1] & 0x7F) << 8)|((charValue[2] & 0xFF) <<8) | (charValue[3] & 0xFF);
        fprintf(output,"%d %s %s\n",(charValue[0] & 0x80 >> 7),valueToConvert(exponentValue - 127),valueToConvert(mantissaValue));
    }
}

char* valueToConvert(int value)
{
    int counter = 0;
    char* conversion = calloc(32,sizeof(int));
    while(value>0)
    {
        if((value%2 == 1) && (value%2 != 0))
        {
            conversion[31 - counter++] = '1';
        }
        if((value%2 == 0) && (value%2 != 1))
        {
            conversion[31 - counter++] = '0';
        }
        value = value/2;
    }
    return conversion;
}
Mani
  • 51
  • 1
  • 2
  • 9
  • 2
    [Which floating-](http://en.wikipedia.org/wiki/Single_precision_floating-point_format)[point standard](http://en.wikipedia.org/wiki/Double_precision_floating-point_format) [were you using?](http://en.wikipedia.org/wiki/Quadruple_precision_floating-point_format) – Makoto Mar 30 '13 at 06:22
  • Shouldn't `fread(&charValue, sizeof(float),1, input);` be `fread(charValue, sizeof(float),1, input);`? – user123 Mar 30 '13 at 06:25
  • i think i am using IEEE 754 – Mani Mar 30 '13 at 06:26
  • @Magtheridon96 i dont know how i missed that, thank you. That does solve the segmentation fault but i dont get the correct output. – Mani Mar 30 '13 at 06:28
  • "while(!feof(input))" is the wrong way to check for end of file in C. – Thomas Padron-McCarthy Mar 30 '13 at 06:31
  • @ThomasPadron-McCarthy, but when using input file, i cant using EOF, since it returns an integer, where as feof gets the file pointer. What else could i use ? if not feof? – Mani Mar 30 '13 at 06:32
  • @Mani: Read until fread fails: while (fread(charValue, sizeof(float), 1, input) == 1) ... – Thomas Padron-McCarthy Mar 30 '13 at 06:33
  • also i have a question, i have not freed the memory i just noticed, does that , can it effect the output? – Mani Mar 30 '13 at 06:34
  • @ThomasPadron-McCarthy, could you explain me a little bit about the difference? i read online just now i think i am a bit confused on that part. Also if i used fread, my output its 1 1, where as earlier it was 1 1 0. Though the output is wrong. Whats the difference? thank you for the help. I highly appreciate it. – Mani Mar 30 '13 at 06:37
  • @Mani: feof returns true not when the last item has been read from the file, but after the first _failed_ attempt to read. So a loop on !feof will make one iteration too many. See also http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong – Thomas Padron-McCarthy Mar 30 '13 at 07:25

1 Answers1

1

The problem is here:

fread(&charValue, sizeof(float),1, input);

That should be

fread(charValue, sizeof(float),1, input);

Because charValue is a pointer.


To address your problems with the output, you're filling the buffer backwards after initializing it completely with 0 via calloc, so fprintf is hitting 0 (a char used to signify the end of a string) and stopping "prematurely".

Here's a fast binary string function:

void fast_d2b(int x, char* c) {
    int i;
    for (i = 31; i >= 0; --i) {
        *(c++) = '0' + ((x >> i) & 0x1);
    }
}

It's based on the one shown here. Only differences are that my variation doesn't write to the buffer backwards and it writes '0' and '1' instead of integral values 0 and 1.

user123
  • 8,970
  • 2
  • 31
  • 52
  • i agree, i am sorry i should have seen that, but i missed it. on running the file i get the output as 1 1 0 in 3 lines. why could that be? – Mani Mar 30 '13 at 06:29
  • That's because `calloc` is initializing the values of the `char*` you're allocating to `0`, simulating an end-of-string. Also, you're filling the `char*` backwards, leaving the initialized `0`s in the beginning causing `fprintf` to print the part of the `char*` that you _didn't_ manipulate. – user123 Mar 30 '13 at 06:36
  • so if i do a memory free towards the end, ( before the return statement) , will that help? – Mani Mar 30 '13 at 06:38
  • Thank you for the link, i have a question regarding your previous comment. i ddn get filling the char* backward statement, if you could tell me what you meant, will be of great help. – Mani Mar 30 '13 at 06:57
  • It means you're filling the `conversion` array starting from index `31` and approaching `0` because `counter` is initially `0`. – user123 Mar 30 '13 at 06:58
  • thank you for the explaining. I am still going wrong somewhere as i am not getting the correct output, could you please hint me towards that? – Mani Mar 30 '13 at 07:00
  • Could you added the updated version of the code in the question? (Link to a pastebin of it) – user123 Mar 30 '13 at 07:31
  • i have not changed my code much, except the '&' sign in fread. – Mani Mar 30 '13 at 14:18
  • You still need to use something like the fast_d2b function to get a binary string with bits starting from index 0 so you can validly print it. – user123 Mar 30 '13 at 19:00
  • I am sorry, i dont understand where i can put this code in my code. if you could help – Mani Mar 30 '13 at 19:05
  • All what the function does is take an `int` and a desired buffer (`char*`) and it converts that `int` to a binary string and stores it in that passed buffer. Yes, it will work for anything. – user123 Mar 30 '13 at 19:23