"fread" reads wrong values when it's reading numbers - c

Let's say I have a file:
file.in:
3 3
and I want to read the 2 numbers that are written in it with fread, so I write this:
#include <stdio.h>
int main() {
int buffer[3] = {0}; // 3 items bcs it also reads the space between the "3"s
FILE* f = fopen("file.in", "r");
fread(buffer, 3, 4, f);
printf("%d %d", buffer[0], buffer[2]);
}
I think the output should be 3 3, but I am getting somethink like 17?????? 17??????. But if I make int buffer[3] = {0}; to char buffer[3] = {'\0'}; it works fine
Any attemt to help is appreciated

fread() is for reading the byte stream from the files. 3 3 is represented using 3bytes 0x33 0x20 0x33 if ASCII is used, so fread(buffer, 3, 4, f); (read 12 bytes) is not for reading this.
If you want to store the bytes in int, you should use fgetc() instead.
#include <stdio.h>
int main() {
int buffer[3] = {0}; // 3 items bcs it also reads the space between the "3"s
FILE* f = fopen("file.in", "r");
for (int i = 0; i < 3; i++) {
buffer[i] = fgetc(f);
}
printf("%c %c", buffer[0], buffer[2]); // use %c instead of %d to print the characters corresponding to the character codes
}

Related

Convert large block of binary into text in C

