Trouble reading/writing .bmp file in C - c

My program needs to be able to read a .bmp image, write some data in it and then create another .bmp image. For a start, I began coding some stuff to read an image and the rewrite the same image in another file, but I got some problems in it.
Here's my code:
bmp.h:
#ifndef _BMP_H_
#define _BMP_H_
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#pragma pack(push, 1)
typedef struct {
uint16_t type;
uint32_t fileSize;
uint16_t reserved1;
uint16_t reserved2;
uint32_t offset;
} BMP_File_Header;
typedef struct {
BMP_File_Header fileHeader;
uint32_t bSize;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bitCount;
uint32_t compression;
uint32_t imageSize;
int32_t xPixelsPerMeter;
int32_t yPixelsPerMeter;
uint32_t colorUsed;
uint32_t importantColor;
} BMP_Info_Header;
#pragma pack(pop)
BMP_Info_Header* loadBMP(const char *filename, char *data);
void writeBMP(BMP_Info_Header *infoHeader, char *data);
#endif
bmp.c:
#include "bmp.h"
BMP_Info_Header* loadBMP(const char *file_name, char *data) {
FILE *file;
BMP_Info_Header *infoHeader;
int n;
//Open the file
file = fopen(file_name, "rb");
if (!file) {
fprintf(stderr, "Failed to read file %s.\n", file_name);
exit(1);
}
//Alloc and read the headers
infoHeader = (BMP_Info_Header *) malloc (sizeof(BMP_Info_Header));
n = fread(infoHeader, sizeof(BMP_Info_Header), 1, file);
//Check format
if (infoHeader->fileHeader.type != 0x4D42) {
fclose(file);
fprintf(stderr, "Invalid image");
exit(1);
}
//-------------------------Checking the image--------------------------
if (infoHeader->bSize != 40) {
fclose(file);
fprintf(stderr, "Couldn't load image correctly");
exit(1);
}
if ((infoHeader->planes != 1) || (infoHeader->bitCount != 24)) {
fclose(file);
fprintf(stderr, "Invalid image");
exit(1);
}
if (infoHeader->compression != 0) {
fclose(file);
fprintf(stderr, "This software currently does not support compressed BMP files.\n");
exit(1);
}
//Move the file through the offset until the beginning of the data itself
fseek(file, sizeof(char) * infoHeader->fileHeader.offset, SEEK_SET);
//Allocate the char array to the needed size to hold the data
data = (char *) malloc (sizeof(char) * infoHeader->imageSize);
//Actually read the image data
fread(data, sizeof(char), infoHeader->imageSize, file);
printf("%s", data);
//Verify the data
if (!data) {
fclose(file);
fprintf(stderr, "Couldn't load image data correctly\n");
exit(1);
}
fclose(file);
return infoHeader;
}
void writeBMP(BMP_Info_Header *header, char *data){
FILE *fp;
fp = fopen("output.bmp", "wb");
int n;
if (!fp) {
fclose(fp);
fprintf(stderr, "Unable to create output file\n");
exit(1);
}
//-----------------------WRITE THE IMAGE------------------------
//Header
n = fwrite(header, sizeof(char), sizeof(BMP_Info_Header), fp);
if (n < 1) {
fclose(fp);
fprintf(stderr, "Couldn't write the image header.\n");
exit(1);
}
//Offset
fseek(fp, sizeof(char) * header->fileHeader.offset, SEEK_SET);
//Data
n = fwrite(data, sizeof(char), header->imageSize, fp);
if (n < 1) {
fclose(fp);
fprintf(stderr, "Couldn't write the image data.\n");
exit(1);
}
fclose(fp);
fprintf(stdout, "Image written successfully!\n");
}
It seems to always fall off at the "Couldn't write the image data" error. Can somebody help me? I'm fairly new to programming and couldn't fix it by myself.

So, I did found the solution to my problem. Trouble is, when a BMP file is NOT compressed, the value in the imageSize variable found in the BMP_Info_Header struct is equal to 0, so when I called the fread and fwrite functions, they wouldn't read or write anything because the header->imageSize value was 0. The solution I found was to substitute the header->imageSize calls for 3 * header->width * header->height, that way I can get the real image resolution and I multiply it by 3 so I can get the exact pixel values. By the way, thanks for the help guys! Appreciate it!

