Jump to content


 


Register a free account to unlock additional features at BleepingComputer.com
Welcome to BleepingComputer, a free community where people like yourself come together to discuss and learn how to use their computers. Using the site is easy and fun. As a guest, you can browse and view the various discussions in the forums, but can not create a new topic or reply to an existing one unless you are logged in. Other benefits of registering an account are subscribing to topics and forums, creating a blog, and having no ads shown anywhere on the site.


Click here to Register a free account now! or read our Welcome Guide to learn how to use this site.

Photo

Novice C Student, Need Help Reading Ascii Binary


  • Please log in to reply
13 replies to this topic

#1 zyrolasting

zyrolasting

  • Members
  • 45 posts
  • OFFLINE
  •  
  • Local time:12:15 AM

Posted 07 June 2008 - 12:07 AM

I've been trying to write several C apps for practice. They were all successful except for this one, which I am stumped.
I am reading a text file titled 'binary' on the C:\ root. In it are several hundred bytes (By that I mean many, many lines of 8-bit binary increments in normal text) that will be read.

It is format is to have each 8 bits typed on it's own line: i.e.

01010100
01101000
01101001

etc...

Here is the code.

#include <stdio.h>/*Read a text file for binary vals. Returns ASCII codes as of now.*/int readbi(char bytebi[]){     int i, res, val;     val = 128;     printf("val is %d\n","val");     for (i=0; i<=8; i++)     {         if (bytebi[i])         {                       res += val;                       printf("res is now %d\n","res");         }         val /= 2;         printf("val halved to %d\n","val");     }     printf("readbi returning %d\n","res");     return res;}int main(){    FILE *f;    int ret;    char s[10];    f = fopen("C:\\binary.txt","r");    if (!f)    {        printf("Error opening file.\n");        return 1;    }    while (fgets(s,9,f)!= NULL)    {        ret = readbi(fgets(s,9,f));        printf("ret is %d\n","ret");        printf("%d\n",ret);    }    fclose(f);    return 0;}

Please note that the several printf's are just a primitive debugging. I'm still learning.
My problem is noted in this screenie.

Posted Image

Noting different to see whenever I scroll about.
Right off the bat, I see that I need to move a line down in the text after each read (do not know how with text functions and \n newline specifically) and find out why readbi's val is being read incorrectly constantly. I figure a pointer comes in somewhere.

I do not know how to figure out ANY of that. That's where my issue stands.

Help is appreciated, as well as advice!

Edited by zyrolasting, 07 June 2008 - 12:11 AM.


BC AdBot (Login to Remove)

 


#2 M...

M...

  • Members
  • 386 posts
  • OFFLINE
  •  
  • Local time:08:15 PM

Posted 07 June 2008 - 06:02 PM

Hello zyrolasting,

printf("val is %d\n","val");


Just at first glance:

The format specification ("val is %d\n") expects the next argument to be an integer (int), and will print/interpret its value as a decimal number (%d). However, the actual argument you are supplying ("val") is a simple, constant character string.

The same is true for most of the other 'printf' statements.

Fix those 'printf' statements, and then you'll have a better chance of seeing what is actually occurring in the underlying input, arithmetic manipulation and looping.

#3 Alan-LB

Alan-LB

  • Members
  • 71 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Junee, NSW, Australia
  • Local time:03:15 PM

Posted 07 June 2008 - 10:11 PM

In the print statements you have "val", "res" and "ret" - remove the quotes. You are trying to print variables not charaters strings.

What is the purpose of val?

What do you expect your output to be - characters? hexadecimal? decimal?

Alan

Edited by Alan-LB, 07 June 2008 - 10:53 PM.

There are 10 types of people - those who understand binary and those who don't!!

Today is the Beta version of Tomorrow!

#4 zyrolasting

zyrolasting
  • Topic Starter

  • Members
  • 45 posts
  • OFFLINE
  •  
  • Local time:12:15 AM