I have a project in which I'm supposed to take in a file via the getchar() function and convert the binary characters within it to text.
Here is the code I have, that will produce the correct ASCII number for only one at a time. I don't know how to read in an entire text file's worth of binary and convert it:
#include <stdio.h>
#include <string.h>
typedef unsigned char byte;
typedef unsigned int uint;
int strbin_to_dec(const char *);
int main(void) {
char * wbin = "01001001";
int c = 0;
printf("%s to ascii %d.\n", wbin, strbin_to_dec(wbin));
printf("The character is %c", strbin_to_dec(wbin));
return 0;
}
int strbin_to_dec(const char * str) {
uint result = 0;
for (int i = strlen(str) - 1, j = 0; i >= 0; i--, j++) {
byte k = str[i] - '0';
k <<= j;
result += k;
}
return result;
}
The above code works when I enter exactly one character's worth of binary into the variable 'wbin', but I can't format this to accept the input from getchar() because getchar gives an int type. The above code produces the result:
01001001 to ascii 73.
The character is I
The file I'm supposed to translate looks like this:
0010001001001000011011110111011100100000011011110110011001110100011001010110111000100000011010000110000101110110011001010010000001001001001000000111001101100001011010010110010000100000011101000110111100100000011110010110111101110101
011101000110100001100001011101000010000001110111011010000110010101101110001000000111100101101111011101010010000001101000011000010111011001100101001000000110010101101100011010010110110101101001011011100110000101110100011001010110010000100000011101000110100001100101001000000110100101101101011100000110111101110011011100110110100101100010011011000110010100101100
01110111011010000110000101110100011001010111011001100101011100100010000001110010011001010110110101100001011010010110111001110011001011000010000001101000011011110111011101100101011101100110010101110010001000000110100101101101011100000111001001101111011000100110000101100010011011000110010100101100
01101101011101010111001101110100001000000110001001100101001000000111010001101000011001010010000001110100011100100111010101110100011010000011111100100010
0010110101010011011010010111001000100000010000010111001001110100011010000111010101110010001000000100001101101111011011100110000101101110001000000100010001101111011110010110110001100101001011000010000001010100011010000110010100100000010100110110100101100111011011100010000001001111011001100010000001000110011011110111010101110010
This is a trivial task to perform simply by using bit shifting. Also instead of using getchar, for performance, the below uses fread.
This implementation uses minimal RAM (no use of malloc), no slow string parsing or math functions such as strlen, strtol or pow, and can handle any stream of infinite size/length, including truncated streams that are not multiples of 8 bytes.
Usage:
./a.out < data.txt > out.txt
#include <stdio.h>
int main(int argc, char * argv[])
{
unsigned char byte = 0;
int bits = 0;
for(;;)
{
char buffer[1024];
int len = fread(buffer, 1, sizeof(buffer), stdin);
// if there was a read error or EOF, stop
if (len <= 0)
break;
for(int i = 0; i < len; ++i)
{
switch(buffer[i])
{
// if a binary 1, turn on bit zero
case '1':
byte |= 1;
break;
// if a binary 0, do nothing
case '0':
break;
// if antyhing else, skip
default:
continue;
}
// incrment the counter, if we dont yet have 8 bits
// shift all the bits left by one
if (++bits < 8)
byte <<= 1;
else
{
// write out the complete byte
fwrite(&byte, 1, 1, stdout);
// reset for the next byte
bits = 0;
byte = 0;
}
}
}
// write out any remaining data if the input was not a multiple of 8 in length.
if (bits)
fwrite(&byte, 1, 1, stdout);
return 0;
}
Input:
0010001001001000011011110111011100100000011011110110011001110100011001010110111000100000011010000110000101110110011001010010000001001001001000000111001101100001011010010110010000100000011101000110111100100000011110010110111101110101
011101000110100001100001011101000010000001110111011010000110010101101110001000000111100101101111011101010010000001101000011000010111011001100101001000000110010101101100011010010110110101101001011011100110000101110100011001010110010000100000011101000110100001100101001000000110100101101101011100000110111101110011011100110110100101100010011011000110010100101100
01110111011010000110000101110100011001010111011001100101011100100010000001110010011001010110110101100001011010010110111001110011001011000010000001101000011011110111011101100101011101100110010101110010001000000110100101101101011100000111001001101111011000100110000101100010011011000110010100101100
01101101011101010111001101110100001000000110001001100101001000000111010001101000011001010010000001110100011100100111010101110100011010000011111100100010
0010110101010011011010010111001000100000010000010111001001110100011010000111010101110010001000000100001101101111011011100110000101101110001000000100010001101111011110010110110001100101001011000010000001010100011010000110010100100000010100110110100101100111011011100010000001001111011001100010000001000110011011110111010101110010
Output:
"How often have I said to youthat when you have eliminated the impossible,whatever remains, however improbable,must be the truth?"-Sir Arthur Conan Doyle, The Sign Of Four
This is a function made by me! I dont know if you use the file as a parameter of execution like: ./text.exe -f binary.txt! But I dont add entries to the program! I has defined the file by my self!
I have created a function to write to a file, but if you want to use the command like ./text.exe -f binary.txt > translatedfile.txt you can simply remove the function write_to_file! Dont forget to remove the prints that you dont want because the parameter ">" will print everything!
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void binary_to_char(char *str);
void write_to_file(char *text);
int main(void)
{
printf("Getting line from file\n");
FILE *file;
char *line = NULL;
size_t len = 0;
ssize_t stringLength;
file = fopen("binary.txt", "r");
if (file == NULL)
{
fprintf(stderr, "[ERROR]: cannot open file -- binary.txt");
perror("");
exit(1);
}
while ((stringLength = getline(&line, &len, file)) != -1)
{
printf("\n%s", line);
binary_to_char(line);
}
free(line);
fclose(file);
return 0;
}
void binary_to_char(char *str)
{
char binary[9];
char *text = malloc((strlen(str) + 1) * sizeof(char));
char c;
int pos = 0;
int letter_pos = 0;
printf("\nConverting into characters\n");
for (size_t j = 0; j < strlen(str) / 8; j++)
{
for (int i = 0; i < 8; i++)
{
binary[i] = str[pos];
pos++;
}
c = strtol(binary, 0, 2);
text[letter_pos] = c;
letter_pos++;
}
printf("\n%s\n", text);
write_to_file(text);
free(text);
}
void write_to_file(char *text)
{
printf("\nContent saved to translatedfile.txt\n");
FILE *fp;
fp = fopen("translatedfile.txt", "w+");
fprintf(fp, "%s", text);
fclose(fp);
}
Content of File binary.txt:
001000100100100001101111011101110010000001101111011001100111010001100101011011100010000001101000011000010111011001100101001000000100100100100000011100110110000101101001011001000010000001110100011011110010000001111001011011110111010101110100011010000110000101110100001000000111011101101000011001010110111000100000011110010110111101110101001000000110100001100001011101100110010100100000011001010110110001101001011011010110100101101110011000010111010001100101011001000010000001110100011010000110010100100000011010010110110101110000011011110111001101110011011010010110001001101100011001010010110001110111011010000110000101110100011001010111011001100101011100100010000001110010011001010110110101100001011010010110111001110011001011000010000001101000011011110111011101100101011101100110010101110010001000000110100101101101011100000111001001101111011000100110000101100010011011000110010100101100011011010111010101110011011101000010000001100010011001010010000001110100011010000110010100100000011101000111001001110101011101000110100000111111001000100010110101010011011010010111001000100000010000010111001001110100011010000111010101110010001000000100001101101111011011100110000101101110001000000100010001101111011110010110110001100101001011000010000001010100011010000110010100100000010100110110100101100111011011100010000001001111011001100010000001000110011011110111010101110010
Read in all the input from the file, and pass in 8 chars at a time to a converter function to return a char. Each char is 8 bits, and each character in the file represents 1 bit.
char string_to_character(char * in)
{
char ret = 0;
int i;
for(i = 7; i >= 0; i--)
if(in[i] == '1')
ret += 1 << (7 - i);
return ret;
}
This function will decode each 8 chars from the file into one character. Simply call the function with an offset of 8 chars for the entire input string and save the result somewhere.
EDIT: Be sure to include and link math library math.h.
EDIT 2: Should be >= not >
For looping...
Say you have the entire file as one long string.
int num_chars = (sizeof(input) / sizeof(char)) / 8;
int i;
char output[num_chars + 1];
for(i = 0; i < num_chars; i++)
output[i] = string_to_character(input + (i * 8));
printf("%s", output);
This was the result I got from the program
"How often have I said to youthat when you have eliminated the impossible,whatever remains, however improbable,must be the truth?"-Sir Arthur
Conan Doyle, The Sign Of Four
EDIT: left bitshift vs pow