Probably the problem is with the fseek, for which you don't check the return value.
fwrite(header, sizeof(char), sizeof(BMP_Info_Header), fp);
fseek(fp, sizeof(char) * header->fileHeader.offset, SEEK_SET);
fwrite(data, sizeof(char), header->imageSize, fp);
See, if your current position after writing the header is less than the fileHeader.offset, , what do you expect to happen? Fill the remaining bytes with random values ? with zero? In any case, you should explicitly write those bytes.

Related

fread and fwrite result file size are different

I am writing a program in Visual Studio.
I copied a file using fread and fwrite.
The output file size is bigger then input file.
Can you explain the reason?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int main()
{
char *buffer;
int fsize;
FILE *fp = fopen("test.txt", "r");
FILE *ofp = fopen("out.txt", "w");
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
buffer = (char *)malloc(fsize);
memset(buffer, 0, fsize); // buffer를 0으로 초기화
fseek(fp, 0, SEEK_SET);
fread(buffer, fsize, 1, fp);
fwrite(buffer, fsize, 1, ofp);
fclose(fp);
fclose(ofp);
free(buffer);
}
You open the files in text mode, which on the Windows operating system using Visual Studio involves non trivial translation phases, including end of line conversion. If your files have binary contents, such as executable, image and document files, end of line conversion replaces '\n' bytes with CR LF pairs, thereby increasing the output size.
You can avoid this issue by opening the files in binary mode with "rb" and "wb" mode strings.
Also note that a stream must be open in binary mode for ftell() to reliably return the file size, assuming the file supports seeking and is not larger than LONG_MAX which is only 2GB on Windows. Using stat to retrieve the file size from the OS is a better approach for POSIX systems. Copying the file one block at a time is also more reliable: it works for streams that do not support seeking and allows for copying files larger than available memory.
Here is a modified version with error checking:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
const char *inputfile = "test.txt";
const char *outputfile = "out.txt";
FILE *fp = fopen(inputfile, "rb");
if (fp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", inputfile, strerror(errno);
return 1;
}
FILE *ofp = fopen(outputfile, "wb");
if (ofp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", outputfile, strerror(errno);
return 1;
}
if (fseek(fp, 0, SEEK_END)) {
fprintf(stderr, "%s: cannot seek to the end of file: %s\n",
inputfile, strerror(errno);
return 1;
}
size_t fsize = ftell(fp);
char *buffer = calloc(fsize, 1);
if (buffer == NULL) {
fprintf(stderr, "cannot allocate %zu bytes: %s\n",
fsize, strerror(errno);
return 1;
}
rewind(fp);
size_t nread = fread(buffer, fsize, 1, fp);
if (nread != fsize) {
fprintf(stderr, "%s: read %zu bytes, file size is %zu bytes\n".
inputfile, nread, fsize);
}
size_t nwritten = fwrite(buffer, nread, 1, ofp);
if (nwritten != nread) {
fprintf(stderr, "%s: wrote %zu bytes, write size is %zu bytes\n".
outputfile, nwritten, nread);
}
fclose(fp);
if (fclose(ofp)) {
fprintf(stderr, "%s: error closing file: %s\n".
outputfile, strerror(errno));
}
free(buffer);
return 0;
}

Recover functions recovers only 4 images instead of 50

I wrote this code to recover 50 images from cs50 pset4 recover. The code can only retrieve 4 images all of which are not the right ones. It is compiling fine. When i use printf to debug it seems like the if(found) piece of code runs many times when name_count == 0 more than it is supposed to.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
typedef uint8_t BYTE;
const int BLOCK_SIZE = 152;
bool is_a_jpeg(BYTE *buffer);
int main(int argc, char *argv[])
{
//Check if there are exactly two commandline arguments
if (argc != 2)
{
printf("usage: ./IMAGE\n");
return 1;
}
//Open a storage device and chack if it has data
FILE *input = fopen(argv[1], "r");
if (input == NULL)
{
fclose(input);
printf("Could not open file.\n");
return 2;
}
//Create a file to write into and clear it
FILE *img = NULL;
//Declar an interger of counting images
int name_count = 0;
// create buffer
BYTE buffer[BLOCK_SIZE];
//Declare space for saving the filename
char filename[8];
//Declare a bolean variable used to check for already found images
bool found = false;
//A function for reading through the device looking for images
while (fread(buffer, BLOCK_SIZE, 1, input))
{
//If a jpeg image is found notify the program(set found = true)
//and start writing the data to a new file
if (is_a_jpeg(buffer))
{
found = true;
//If we are not writing the first image, close the previous one
if (name_count > 0)
{
fclose(img);
}
//Create incrementing filenames for each new picture i.e 000.jpg, 001.jpg etc.
sprintf(filename, "%03d.jpg", name_count);
//Open an initially created empty file and start writing to it
img = fopen (filename, "w");
name_count++;
fwrite(buffer, BLOCK_SIZE, 1, img);
}
//Continue writing to a file as soon as it is found until another JPEG image is found
if(found)
{
fwrite(buffer, BLOCK_SIZE, 1, img);
}
}
//Close all the files
fclose(input);
fclose(img);
return 0;
}
//Function to check for a JPEG Image
bool is_a_jpeg(BYTE *buffer)
{
return buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0;
}
cs50 results for check50
printing dot everytime if(found) code runs. The code unnecessarily spends a lot of time on the first image before closing it
There are some problems in the posted code:
the block size should be 512 bytes, not 152.
you should not fclose(file) if fopen failed. This has undefined behavior.
you unconditionally close img at the end, which may have undefined behavior if no JPG file was found or if the last JPG file could not be open.
both the disk image file and the jpg destination files must be open in binary mode. This may explain unexpected behavior if you are working on Windows.
Here is a modified version:
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef uint8_t BYTE;
const int BLOCK_SIZE = 512;
bool is_a_jpeg(const BYTE *buffer);
int main(int argc, char *argv[]) {
//Check if there are exactly two commandline arguments
if (argc != 2) {
printf("usage: ./IMAGE\n");
return 1;
}
//Open a storage device and check if it has data
FILE *input = fopen(argv[1], "rb");
if (input == NULL) {
fprintf(stderr, "Could not open file %s: %s.\n", argv[1], strerror(errno));
return 2;
}
//Create a file to write into and clear it
FILE *img = NULL;
//Declare an integer of counting images
int name_count = 0;
// create buffer
BYTE buffer[BLOCK_SIZE];
//Declare space for saving the filename
char filename[16];
//A function for reading through the device looking for images
while (fread(buffer, BLOCK_SIZE, 1, input)) {
//If a jpeg image is found notify the program(set found = true)
//and start writing the data to a new file
if (is_a_jpeg(buffer)) {
//close the current image file if any
if (img) {
fclose(img);
img = NULL;
}
//Create incrementing filenames for each new picture i.e 000.jpg, 001.jpg etc.
sprintf(filename, "%03d.jpg", name_count);
name_count++;
//Create an empty file and start writing to it
img = fopen(filename, "wb");
if (img == NULL) {
fprintf(stderr, "Could not open output file %s: %s.\n", filename, strerror(errno));
}
}
//Continue writing to a file as soon as it is found until another JPEG image is found
if (img) {
if (!fwrite(buffer, BLOCK_SIZE, 1, img)) {
fprintf(stderr, "Error writing to %s: %s.\n", filename, strerror(errno));
fclose(img);
img = NULL;
}
}
}
//Close all the files
fclose(input);
if (img)
fclose(img);
return 0;
}
//Function to check for a JPEG Image
bool is_a_jpeg(const BYTE *buffer) {
return buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0;
}

memcpy returns junk data when copying from character buffer

I'm attempting to read 4 bytes from the start of a character buffer, but I'm having an issue. memcpy is returning junk.
buffer contains the contents of the file. Using breakpoints I see that the file starts with 41 53 45 46 or ASEF in ASCII. This is the file signature for an Adobe Swatch File.
But when I copy those 4 bytes from a character buffer, to a 4 byte array signature, I get random data.
Any idea what I'm doing wrong here?
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int main(int argc, char **argv)
{
errno_t err = NULL;
FILE *fptr = NULL;
long fileSize = 0;
unsigned char* buffer;
int i, bytesRead;
char signature[4] = { 0 };
err = fopen_s(&fptr, argv[1], "rb");
if (err || fptr == NULL) {
fprintf(stderr, "Could not open file: %s\n", argv[1]);
return 1;
}
// Get filesize
fseek(fptr, 0, SEEK_END);
fileSize = ftell(fptr);
rewind(fptr);
// Allocate memory to store file contents
buffer = malloc(fileSize);
if (buffer == NULL) {
fprintf(stderr, "Could not allocate %i bytes of memory\n", fileSize);
return 1;
}
// Read file contents into buffer
bytesRead = fread(buffer, 1, fileSize, fptr);
if (bytesRead == 0) {
fprintf(stderr, "Failed to read bytes from file: %s\n", argv[1]);
return 1;
}
// Read and check signature
memcpy(signature, &buffer, 4);
fclose(fptr);
return 0;
}
This line is wrong:
memcpy(signature, &buffer, 4);
You want to copy the data in your buffer, not the value of the buffer pointer itself. That means you want:
memcpy(signature, buffer, 4);

Storing .raw File Data as a Pointer Using C

I am attempting to read a '.raw' file which stores the contents of an image that was taken on a camera using C. I would like to store these contents into a uint16_t *.
In the following code I attempt to store this data into a pointer, using fread(), and then write this data into a test file, using fwrite(), to check if my data was correct.
However, when I write the file back it is completely black when I check it.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define MAX_ROW 2560
#define MAX_COL 2160
int main()
{
char filename[32] = "image1.raw";
FILE * image_raw = fopen(filename, "rb");
fseek(image_raw, 0, 2);
long filesize = ftell(image_raw);
/*READ IMAGE DATA*/
uint16_t * image_data_ptr;
image_data_ptr = (uint16_t *)malloc(sizeof(uint16_t)*MAX_ROW*MAX_COL);
fread(image_data_ptr, sizeof(uint16_t), filesize, image_raw);
fclose(image_raw);
/*TEST WRITING THE SAME DATA BACK INTO TEST RAW FILE*/
FILE *fp;
fp = fopen("TEST.raw", "w");
fwrite(image_data_ptr, sizeof(uint16_t), filesize, fp);
fclose(fp);
return 0;
}
There are multiple issues with your code:
lack of error handling.
not seeking the input file back to offset 0 after seeking it to get its size. Consider using stat() or equivalent to get the file size without having to seek the file at all.
not dividing filesize by sizeof(uint16_t) when reading from the input file, or writing to the output file. filesize is expressed in bytes, but fread/fwrite are expressed in number of items of a given size instead, and your items are not 1 byte in size.
not opening the output file in binary mode.
leaking the buffer you allocate.
With that said, try something more like this instead:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main()
{
char filename[32] = "image1.raw";
FILE *image_raw = fopen(filename, "rb");
if (!image_raw) {
fprintf(stderr, "Can't open input file\n");
return -1;
}
if (fseek(image_raw, 0, SEEK_END) != 0) {
fprintf(stderr, "Can't seek input file\n");
fclose(image_raw);
return -1;
}
long filesize = ftell(image_raw);
if (filesize == -1L) {
fprintf(stderr, "Can't get input file size\n");
fclose(image_raw);
return -1;
}
rewind(image_raw);
long numSamples = filesize / sizeof(uint16_t);
/*READ IMAGE DATA*/
uint16_t *image_data_ptr = (uint16_t*) malloc(filesize);
if (!image_data_ptr) {
fprintf(stderr, "Can't allocate memory\n");
fclose(image_raw);
return -1;
}
size_t numRead = fread(image_data_ptr, sizeof(uint16_t), numSamples, image_raw);
if (numRead != numSamples) {
fprintf(stderr, "Can't read samples from file\n");
free(image_data_ptr);
fclose(image_raw);
return -1;
}
fclose(image_raw);
/*TEST WRITING THE SAME DATA BACK INTO TEST RAW FILE*/
FILE *fp = fopen("TEST.raw", "wb");
if (!fp) {
fprintf(stderr, "Can't open output file\n");
free(image_data_ptr);
return -1;
}
if (fwrite(image_data_ptr, sizeof(uint16_t), numSamples, fp) != numSamples) {
fprintf(stderr, "Can't write to output file\n");
fclose(fp);
free(image_data_ptr);
return -1;
}
fclose(fp);
free(image_data_ptr);
return 0;
}
You have already a great answer and useful comments
anyway, consider that if you want to iterate over your file, loaded in memory as a whole, as an array of unsigned words:
if the file size could be odd what to do at the last byte/word
you may read the file as a whole in a single call, after having the file size determined
fstat() is the normal way to get the file size
get the file name from the command line as an argument is much more flexible than recompile the program or change the file name in order to use the program
The code below does just that:
uses image.raw as a default for the file name, but allowing you to enter the file name on the command line
uses fstat() to get the file size
uses a single fread() call to read the entire file as a single record
A test using the original program file as input:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 20/07/2021 17:40 1067 main.c
PS > gcc -Wall -o tst main.c
PS > ./tst main.c
File is "main.c". Size is 1067 bytes
File "main.c" loaded in memory.
PS > ./tst xys
File is "xys". Could not open: No such file or directory
The C example
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char**argv)
{
const char* default_file = "image.raw";
char f_name[256];
if (argc < 2)
strcpy(f_name, default_file);
else
strcpy(f_name, argv[1]);
FILE* F = fopen(f_name, "rb");
if (F == NULL)
{
printf("File is \"%s\". ", f_name);
perror("Could not open");
return -1;
}
struct stat info;
fstat(_fileno(F),&info);
printf("File is \"%s\". Size is %lu bytes\n", f_name, info.st_size);
uint16_t* image = malloc(info.st_size);
if (image == NULL)
{ perror("malloc() error");
return -2;
};
if (fread(image, info.st_size, 1, F) != 1)
{ perror("read error");
free(image);
return -3;
};
// use 'image'
printf("File \"%s\" loaded in memory.\n", f_name);
free(image);
fclose(F);
return 0;
}

