#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
// Only allow 2 command line arguments
if (argc != 2)
{
printf("Usage: ./recover FILENAME\n");
return 1;
}
// Open the file
FILE *input_file = fopen(argv[1], "r");
// Check if the input_file file is a valid ifle
if (input_file == NULL)
{
printf("No existing file");
return 1;
}
// Make a buffer for storing 512 bytes, !unsigned because our values MUSTN'T be negative!
unsigned char buffer[512];
// Count the number of images we found
int image_count = 0;
// Make a pointer for recovered images
FILE *output_file = NULL;
// Use malloc for memory allocation
char *filename = malloc(8 * sizeof(char));
// Read the blocks of our array
while (fread(buffer, sizeof(char), 512, input_file))
{
// Check for JPEG header hex values
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0 )
{
// Set the names of the JPEG files
sprintf(filename, "%03i.jpg", image_count);
// Open the file we will write to
output_file = fopen(filename, "w");
// Count the number of images we found
image_count++;
}
// Check validity of input output_file input
if (output_file != NULL)
{
fwrite(buffer, sizeof(char), 512, output_file);
}
// Free the memory becuase we used malloc (to prevent leaking/segmentation fault)
free(filename);
// Close both the input and output files
fclose(output_file);
fclose(input_file);
return 0;
}
}
I am trying to solve this CS50 problem set and i don't get why I'm getting segmentation fault even though i freed memory. I obviously did something wrong, but i can't wrap my head around what exactly because I am only a begginer in c, especially with all this malloc stuff. Also, I can compile my code, it's only that I get an error when running the program.
You're freeing inside the loop. i.e. you allocate once but try to free it several times.
You want to free it just once. Put it outside the loop.
OTOH, since you know the filenames are only 7 bytes long, you might as well use a char array instead of mallocing.
char filename[256];
Then use snprintf:
snprintf(filename, sizeof filename, "%03i.jpg", image_count);
Related
I am doing the CS50 PSet 4 Recover problem and get the below error:
program is free of memory errors
valgrind tests failed; see log for more information.
I don't understand what is the error, and therefore not sure how to fix it. I've tried using the debugger but it doesn't help.
My code is the below:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
// Check number of arguments
if (argc != 2)
{
printf("Only one argument should be used\n");
return 1;
}
// Open reading file
FILE *input_file = fopen(argv[1], "r");
if (input_file == NULL)
{
printf("Could not open file.\n");
return 2;
}
// Store blocks of 512 bytes in an array
BYTE buffer[512];
// Keep track of number of images generated
int count_image = 0;
// File pointer for recovered images
FILE *output_file = NULL;
// Char filename
char *filename = malloc (8 * sizeof(char));
// Read the blocks of 512 bytes
while (fread(buffer, sizeof(char), 512, input_file))
{
// Check if the bytes indicate start of JPEG
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
// Write the JPEG filenames
sprintf(filename, "%03i.jpg", count_image);
// Open output file for writing
output_file = fopen(filename, "w");
// Count number of images found
count_image++;
}
if (output_file != NULL)
{
fwrite(buffer, sizeof(char), 512, output_file);
}
}
free(filename);
fclose(output_file);
fclose(input_file);
return 0;
}
Can someone please explain what I'm doing wrong? Valgrind says there's an error with the line:
output_file = fopen(filename, "w");
But where in your code would you close 50 files? You open them in a loop but only close once after the loop. You must close the old file whenever you open a new one. Otherwise the pointer to the old FILE structure is lost and you can never close the file resulting in 49 memory leaks.
I have been working on an assignment that recovers deleted data from the memory card so that the image is viewable. My code compiles and runs fine and produces viewable jpeg images. The program also automatically titles the jpeg image by assigning a number to it. However, when I run it, it is only able produce about half of the images. The other half were unviewable, with random numbers as titles and the error 'unsupported image format' is shown. I'm not too sure what went wrong with my code and I'm fairly new to the intricacies but I suspect it has something to do with memory. Here is my code, any help would be really nice:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
bool function(unsigned char arr[], FILE *pointer);
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr,"Usage: ./recover image");
return 1;
}
// opening the memory card
FILE *memorycard = fopen(argv[1], "r");
if (memorycard == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
unsigned char buffer[512];
int i = 0;
char filename[8];
while(fread(buffer,1, 512, memorycard) == 512)
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
//create a new file
sprintf(filename, "%03i.jpg", i);
//write the values currently stored in the buffer to the file
FILE *img = fopen(filename, "w");
fwrite(buffer, sizeof(char), 512, img);
memset (buffer, 0, 512);
//add one to the title of the next jpeg file
i++;
do
{
//read the next chunk of 512 bytes
fread(buffer,1, 512, memorycard);
}
while (function(buffer, img) == true);
}
}
}
bool function(unsigned char arr[], FILE *pointer)
{
if (arr[0] == 0xff && arr[1] == 0xd8 && arr[2] == 0xff && (arr[3] & 0xf0) == 0xe0)
{
//rewind by 512 bytes
fseek(pointer, -512, SEEK_CUR);
//close file being written to
fclose(pointer);
memset (arr, 0, 512);
return false;
}
else
{
//write values into the currently opened file
fwrite(arr, sizeof(char), 512, pointer);
memset(arr, 0, 512);
return true;
}
}
I changed a couple things in your code. In general try to always keep the file "cursor" moving in one direction (try not to seek backwards too much) because this can ruin time complexity especially for large sd cards. This is the modified code I came up with let me know if it works or might clear anything up for you. I haven't actually run this because I don't have anything to test with; however it should work in theory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
struct _imgblock{
// The first 4 bytes have a magic sequence and it is just easier to view them all as 1 integer
int32_t magicTag;
char buffer[508];
}__attribute__((packed));
typedef union{
struct _imgblock imageBlock;
unsigned char dataBuffer[512];
} Buffer;
// make sure this function matches the sequence sepcified in the original code (that the low order byte & 0xf0 is 0xe0 and the other bytes match 0xffd8ff)
bool buffer_starts_with_magic(Buffer* buff){
return (buff->imageBlock.magicTag & 0xf0) == 0xe0 && (buff->imageBlock.magicTag >> 8) & 0xffd8ff;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr,"Usage: ./recover image");
return 1;
}
// opening the memory card
FILE *memorycard = fopen(argv[1], "r");
if (memorycard == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
Buffer custom_buff;
int i = 0;
char filename[8];
FILE* openFile = NULL;
// Start reading 512 byte buffers from the file
while(fread(&custom_buff,1, sizeof(Buffer), memorycard) == sizeof(Buffer))
{
// If the buffer starts with the magic sequence found in the original code and a file is open
if(buffer_starts_with_magic(&custom_buff) && openFile){
// then end the current file and start a new one
fclose(openFile);
openFile = NULL;
}else if(openFile){
// else if the buffer doesnt start with the magic sequence append data and keep reading
goto appendBuffer;
}
//create the new file
sprintf(filename, "%03i.jpg", i++);
openFile = fopen(filename,"w");
appendBuffer: fwrite(custom_buff.dataBuffer,1,512,openFile);
}
if(openFile)
fclose(openFile);
openFile = NULL;
fclose(memorycard);
}
I am trying to use fread on a file containing multiple JPEGs and write the JPEGs into new files, but before I can do that I need to properly look through the file and look for the JPEGs based on their first bytes based on the if statement at the bottom of the code below.
I have not been able to get into the if statement, and have been trying to print out the bytes, but I have been running into issues in printing.
I'm looking to print just the 0 byte of the buffer, but my output is looking like this:
711151a6
cec117f0
7603c9a9
73599166
I'm very new to C and fread, and any help would be appreciated!
Code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// Check for 2 arguments, the name of the program and the file being read
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
else
{
//Open the file
FILE * fp;
fp = fopen(argv[1], "r");
//Get file length
fseek(fp, 0, SEEK_END);
int f_length = ftell(fp);
fseek(fp, 0, SEEK_SET);
// If not file is found then exit
if(fp == NULL)
{
printf("File not found\n");
return 2;
}
// Allocate buffer for fread function
int *buffer = (int*)malloc(f_length);
if (buffer == NULL)
{
printf("Buffer is null\n");
return 1;
}
// Read thorugh the file
while(fread(buffer, 512, 1, fp) == 1)
{
for (int i = 0; i < 1; i++)
{
printf("%x\n", buffer[i]);
}
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
printf("Found a jpg\n");
}
}
// Exit the program
return 0;
}
}
int *buffer is not correct because the intention is to deal with bytes and not ints. If int * is used, then for example, buffer[0] will be the first 4 bytes and not the first byte as intended. Change that to unsigned char *buffer.
So explicitly, that line should be the following (including removing the unnecessary cast):
unsigned char *buffer = malloc(f_length);
I'm working on an assignment for CS50 but i have a strange behaviour of a counter variable after running sprintf function:
//recover jpg files from memory
#include <stdio.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 2)
{
fprintf(stderr, "Please submit an input file\n");
return 1;
}
// remember filename
char *infile = argv[1];
// open input file
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", infile);
return 2;
}
// define the buffer as array of BYTEs
BYTE buffer[512];
// define the counter of images found
int counter = 0;
// declare the array for the filename
char filename[3];
while (fread(buffer, 512, 1, inptr)>0)
{
if (buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0)
{
sprintf(filename, "%03i.jpg", counter);
printf("%c%c%c\n", filename[0],filename[1],filename[2]);
counter++;
}
}
}
I tried the debug50 tool and i saw that after running fprintf variable counter passes from 0 to a big strange number.
Any suggestions on where is the problem and how to fix it?
Thanks to the comments I got the error:
I forgot to consider the right length of 'filename' variable, and when running sprintf i was exceeding the memory allowed for it
It's a solution of CS50-pset4 recover. But why I am getting segmentation fault?
I tried to not access any NULL pointer ar any uninitialized file, but can't figure the way out.
The intent was to copy block of 512B memory from a given file to another if it matches the condition of being a jpeg file. And it is assumed that the jpeg files are stored in a contiguous memory location.
$
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 2)
{
fprintf(stderr, "Usage: copy infile outfile\n");
return 1;
}
// remember filename
char *infile = argv[1];
// open input file
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", infile);
return 2;
}
FILE *img = NULL;
unsigned char buffer[512] = {0};
//char *jpgname = NULL;
string jpegname = "";
int jpegnum = 0; // for keep track of jpeg no.
//sprintf(jpgname, "%03d.jpg", jpegnum+1);
//jpegnum += 1;
while (fread(buffer, 512, 1, inptr) == 1)
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff &&
((buffer[3] & 0xf0) == 0xe0))
{
if (jpegnum > 0) // if there exist a jpeg file, it should close first
{
fclose(img);
}
sprintf(jpegname, "%03d.jpg", (jpegnum+1));
jpegnum += 1;
img = fopen(jpegname, "w");
//fwrite(buffer, 512, 1, img);
}
else if (jpegnum == 0)
{
continue;
}
fwrite(buffer, 512, 1, img);
}
fclose(img);
fclose(inptr);
return 0;
}
$
A string literal "" is assigned to jpegname and it is passed to sprintf().
This is bad because
Modifying string literals is forbidden.
Even if modifying were allowed, "" has only 1 element (for the terminating null character) and it won't be enough for saving the filename.
Try using
char jpegname[512] = "";
instead of
string jpegname = "";
This change will give modifiable 512-byte buffer to jpegname, which will be enough for the filename.
Also note that passing img, whose value is NULL, to fclose() should be bad.