how to read int values from a file.txt using fread() function in C?

I would like to read some int values from a file which contains :
1
821
4
5423
2
I used this code :
#include <stdio.h>
#define N 5
int main() {
int buffer[N]; // Buffer to store data
int i ;
FILE * stream;
stream = fopen("file.txt", "r");
fread(&buffer, sizeof(int), N, stream);
fclose(stream);
// Printing data to check validity
for (i=0 ; i<N ; i++)
printf("buffer[%d] : %d \n",i,buffer[i]);
printf("\n");
return 0;
}
but what I obtain are some random values and not file values
buffer[0] : 842533425
buffer[1] : 171182641
buffer[2] : 858928181
buffer[3] : 168440330
buffer[4] : 2106524480

fgets() reads and stores a char form a line twice

So I have a file data.txt, with random integers written in it, for example "17 12 5 4 16".
So, I used fgets() to read this line of integers and store it in a char str []. As expected str [0] == 17, but str [1] == 7, an so on... every 2 digits the integer is stored in an element in the array, but the second digit is also stored in the following element.
Example: str [3] = 12, str [4] = 2, str[5] = ' '.
What could be done to fix this issue?
Here is my very typical code:
FILE* fp = fopen ("data.txt", "r");
int i = 0, j = 0;
int size = fileSize(fp) + 1; // Enumerate the char numbers in file
char str [size];
rewind (fp);
fgets (str, size, fp);
Here is my entire code
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct RATIONAL
{
int top;
int bottom;
} RATIONAL;
void printArray (int arr [], int count)
{
for (int i = 0; i < count; ++i)
{
printf ("%d\n", arr[i]);
}
}
int fileSize (FILE* fp)
{
char c;
int i = 0;
while ((c = getc (fp)) != EOF)
{
i++;
}
return (i);
}
int main ()
{
RATIONAL ratArray [23]; //array to hold rational numbers
int intArray [45]; //array to hold integer values
FILE* fp = fopen ("data.txt", "r");
int i = 0, j = 0;
int size = fileSize(fp) + 1; // Enumerate the char numbers in file
char str [size];
rewind (fp);
fgets (str, size, fp);
//Convert string to array of ints
while (i < size -1)
{
if (isdigit (str [i]))
{
intArray[j++] = atoi(&str[i]);
i++;
}
else
i++;
}
printArray (intArray, intArray[0]);
Input: data.txt
What you experience is absolutely expected. The key misunderstanding is that you expect arr[N] to hold the (N+1)th integer as it was an array of integers... but it's not. It is an array of characters.
If you store integers within a char array, every digit will occupy an array location. So arr[0] will contain the most significant digit of the first number and arr[a] the least significant digit.
So, in your example, the string "17 12 5 4 16" will be stored in this way:
--------------------------------------------------------------------------------------------
| 0x31 | 0x37 | 0x20 | 0x31 | 0x32 | 0x20 | 0x35 | 0x20 | 0x34 | 0x20 | 0x31 | 0x36 | 0x00 |
--------------------------------------------------------------------------------------------
| '1' | '7' | ' ' | '1' | '2' | ' ' | '5' | ' ' | '4' | ' ' | '1' | '7' | '\0' |
--------------------------------------------------------------------------------------------
All digits are in the same array and separated by spaces. The string is closed by a string terminator '\0'.
Interesting enough, if you print the whole string with printf("%s\n", arr) you get
17 12 5 4 16
but if you try to print passing the address of the second character, with printf("%s\n", &arr[1]) you get
7 12 5 4 16
And so on. This means that C has no idea (not yet) that your intention is to store 5 integers. The string is one until the string terminator is found (the space doesn't terminate the string), so starting from the second digit will just make C print all the string except the first digit.
Since you have a string formatted in a well known way and you want an array of integers, you have to parse it to get the integers:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char arr[] = "7 12 5 4 16";
int main()
{
char * token = strtok(arr, " ");
while(token != NULL)
{
printf("Next int: %d %s\n", atoi(token)); // Here you can assign the value to your array
token = strtok(NULL, " ");
}
return 0;
}
In my demonstrative example, in which the input string was a global array instead of something read from a file like in your scenario, I used strtok() (strtok_r can be used in case a re-entrant function is required) and I got the integers using the simple atoi() (just because the input format was _under control - I recommend using strtol() for a better control of the input).

Reading in a binary file in C, then matching data from the file to what I have read in

So I'm trying to read in a binary file with 4 bytes per chunk, and when doing a hexdump on my file here is the output:
0000000 0022 0000 6261 6463 3030 3030 6261 6463
0000010 3030 3030 6261 6463 3030 3030 6261 6463
*
00000d0 3030 3030 6261 6463 3030 3030 000a
00000dd
(There shouldn't be a line in between each line of digits, sorry)
But when it reads these values into an array here is the output I'm getting:
34 61000000 30646362 61303030 30646362 61303030 30646362 61303030 30646362 2283030 0 44c5bbc0 7fff 22 0 14fea515 7f68 0 0 22 0 22 0 4007b2 0 1 0 1000 0 2289010 0 44c5bbc0 7f
I've followed a lot of instructions online and I'm really not sure where to go from here.
Here is the code I'm using:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char** argv)
{
unsigned char buffer[1];
FILE *filePointer;
filePointer = fopen(argv[1], "rb");
//unsigned char buffer[filePointer];
int readVal = 0;
readVal = fread(buffer, sizeof(buffer), 1, filePointer);
if (readVal == 0)
{
printf("File did not read anything\n");
}
int size = buffer[0];
/*int i = 1;
for(; i < 1; i++)
{
printf("%x ", buffer[i]);
}
*/
//int size = buffer[0];
printf("%d\n", size);
unsigned int array[size];
int otherDataElements;
otherDataElements = fread(array, sizeof(buffer), size, filePointer);
if (otherDataElements == 0)
{
printf("There was nothing there!");
}
int j = 0;
for (; j < size; j++)
{
printf("%x ", array[j]);
}
return 0;
}
There is some code commented out, ignore it. Thanks!
what is size? Number of bytes? or integers?
This seems suspicious:
otherDataElements = fread(array, sizeof(buffer), size, filePointer);
Try changing to this:
otherDataElements = fread(array, sizeof(unsigned int), size/sizeof(unsigned int), filePointer);
Because array is array of unsigned integers and second parameter to fread asks you for size of each element to be read. File length should also be multiple of 4 if you want to interpret the file contents as array of 4 byte integers I think.
Anyway the output of this program on my machine is (this is similar program as yours just added writing data to file for testing - and I have simplified reading):
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void test()
{
unsigned char buffer[1];
FILE *filePointer;
filePointer = fopen("/Users/macbookair/Documents/test/test/t.bin", "rb");
//unsigned char buffer[filePointer];
//readVal = fread(buffer, sizeof(buffer), 1, filePointer);
//if (readVal == 0)
//{
// printf("File did not read anything\n");
// }
//int size = 4;
/*int i = 1;
for(; i < 1; i++)
{
printf("%x ", buffer[i]);
}
*/
//int size = buffer[0];
//printf("%d\n", size);
unsigned int array[4] = {0};
int otherDataElements;
int nrOfInts = 1; // In this test method we only want to read 1 integer from file, we assume there is one integer only
otherDataElements = fread(array, sizeof(unsigned int), nrOfInts, filePointer);
if (otherDataElements == 0)
{
printf("There was nothing there!");
}
int j = 0;
for (; j < nrOfInts; j++)
{
printf("%x ", array[j]);
}
}
int main(int argc, const char * argv[])
{
// Just do a test write to file. Write 4 bytes to read back later.
FILE *write_ptr;
unsigned char buffer[4] = {0,1,2,3};
write_ptr = fopen("/Users/macbookair/Documents/test/test/t.bin","wb");
fwrite(buffer,sizeof(buffer),1,write_ptr);
fclose(write_ptr);
// Call our method for reading the data
test();
return 0;
}
this:
3020100
You can see the output is swapped but that is because of endianness - when my computer interpreted bytes 00 01 02 03 as bytes of an integer, it did so in little endian way - hence the output is integer 03020100. You may want to consider this also in your case. So in my case it worked fine I guess.

C print whole string variable (ignore \0 termination)

An example says more than thousand words:
unsigned char *hello = (unsigned char*)malloc(STR_LEN * sizeof(unsigned char));
const char *str= "haha";
memcpy(hello, str, strlen(str) + 1);
How can I print the content of the whole hello-variable (printf("%s",..) would only respect the part before the \0-termination and not all STR_LEN characters).
You can use fwrite to write unformatted data:
char buf[4] = { 1, 2 };
fwrite(buf, 1, 4, stdout); // writes the bytes 1, 2, 0, 0
You could use fwrite(hello, 1, STR_LEN, stdout), but note that you're not allowed to read uninitialized data (so you should use calloc instead or initialize the data in some other way).
You'd have to write your own for loop that goes from hello to hello+STR_LEN, and prints each character one at a time.
for (unsigned char *c = hello, e = hello +STR_LEN; c < e; ++c) {
printf("%c", *c);
}
int i;
for(i = 0; i < STR_LEN; i++) {
putchar(hello[i]);
}

Resources