Posted 07 June 2008 - 11:00 PM

In the print statements you have "val", "res" and "ret" - remove the quotes. You are trying to print variables not charaters strings.


Point taken. Thanks for that. I have another question about that, branching off slightly. The concept of strings managed in chars arrays were confusing to me, considering that in other coding languages I could just assign the string right off.

i.e. a = "This is my string.";

But juding from your response, are you saying that for some functions I could just type the string right off and if I had a char xxx[] parameter, it will take care of itself?
Again, not too experienced here.


Fix those 'printf' statements, and then you'll have a better chance of seeing what is actually occurring in the underlying input, arithmetic manipulation and looping.


Pretty much the same issue for the other things you've said (Thanks again for noticing), but can you clarify what you mean by this?

Alright. I tried removing the quotes. Now ret is being reported with no change. val is fixed, but is now being halved even to 0, bypassing the for loops limitation of 8.
Windows tells me it has encountered a problem and needed to close.

Here is the source again, but first let me ask about this statement in there...
f = fopen("C:\\binary.txt","r");
Is the second argument in fopen meant to be another control string?
#include <stdio.h>/*Read a text file for binary vals. Returns ASCII codes as of now.*/int readbi(char bytebi[]){     int i, res, val=128;     printf("val is %d\n",val);     for (i=0; i<=8; i++)     {         if (bytebi[i])         {                       res += val;                       printf("res is now %d\n",res);         }         val /= 2;         printf("val halved to %d\n",val);     }     printf("readbi returning %d\n",res);     return res;}int main(){    FILE *f;    int ret;    char s[10];    f = fopen("C:\\binary.txt","r");    if (!f)    {        printf("Error opening file.\n");        return 1;    }    while (fgets(s,9,f)!= NULL)    {        ret = readbi(fgets(s,9,f));        printf("ret is %d\n",ret);        printf("%d\n",ret);    }    fclose(f);    return 0;}

Edited by zyrolasting, 07 June 2008 - 11:01 PM.


#5 Alan-LB

Alan-LB

  • Members
  • 71 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Junee, NSW, Australia
  • Local time:03:15 PM

Posted 07 June 2008 - 11:52 PM

As far as Strings are concerned you would be better to refer to a textbook and read up on them. In C a string is an array of characters ending with the NULL (\0). This adds an extra character to the String length.

So -
str[5] = "Fred";
gives an array of 5 characters 'F', 'r', 'e', 'd', \0
str[3] is the character 'd' - the first index to the character array is 0.
Try here - http://www.acm.uiuc.edu/webmonkeys/book/c_....2.html#strings

If you want to display a string use %s - so
printf("My string is %s", str);
Try here - http://www.acm.uiuc.edu/webmonkeys/book/c_....12.html#printf
http://www.elook.org/programming/c/printf.html

Again with fopen, go to a textbook and read it up. The first argiment is the name of the file to be opened, the second argument is the mode in which you want to open the file -
r read
w write, create a file if it doesn't exist
a append to a file
b binary mode
and so on...
Try here - http://www.acm.uiuc.edu/webmonkeys/book/c_...2.12.html#fopen
http://www.elook.org/programming/c/fopen.html

Add getchar(); after fclose()
This will pause the program so that you can see the output - you will have to press Return to end the program.

You still dont say what you want the program to output

Alan.

Edited by Alan-LB, 08 June 2008 - 12:41 AM.

There are 10 types of people - those who understand binary and those who don't!!

Today is the Beta version of Tomorrow!

#6 zyrolasting

zyrolasting
  • Topic Starter

  • Members
  • 45 posts
  • OFFLINE
  •  
  • Local time:12:15 AM

Posted 08 June 2008 - 12:14 PM

Oh sorry, thought I made that clear. The program reads ASCII references to binary from a text file and returns the output of the values they represent. Simply an automated binary-to-ASCII.

