I'm trying to read the following binary (01100001) from a file and convert it to ascii code (97), but when using fread i'm getting a very big numbers.
the file "c:/input.txt" contain only the following line -01100001
printf of the array values print big numbers, such as 825241648
My code:
int main()
{
unsigned int arr[8];
int cnt,i,temp=0;
FILE * input;
if(!(input=fopen("C:/input.txt","r")))
{
fprintf(stderr,"cannot open file\n");
exit(0);
}
cnt = fread(arr,1,8,input);
for(i=0;i<cnt;i++)
{
printf("%d\n",arr[i]);
}
return 0;
}
any idea why?
arr is an array of integers. But you read only 8 bytes into it. So your first integer will have some large value, and so will your second, but after that they will have garbage values. (You made arr an "automatic" variable, which is allocated on the stack, so it will have random garbage in it; if you made it a static variable it would be pre-initialized to zero bytes.)
If you change the declaration of arr so that it is of type char, you can read your string in, and your for loop will loop over those bytes one at a time.
Then you can write a string-to-binary translator, or alternatively you could use strtol() to do the conversion with the base set to 2. strtol() is not available in all compilers; GCC is fine but Microsoft C doesn't have it.
Pl. see if the code (Compiled using gcc on Linux) below works for this.
#include<stdio.h>
#include<stdlib.h>
int main()
{
char arr[8];
int cnt,i,temp=0;
FILE * input;
if((input=fopen("data","r"))==NULL)
{
fprintf(stderr,"cannot open file\n");
exit(1);
}
//Read the 8 bytes in a character array of size 8
cnt = fread(arr,1,8,input);
for (i = 0; i < cnt; i++)
{
//Now change it to 0/1 form by substracting 48
arr[i] = arr[i] - '0';/* Ascii of 0 = 48*/
//Also Left shift..
arr[i] = arr[i] << (cnt - (i+1));
//Now Bit wise OR with the integer...
temp = temp | arr[i];
}
printf("The ascii value is %d and the character is %c\n", temp, temp);
return 0;
}
You first declare unsigned int arr[8]; which means 8 integers or more precisely 8*4=32 bytes. After that you read 8 bytes and then again try to output 8 integers. I suppose you want to read 8 bytes and output them as numbers? If you change type int to char, code might work. If file size is 32 bytes and contains integers, you may want to change fread() like this: fread(arr,sizeof(int),8,input);
Related
I'm not familiar with C at all so this might be a simple problem to solve. I'm trying to take an input char* array of binary character sequences, ex. "0100100001101001", and output its relative string ("Hi"). The problem I'm having is coming up with a way to split the input into seperate strings of length 8 and then convert them individually to ulimately get the full output string.
char* binaryToString(char* b){
char binary[8];
for(int i=0; i<8; ++i){
binary[i] = b[i];
}
printf("%s", binary);
}
I'm aware of how to convert 8-bit into its character, I just need a way to split the input string in a way that will allow me to convert massive inputs of 8-bit binary characters.
Any help is appreciated... thanks!
From what I can tell, your binaryToString() function does not do what you'd want it to. The print statement just prints the first eight characters from the address pointed to by char* b.
Instead, you can convert the string of 8 bits to an integer, utilizing a standard C function strtol(). There's no need to convert any further, because binary, hex, decimal, etc, are all just representations of the same data! So once the string is converted to a long, you can use that value to represent an ASCII character.
Updating the implementation (as below), you can then leverage it to print a whole sequence.
#include <stdio.h>
#include <string.h>
void binaryToString(char* input, char* output){
char binary[9] = {0}; // initialize string to 0's
// copy 8 bits from input string
for (int i = 0; i < 8; i ++){
binary[i] = input[i];
}
*output = strtol(binary,NULL,2); // convert the byte to a long, using base 2
}
int main()
{
char inputStr[] = "01100001011100110110010001100110"; // "asdf" in ascii
char outputStr[20] = {0}; // initialize string to 0's
size_t iterations = strlen(inputStr) / 8; // get the # of bytes
// convert each byte into an ascii value
for (int i = 0; i < iterations; i++){
binaryToString(&inputStr[i*8], &outputStr[i]);
}
printf("%s", outputStr); // print the resulting string
return 0;
}
I compiled this and it seems to work fine. Of course, this can be done cleaner and safer, but this should help you get started.
I just need a way to split the input string in a way that will allow me to convert massive inputs of 8-bit binary characters.
You can use strncpy() to copy the sequence of '0' and '1' in a chunk of 8 characters at a time from the input string, something like this:
//get the size of input string
size_t len = strlen(b);
//Your input array of '0' and '1' and every sequence of 8 bytes represents a character
unsigned int num_chars = len/8;
//Take a temporary pointer and point it to input string
const char *tmp = b;
//Now copy the 8 chars from input string to buffer "binary"
for(int i=0; i<num_chars; ++i){
strncpy(binary, tmp+(i*8), 8);
//do your stuff with the 8 chars copied from input string to "binary" buffer
}
Maybe this can help. I didnt compile it but there is the idea. You can loop every 8 bit separately with while loop. And assign 8 bit to binary array with for loop. After that send this binary array to convert8BitToChar function to get letter equivalent of 8 bit. Then append the letter to result array. I'm not writing c for 3 year if there is mistakes sorry about that. Here pseudo code.
char* binaryToString(char* b){
char* result = malloc(sizeof(256*char));
char binary[8];
int nextLetter = 0;
while (b[nextLetter*8] != NULL) { // loop every 8 bit
for(int i=0; i<8; ++i){
binary[i] = b[nextLetter*8+i];
}
result[nextLetter] = 8bitToChar(binary));// convert 8bitToChar and append yo result
nextLetter++;
}
result[nextLetter] = '\0';
return result;
}
code doesnt accept values from file since when i print some garbage pops up
the file is a textfile with a letter representing a status, and theres a number. there are 5 sets of these , each on new line the letter and the number is seperated with a space, i need to get the numbers in one array
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char status;
int number;
} information;
int main() {
int array[5] = {0};
int i;
FILE *pointer = fopen("transaction22.txt", "r");
information information1;
for (i = 0; i < 5; i++) {
fread(&information1, sizeof(information1), 1, pointer);
array[i] = information1.number;
printf("%d", information1.number);
}
return 0;
}
You can use fscanf instead of fread as:
fscanf(pointer, "%s %d", info1.status, &info1.number);
where status will be defined as char status[2]; inside struct information.
fread is used for reading raw bytes (blocks of data) from a file.
Now, you are using a text file and trying to read sizeof(info) amount of data which is 5 bytes of data (assuming 32-bit int), therefore what you get after first fread is:
info1.status (1 byte) info1.number (4 bytes)
Byte 1 SPACE + number + NEWLINE + [One more byte]
read by fread (next four bytes read by fread)
Thus info1.number is storing a garbage value.
Also the successive fread call starts reading after the data read by previous fread.
Better to use a character array like c[5]. and replace this is with struct. variable in fread ..like in for loop
fread(c,sizeof(c),1,pointer)
than use
print("%s\n",c);
I am attempting to put a list of characters AND integers into an array of just integers. The file.txt looks like:
a 5 4 10
4 10 a 4
In the array I want the values to come out as {97,5,4,10,4,10,97,4}
This is part of my code:
int * array = malloc(100 * sizeof(int));
FILE* file;
int i=0;
int integer = 1;
file=fopen(filename,"r");
while (fscanf(file,"%d",&integer) > 0)
{
array[i] = integer;
i++;
}
Your problem is that, at first read, your while condition will exit because first element in the file is a char and fscanf won't interpret it as an integer, returning 0. I would suggest, if you are sure that your separator is a space, reading a string (it will automatically stop at space) and convert read value to int with strtol.
Something like:
int * array = malloc(100 * sizeof(int));
FILE* file;
int i=0;
char tmp[2], *pEnd;
file=fopen("./test.txt","r");
while (fscanf(file,"%s",tmp) > 0)
{
if( !(array[i] = strtol(tmp, &pEnd,10)))
array[i] = tmp[0];
i++;
}
Note that I assumed that you'll have no integer bigger than one digit (tmp array size) and that I check strtol response for detecting non integer chars.
It seems to me that what you want to do is use fscanf("%s", some_string) since numerics can be received as strings but strings cannot be received as numerics. Then with each input, you need to decide if the string is actually numeric or not, and then derive the value you want to place into the array accordingly.
My assignment this week is to go create a program that reads a data file that my professor sent to me. The assignment says there are 10 integers in this data that I need to write to an array, which I've done but I'm not sure if it's correct or just junk data. I will attach the a DL link for this file (it's only 40bytes). I've created a program below that will read off the 10 numbers that I need, but how do I know if it is junk data or the real deal. I am getting the same numbers everytime, is that an indication that I'm doing this correctly? Any long term tips for me to use in the future would be appreciated as well.
Here is the DL link
mysteryData
#include <stdio.h>
#include <string.h>
int main(void)
{
int i;
FILE* myFile = NULL;
myFile = fopen("mysteryData.dat", "rb");
int Mystery[10] =
{ '\0' };
if (myFile == NULL )
{
printf("Failed to open file\n");
}
else
{
fread(Mystery, sizeof(int), sizeof(Mystery), myFile);
printf("%d\n", Mystery);
}
for (i = 0; i < 9; i++)
{
printf("%d\n", Mystery[i]);
}
fclose(myFile);
}
First, if you mean to print the address of Mystery after the fread call, you should use %p. Second, perhaps printing in hex will help you see the problem:
% echo $'\x12\x34\x56\x78\x9a\xbc\xde\xff' > mysteryData.dat
% ./test
0x7fff598cfae0 # %p
78563412 # %x
ffdebc9a
a # newline = 0x0a
0
0
0
0
0
0
%
The values are being strung together in the integers, and are bytewise-reversed. They are being strung together because you are reading them as integers:
12 34 56 78 9a bc de ff a0 00 00 00
^---------^ ^---------^ ^---------^
From this we see that ints in my compiler are 32 bits (4 bytes). Furthermore, the reason the bytes are swapped is because my system is little-endian; that means that the 12 is the least significant 8 bits, 34 is the next most significant, etc.
You probably want to access these as individual bytes, for which you should change Mystery to a char[10]. And maybe make it bigger to ensure you have enough space. Finally, you want to check the return value of fread, which will tell you how many bytes you have actually read.
Fread is declared thusly:
fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
^^^^ ^^^^^^
You are passing the right size, but instead of passing the number of items for nitems, you are passing the size of Mystery, which is nitems*sizeof(int). Use
fread(Mystery, sizeof(int), sizeof(Mystery)/sizeof(int), myFile);
Or better,
fread(Mystery, sizeof(Mystery[0]), sizeof(Mystery)/sizeof(Mystery[0]), myFile);
First of all it should specified how these integers are stored into the file.
As the file is 40 bytes and there is a specification that the count of items is 10 you can assume that they are stored as binary data and each integer takes four bytes.
*I say that because the file may be a text file with integers stored as newline separated values:
10
13
4563
-32
etc......
But. In 40 bytes there is no space for 10 integers stored as text, so let's say they are in binary data.
At this point we assume also that the endianess of the data is the same of the architecture your program will be compiled and run. I won't go further on this, for more info you may google for big endian little endian
Finally it should be specified what is the size of an integer. The size of an integer may vary depending on the OS / architecture:
see What does the C++ standard state the size of int, long type to be?
But we have 40 bytes, we know we have 10 ints. Into the file the int is 4 bytes for each number.
You may check if that match with your architecture with:
printf("Here ints are %d bytes.\n", (int) sizeof(int));
and looking at the output.
Going back to your code thare are some things to be adjusted. See the comments...
#include <stdio.h>
#include <string.h>
int main (void)
{
int i;
int itemsRead; // we'll use that later...
FILE* myFile=NULL;
myFile=fopen("mysteryData.dat", "rb");
int *Mystery = malloc (sizeof(int) * 10); // It's a better practice...
//... to allocate the buffers/arrays you need instead of declaring them
// statically. If your file grows up with millions of numbers your code
// will still be scalable.
if(!Mystery) // Just check the alloc succeeded
{
printf("Failed to allocate buffer\n");
}
if(myFile==NULL)
{
printf("Failed to open file\n");
free( Mystery ); // Free the buffer
return 0; // Quit
}
itemsRead = fread(Mystery, sizeof(int), 10, myFile);
// 2nd parameter is size of element
// 3rd parameter is how many items
// the function returns the items actually read
// What is the file was shorter than expected?
// Check we were able to actually read 10 items of 4 bytes each
if( itemsRead < 10 )
{
printf("The file ended unexpectedly\n");
free( Mystery ); // Free the buffer
return 0; // Quit
}
for (i=0; i<10; i++) // 10 Items: count from 0 to 9 so until i<10
{
printf("%d\n", Mystery[i]);
}
free( Mystery );
fclose( myFile );
}
I'm wanting to read hex numbers from a text file into an unsigned integer so that I can execute Machine instructions. It's just a simulation type thing that looks inside the text file and according to the values and its corresponding instruction outputs the new values in the registers.
For example, the instructions would be:
1RXY -> Save register R with value in
memory address XY
2RXY -> Save register R with value XY
BRXY -> Jump to register R if xy is
this and that etc..
ARXY -> AND register R with value at
memory address XY
The text file contains something like this each in a new line. (in hexidecimal)
120F
B007
290B
My problem is copying each individual instruction into an unsigned integer...how do I do this?
#include <stdio.h>
int main(){
FILE *f;
unsigned int num[80];
f=fopen("values.txt","r");
if (f==NULL){
printf("file doesnt exist?!");
}
int i=0;
while (fscanf(f,"%x",num[i]) != EOF){
fscanf(f,"%x",num[i]);
i++;
}
fclose(f);
printf("%x",num[0]);
}
You're on the right track. Here's the problems I saw:
You need to exit if fopen() return NULL - you're printing an error message but then continuing.
Your loop should terminate if i >= 80, so you don't read more integers than you have space for.
You need to pass the address of num[i], not the value, to fscanf.
You're calling fscanf() twice in the loop, which means you're throwing away half of your values without storing them.
Here's what it looks like with those issues fixed:
#include <stdio.h>
int main() {
FILE *f;
unsigned int num[80];
int i=0;
int rv;
int num_values;
f=fopen("values.txt","r");
if (f==NULL){
printf("file doesnt exist?!\n");
return 1;
}
while (i < 80) {
rv = fscanf(f, "%x", &num[i]);
if (rv != 1)
break;
i++;
}
fclose(f);
num_values = i;
if (i >= 80)
{
printf("Warning: Stopped reading input due to input too long.\n");
}
else if (rv != EOF)
{
printf("Warning: Stopped reading input due to bad value.\n");
}
else
{
printf("Reached end of input.\n");
}
printf("Successfully read %d values:\n", num_values);
for (i = 0; i < num_values; i++)
{
printf("\t%x\n", num[i]);
}
return 0
}
You can also use the function strtol(). If you use a base of 16 it will convert your hex string value to an int/long.
errno = 0;
my_int = strtol(my_str, NULL, 16);
/* check errno */
Edit: One other note, various static analysis tools may flag things like atoi() and scanf() as unsafe. atoi is obsolete due to the fact that it does not check for errors like strtol() does. scanf() on the other hand can do a buffer overflow of sorts since its not checking the type sent into scanf(). For instance you could give a pointer to a short to scanf where the read value is actually a long....and boom.
You're reading two numbers into each element of your array (so you lose half of them as you overwrite them. Try using just
while (i < 80 && fscanf(f,"%x",&num[i]) != EOF)
i++;
for your loop
edit
you're also missing the '&' to get the address of the array element, so you're passing a random garbage pointer to scanf and probably crashing. The -Wall option is your friend.
In this case, all of your input is upper case hex while you are trying to read lower case hex.
To fix it, change %x to %X.
Do you want each of the lines (each 4 characters long) separated in 4 different array elements? If you do, I'd try this:
/* read the line */
/* fgets(buf, ...) */
/* check it's correct, mind the '\n' */
/* ... strlen ... isxdigit ... */
/* put each separate input digit in a separate array member */
num[i++] = convert_xdigit_to_int(buf[j++]);
Where the function convert_xdigit_to_int() simply converts '0' (the character) to 0 (an int), '1' to 1, '2' to 2, ... '9' to 9, 'a' or 'A' to 10, ...
Of course that pseudo-code is inside a loop that executes until the file runs out or the array gets filled. Maybe putting the fgets() as the condition for a while(...)
while(/*there is space in the array && */ fgets(...)) {
}