How can I get a file's size in C? [duplicate]

This question already has answers here:
How do you determine the size of a file in C?
(15 answers)
Closed 3 years ago.
How can I find out the size of a file I opened with an application written in C ?
I would like to know the size, because I want to put the content of the loaded file into a string, which I allocate using malloc(). Just writing malloc(10000*sizeof(char)); is IMHO a bad idea.
You need to seek to the end of the file and then ask for the position:
fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
You can then seek back, e.g.:
fseek(fp, 0L, SEEK_SET);
or (if seeking to go to the beginning)
rewind(fp);
Using standard library:
Assuming that your implementation meaningfully supports SEEK_END:
fseek(f, 0, SEEK_END); // seek to end of file
size = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file
// proceed with allocating memory and reading the file
Linux/POSIX:
You can use stat (if you know the filename), or fstat (if you have the file descriptor).
Here is an example for stat:
#include <sys/stat.h>
struct stat st;
stat(filename, &st);
size = st.st_size;
Win32:
You can use GetFileSize or GetFileSizeEx.
If you have the file descriptor fstat() returns a stat structure which contain the file size.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
// fd = fileno(f); //if you have a stream (e.g. from fopen), not a file descriptor.
struct stat buf;
fstat(fd, &buf);
off_t size = buf.st_size;
I ended up just making a short and sweet fsize function(note, no error checking)
int fsize(FILE *fp){
int prev=ftell(fp);
fseek(fp, 0L, SEEK_END);
int sz=ftell(fp);
fseek(fp,prev,SEEK_SET); //go back to where we were
return sz;
}
It's kind of silly that the standard C library doesn't have such a function, but I can see why it'd be difficult as not every "file" has a size(for instance /dev/null)
How to use lseek/fseek/stat/fstat to get filesize ?
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
void
fseek_filesize(const char *filename)
{
FILE *fp = NULL;
long off;
fp = fopen(filename, "r");
if (fp == NULL)
{
printf("failed to fopen %s\n", filename);
exit(EXIT_FAILURE);
}
if (fseek(fp, 0, SEEK_END) == -1)
{
printf("failed to fseek %s\n", filename);
exit(EXIT_FAILURE);
}
off = ftell(fp);
if (off == -1)
{
printf("failed to ftell %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] fseek_filesize - file: %s, size: %ld\n", filename, off);
if (fclose(fp) != 0)
{
printf("failed to fclose %s\n", filename);
exit(EXIT_FAILURE);
}
}
void
fstat_filesize(const char *filename)
{
int fd;
struct stat statbuf;
fd = open(filename, O_RDONLY, S_IRUSR | S_IRGRP);
if (fd == -1)
{
printf("failed to open %s\n", filename);
exit(EXIT_FAILURE);
}
if (fstat(fd, &statbuf) == -1)
{
printf("failed to fstat %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] fstat_filesize - file: %s, size: %lld\n", filename, statbuf.st_size);
if (close(fd) == -1)
{
printf("failed to fclose %s\n", filename);
exit(EXIT_FAILURE);
}
}
void
stat_filesize(const char *filename)
{
struct stat statbuf;
if (stat(filename, &statbuf) == -1)
{
printf("failed to stat %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] stat_filesize - file: %s, size: %lld\n", filename, statbuf.st_size);
}
void
seek_filesize(const char *filename)
{
int fd;
off_t off;
if (filename == NULL)
{
printf("invalid filename\n");
exit(EXIT_FAILURE);
}
fd = open(filename, O_RDONLY, S_IRUSR | S_IRGRP);
if (fd == -1)
{
printf("failed to open %s\n", filename);
exit(EXIT_FAILURE);
}
off = lseek(fd, 0, SEEK_END);
if (off == -1)
{
printf("failed to lseek %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] seek_filesize - file: %s, size: %lld\n", filename, (long long) off);
if (close(fd) == -1)
{
printf("failed to close %s\n", filename);
exit(EXIT_FAILURE);
}
}
int
main(int argc, const char *argv[])
{
int i;
if (argc < 2)
{
printf("%s <file1> <file2>...\n", argv[0]);
exit(0);
}
for(i = 1; i < argc; i++)
{
seek_filesize(argv[i]);
stat_filesize(argv[i]);
fstat_filesize(argv[i]);
fseek_filesize(argv[i]);
}
return 0;
}
Have you considered not computing the file size and just growing the array if necessary? Here's an example (with error checking ommitted):
#define CHUNK 1024
/* Read the contents of a file into a buffer. Return the size of the file
* and set buf to point to a buffer allocated with malloc that contains
* the file contents.
*/
int read_file(FILE *fp, char **buf)
{
int n, np;
char *b, *b2;
n = CHUNK;
np = n;
b = malloc(sizeof(char)*n);
while ((r = fread(b, sizeof(char), CHUNK, fp)) > 0) {
n += r;
if (np - n < CHUNK) {
np *= 2; // buffer is too small, the next read could overflow!
b2 = malloc(np*sizeof(char));
memcpy(b2, b, n * sizeof(char));
free(b);
b = b2;
}
}
*buf = b;
return n;
}
This has the advantage of working even for streams in which it is impossible to get the file size (like stdin).
If you're on Linux, seriously consider just using the g_file_get_contents function from glib. It handles all the code for loading a file, allocating memory, and handling errors.
#include <stdio.h>
#define MAXNUMBER 1024
int main()
{
int i;
char a[MAXNUMBER];
FILE *fp = popen("du -b /bin/bash", "r");
while((a[i++] = getc(fp))!= 9)
;
a[i] ='\0';
printf(" a is %s\n", a);
pclose(fp);
return 0;
}
HTH

Resources