10011101 returns 157, next line read... etc.
Should the range be within 32 and 126, I have a table for what is returned in another text file that will be managed as a char array. The indexes match the needed output.
01010101 = 85 = "U"

Thanks so much for the links, I'll check those out.
Is there anything else you can share with me?

#7 M...

M...

  • Members
  • 386 posts
  • OFFLINE
  •  
  • Local time:08:15 PM

Posted 08 June 2008 - 04:14 PM

1. The loop:

for (i=0; i<=8; i++)


will iterate 9 times, with the following values of 'i': 0,1,2,3,4,5,6,7,8.
I think that is probably one too many times.

2. In the routine 'readbi()', the integer variable 'res' is never initialized. Since it is on the stack (auto), it initially contains a random/undefined value. The first thing the program does to 'res' is add to it:

res += val;


In other words: 'res = res + val;', where the initial value of 'res' is undefined/random.

3. Since 'bytebi[]' is an array of characters, where each element of 'bytebi[]' contains the ASCII representation of the digit '0' or the digit '1', I don't think the following is doing what you want:

if (bytebi[i])


The binary value of the ASCII character '0' is not zero.

4. I think your main 'while' loop actually reads two strings/lines from the file for each iteration of the loop, and it effectivly ignores the first string/line read -- there are two 'fgets' being executed on each iteration of the 'while' loop. This results in the program effectively processing every OTHER line from the input file.

#8 zyrolasting

zyrolasting
  • Topic Starter

  • Members
  • 45 posts
  • OFFLINE
  •  
  • Local time:12:15 AM

Posted 08 June 2008 - 05:22 PM

Progress. Info is really appreciated! However, I'm not in the clear yet.
Alright. Here is the source I edited from your observations, M...

         {
res += val;
printf("res is now %d\n",res);
}
val /= 2;
printf("val halved to %d\n",val);
}
printf("readbi returning %d\n",res);
return res;
}

int main()
{
FILE *f;
int ret;
char s[10];
f = fopen("C _linenums:0'>#include <stdio.h>/*Read a text file for binary vals. Returns ASCII codes as of now.*/int readbi(char bytebi[]){ int i, res=0, val=128; printf("val is %d\n",val); for (i=0; i<=7; i++) { if (bytebi[i]='1') { res += val; printf("res is now %d\n",res); } val /= 2; printf("val halved to %d\n",val); } printf("readbi returning %d\n",res); return res;}int main(){ FILE *f; int ret; char s[10]; f = fopen("C:\\binary.txt","r"); if (!f) { printf("Error opening file.\n"); return 1; } do { ret = readbi(fgets(s,8,f)); printf("ret is %d\n",ret); printf("%d\n",ret); } while (ret!= NULL); fclose(f); return 0;}

Here is a screen shot of the repetitive behavior.

Posted Image

Does not change pattern. Alright. It's pretty obvious. Val is ALWAYS being added.
Also, val becoming 0 has been fixed. I made the for loop end condition < rather than <=, so ignore that tidbit in the code box there.
The other problems still remain.

if (bytebi[i] = '1') has been tried with a single and double quote with no change, so I guess that test was pointless.
Let me note other peculiar behaviors. Windows still tells me that the .exe has encountered a problem and needed to be closed.
A difference to note is that the script whizzed by for a longer period of time. My only guess to note now is my text file's formatting. It was written loosely, having multiple bytes represented on one line.
I assumed fgets would read the first 8 regardless, and my concern is not necessarily accuracy now.
So I renamed the file to binary2.txt and made a new one. I only put...

10011000
01010101
11111111
00110101

Each entry is on it's own line.
I tried this by getting fgets 2nd argument to 8 and 9.
The pattern did not change either way, but this time the program did the readbi() function ONCE and Windows informed me of another fatal error.
Am I missing a function, namely one to target the next line for reading? Am I bypassing some range? Are null characters at the end of each line disrupting the program?

Brain pain.

Edited by zyrolasting, 08 June 2008 - 05:27 PM.


#9 M...

M...

  • Members
  • 386 posts
  • OFFLINE
  •  
  • Local time:08:15 PM

Posted 08 June 2008 - 06:43 PM

1.

if (bytebi[i]='1')


contains an assignment expression, which you probably don't want in this context. It is an easy mistake to make and quite often easily overlooked.

2. In:

do
{
   ret = readbi(fgets(s,8,f));
   printf("ret is %d\n",ret);
   printf("%d\n",ret);
}
while (ret!= NULL);

the value returned by 'fgets' is not being saved for later checking. The assignment to 'ret', which is later checked for termination of the loop, is actually the value returned by the 'readbi' function.

You need to restructure this so that a) 'readbi' is not called when 'fgets' returns NULL, and b) the loop termination check should be based on the value returned by 'fgets', not on the value returned by 'readbi'.

HINT: Except in the case of a return value NULL (EOF or error), 'fgets' returns the value of its first argument (i.e., 's' in this case).

3. With respect to your last question, see the Remarks section (the entire section) in the description at the following link:

http://msdn.microsoft.com/en-us/library/c37dh6kf.aspx

Particularly important in the above is the phrase "..., whichever comes first".

#10 zyrolasting

zyrolasting
  • Topic Starter

  • Members
  • 45 posts
  • OFFLINE
  •  
  • Local time:12:15 AM

Posted 08 June 2008 - 09:18 PM

Alrighty, let me see if I get what you are saying.

if (bytebi[i]=="1") Doy, of course. :thumbsup:

the value returned by 'fgets' is not being saved for later checking. The assignment to 'ret', which is later checked for termination of the loop, is actually the value returned by the 'readbi' function.
You need to restructure this so that a) 'readbi' is not called when 'fgets' returns NULL, and :flowers: the loop termination check should be based on the value returned by 'fgets', not on the value returned by 'readbi'.


Alright, so my mistake was that the while loop expected the 8-char string while my structure granted it an integer as returned by my function. Got it.
I assume this is the fix.

while (fgets(s,8,f) != NULL)
{
ret = readbi(fgets(s,8,f));
printf("ret is %d\n",ret);
printf("%d\n",ret);
}

HINT: Except in the case of a return value NULL (EOF or error), 'fgets' returns the value of its first argument (i.e., 's' in this case).


I'm having a bit of difficulty understanding that. Wouldn't 's' be blank in itself at that point, or are you saying that the return is applied to 's'? The implication I got from your statement here is that 's'
is being returned to me, when I have a text file to worry about.

I also got that former bit of info from your link, (Thanks, good reference) but it still is not really answering my question. If I could reword it, how does C prepare itself to read the next line of a text file?
What I got from the page was that fgets() includes the newline character. Alright, so what does that mean for my structure? Do I have to type my input file like this, thus allowing say printf() to display them properly?

10011000\n
01010101\n
11111111\n
00110101

...Or does C use fgets, get the string and prepare itself to read the next line anyway?
Oh, and as for the edit's effect? Thrilled to say it's much cleaner and is showing signs of actually doing something.
Posted Image
As it seems from the low amount of repeated patterns and the visibility of both command prompt entries Windows did not complain about a fatal error and the loops met the number of lines in my document.
So, I guess I answered my own question about new lines. But can you still clarify what newline characters exactly do for me if I were to type it like above?
Alright. The next thing is that 0 is always returned. Now, I want to point out something my compiler warned me of at that build.

in function readbi()
Line 12: comparison between pointer and integer.

Great. Pointers. I understand them except for their relationship with arrays.
So my problem is here...

if (bytebi[i]=="1")

res += val obviously lost use. What is wrong with my condition now?
My head now turned to a question mark.
Oh, and what the hell was I thinking here?
printf("ret is %d\n",ret);
printf("%d\n",ret);

Gah.

Edited by zyrolasting, 08 June 2008 - 09:23 PM.


#11 M...

M...

  • Members
  • 386 posts
  • OFFLINE
  •  
  • Local time:08:15 PM

Posted 09 June 2008 - 09:31 AM

1. The expression

if (bytebi[i] == "1")

is comparing a single character/byte, bytebi[i], to the starting address of a string literal, "1". Strings are stored in memory as a NULL-terminated array of characters, and the "value" of a string is the address of (pointer to) the first element in that array. In this case, you want to be comparing a single character to a single character:

if (bytebi[i] == '1')

NOTE: When a reference is made to a single character/byte, as in bytebi[i], the compiler usually "widens" that byte value to an integer. That is why the compiler is issuing the warning message. Essentially, the program is comparing apples to oranges.

2. If you are creating the input file in a text editor, the newline character is automatically and "invisibly" placed at the end of each line (i.e., when you press the 'Enter' key on the keyboard when typing the lines in the file).

3. The following code (the last posted revision)

while (fgets(s,8,f) != NULL)
{
ret = readbi(fgets(s,8,f));
printf("ret is %d\n",ret);
printf("%d\n",ret);
}

again essentially processes (calls readbi() for) every other line in the file. The fgets in the while expression at the top of the loop checks for EOF, but ignores the characters that were read into s[], because the next line of the loop calls fgets again and overwrites s[].

EDIT: The above loop may actually seem to work, but it is only reading, at most, 7 bytes of data from the file each time fgets is called. Carefully review the description of fgets again. You might be better off using something like:



char s[15];

....

..... fgets(s,15,f) ..... or ...... fgets(s,sizeof(s),f) .......



Remember that fgets will stop reading when it encounters the newline character in the file.

Edited by M..., 09 June 2008 - 09:54 AM.


#12 zyrolasting

zyrolasting
  • Topic Starter

  • Members
  • 45 posts
  • OFFLINE
  •  
  • Local time:12:15 AM

Posted 09 June 2008 - 12:53 PM

A little syntax mistake goes a long way. Just to ask, with the difference between double and single quotes in a comparison... Are you saying that double quotes check the heap, or the address matching that comparison? In other words, if I type that same if statement you have just now corrected with double quotes, does it check the address by that quote? That was a little off-topic, but may be nice to know.
Alright, so now I finally registered that the string is a char array. Took me long enough, right? :thumbsup:

Alright, so as for my loop I see where you are coming from. My experience in another coding languages (most are engine-specific) have led me to believe that checked expressions are boolean in all occasions, but do not take action with the expression if it contains a function. If I'm understanding you correctly, the expression of my while loops is checked, but s receives it's assignment there anyway.

But that brings up a new question... My last run make it apparent that there were 4 runs of the loop. There were 4 lines in the file.
I understand that s can be overwritten to read the next line, but wouldn't the loop break after two runs in that case?

Alright, I am now trying this source.

         {
res += val;
}
val /= 2;
}
return res;
}

int main()
{
FILE *f;
int ret;
char s[10];
f = fopen("C _linenums:0'>#include <stdio.h>/*Read a text file for binary vals. Returns ASCII codes as of now.*/int readbi(char bytebi[]){ int i, res=0, val=128; for (i=0; i<8; i++) { if (bytebi[i]=='1') { res += val; } val /= 2; } return res;}int main(){ FILE *f; int ret; char s[10]; f = fopen("C:\\binary.txt","r"); if (!f) { printf("Error opening file.\n"); return 1; } while (fgets(s,9,f) != NULL) { printf("string is %s\n",s); printf("ret is %d\n",readbi(s)); } fclose(f); return 0;}

Here is the Command Prompt's response. Kind of sick of uploading images. Completely forgot normal clipboard operations can be done there, gah.
As you can see, this is really close.

string is 10011000ret is 152string isret is 24string is 01010101ret is 85string isret is 21string is 11111111ret is 255string isret is 63string is 00110101ret is 53

But what about the strange returns of s? s becomes blank, and I think i changed my loop ends appropriately...
Is there a condition that here that forced another newline? I notice the blank s also makes 2 new lines when a proper run has space between each line.
This does not happen at EOF. What can cause this? I left my text file with only binary lines, and they are not double-spaced.

Edited by zyrolasting, 09 June 2008 - 01:03 PM.


#13 M...

M...

  • Members
  • 386 posts
  • OFFLINE
  •  
  • Local time:08:15 PM

Posted 09 June 2008 - 02:56 PM

You're almost there, and your program is operating correctly, but not exactly the way you want it to.

A text file (which is what you're dealing with) is treated as a linear stream of bytes (characters) by fgets. These bytes include not only the "data" bytes (i.e., the '0' and '1' characters you typed as you created the file), but also the newline control character/byte ('\n') which signifies the end of one line and the beginning of the next line.

Each character in the line below represents a linear view of the contents of your file, where each 0 or 1 is the character you typed into the file and \n represents the single-byte newline character stored in the file at the end of each line (i.e., what was placed in the file when you pressed the 'Enter' key on the keyboard to end a line and begin the next line):

10011000\n01010101\n11111111\n00110101


The C function fgets "sees" just a sequence of bytes. The 2nd argument to fgets represents the size of the buffer into which the bytes read from the stream/file will be placed. fgets always constructs a valid C string ('\0'-terminated) and fgets needs to make sure there is room for that string-terminator byte in the buffer it builds. That is why it processes, at most, n-1 characters/bytes from the file at each call.

Your program currently specifies of size of 9 in the call to fgets. In the first call, fgets reads the first 8 bytes from the file (the 0's and 1's you typed into the file), places the '\0' string-terminator at the end of that buffer and returns the result to your program.

At the very next call to fgets, again specifying a buffer size of 9, the file position maintained internally by fgets is positioned at the newline character ('\n') in the file following the characters/bytes that were previously read. fgets retrieves the '\n' character, places it into the buffer provided in the call, adds a '\0' as the next character in that buffer (to create a valid '\0'-terminated string) and returns the result to your program. What the program "sees" at that point is a valid C string containing the single newline character ('\n'). That explains the double-spaced output, and also uncovers a few bugs in the readbi() function: What happens if readbi() is passed a string containing bytes/characters other than '0' or '1', or the string contains too few bytes (i.e., not exactly 8)?

The above pattern repeats, explaining the seemingly strange output you are seeing.

In a simple case such as this, it is probably easiest to simply declare a buffer larger than any line you expect to process from the file (i.e., 15 bytes), and let fgets automatically "terminate" each call at each newline character ('\n') in the file. In a real-life program, there needs to be much more input validity checking, parsing, etc., but you're learning.

Also remember that fgets does return the newline character ('\n') as just another byte in the string, so you need to process it appropriately.

You might want to look at the following. I glanced at a few parts and it seems reasonably well-written, along with many useful pictures. The first link is for the Web view of the article and the second link is for the printable view:

http://computer.howstuffworks.com/c.htm

http://computer.howstuffworks.com/c.htm/printable

#14 zyrolasting

zyrolasting
  • Topic Starter

  • Members
  • 45 posts
  • OFFLINE
  •  
  • Local time:12:15 AM

Posted 09 June 2008 - 08:36 PM

Very, very much obliged. I do think I can take this under my wing and see if I can improve on it.
Thanks so much for your time, it is much appreciated.

Oh, and I've been to howstuffworks. I read the entire C tut, learned the basics of pointers there, but other things still did not seem clear to me. (Namely this topic, strings)
I've been familiar with other languages, and the help I got in this topic helped me see more to how the behavior flows. I'll try re-reading the tutorial and seeing if it's clearer!

Edited by zyrolasting, 09 June 2008 - 08:39 PM.





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users