Get a segment fault while reading a file - c

I want to read the whole file content and print it out , but I get a segment fault , I can't find what's wrong with the code ...
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE * file;
long fsize;
file = fopen("./input.txt","r");
if(file != NULL){
//get file size
fseek(file,0,SEEK_END);
fsize = ftell(file);
rewind(file);
// print
char * file_content;
fgets(file_content,fsize,file);
puts(file_content);
}
else{
printf("open failure\n");
}
fclose(file);
return 0;
}

The pointer you pass to fgets (file_content) is uninitialized. It should be pointing to a block of memory large enough to contain the specified number (fsize) of bytes. You can use malloc to allocate the memory.
char* file_content = (char*)malloc(fsize);

char * file_content is just a pointer, you need to allocate memory to store the string.
char * file_content;
file_content = malloc(fsize);

"..but I get a segment fault"
Obviously because you're attempting to write to an uninitialized file_content
Allocated memory for file_content before use
char * file_content =malloc(fsize);

Related

Dynamically allocating memory to an array and reading a large text file

I've had a look at some other similar questions and examples but I'm stumped. My goal is to open a very large text file (novel sized), allocate memory to an array, and then store the text into that array so I'm able to do further processing in the future.
This is my current code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINELEN 74
int main(void) {
FILE *file;
char filename[] = "large.txt";
int count = 0, i = 0, len;
/* Open the file */
file = fopen(filename, "r");
if (file == NULL) {
printf("Cannot open file");
return -1;
}
/* Get size of file for memory allocation */
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
/* Allocate memory to the array */
char *text_array = (char*)malloc(size*sizeof(char));
/* Store the information into the array */
while(fgets(&text_array[count], LINELEN, file) != NULL) {
count++;
}
len = sizeof(text_array) / sizeof(text_array[0]);
while(i<len) {
/* printf("%s", text_array); */
i++;
}
printf("%s", text_array);
/* return array */
return EXIT_SUCCESS;
}
I was expecting to have a large body of text printed from text_array at the bottom. Instead I get a garbled mess of random characters much smaller than the body of text I was hoping for. What am I doing wrong? I suspect it has something to do with my memory allocation but don't know what.
Any help is much appreciated.
There's no need to call fgets() in a loop. You know how big the file is, just read the entire thing into text_array with one call:
fread(text_array, 1, size, file);
However, if you want to treat text_array as a string, you need to add a null terminator. So you should add 1 when calling malloc().
Another problem is len = sizeof(text_array) / sizeof(text_array[0]). text_array is a pointer, not an array, so you can't use sizeof to get the amount of space it uses. But you don't need to do that, since you already have the space in the size variable.
There's no need to print text_array in a loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINELEN 74
int main(void) {
FILE *file;
char filename[] = "large.txt";
int count = 0, i = 0, len;
/* Open the file */
file = fopen(filename, "r");
if (file == NULL) {
printf("Cannot open file");
return -1;
}
/* Get size of file for memory allocation */
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
fseek(file, 0, SEEK_SET);
/* Allocate memory to the array */
char *text_array = (char*)malloc(size*sizeof(char) + 1);
/* Store the information into the array */
fread(text_array, 1, size, file);
text_array[size] = '\0';
printf("%s, text_array);
/* return array */
return EXIT_SUCCESS;
}
This part
while(fgets(&text_array[count], LINELEN, file) != NULL) {
count++;
}
is problematic.
If the loop is un-rolled it's "kind of like":
fgets(&text_array[0], LINELEN, file)
fgets(&text_array[1], LINELEN, file)
fgets(&text_array[2], LINELEN, file)
So you only advance the fgetsdestination buffer by a single char between each fgets call. If we assume the fgets reads more than a single character, the second fgets overwrites data from the first fgets. The third fgets overwrites data from the second and so on.
You need to advance the buffer with as many characters as fgets actually read or use another way of reading, e.g. fread.

Tried to call text file and copy the text file to my new variable in C programming

my text file is "Foo bar!!", name foo.txt
So i want to create a new variable in my main function and copy the text file into new variable.
#include <stdio.h>
#include <stdlib.h>
FILE *fopen_with_error (const char *f, const char *mode){
FILE *fp;
if((fp = fopen(f,mode)) == NULL){
printf("Error opening %s\n",f);
exit(EXIT_FAILURE);
}
return fp;
}
int main(int argc, char* argv[]){
FILE *fp;
int a, num;
if(argc != 2){
printf("Usage: program input file\n");
return 0;
}
fp = fopen_with_error(argv[1],"rb");
}
I want to store the copied text into 'a' variable.
I tried to use fread function but everytime i try, it fails somehow.
In addition to using stat to obtain the number of bytes in the file to accurately size your buffer for reading the file into a single variable, you can also use fseek and ftell to accomplish the same thing.
The bigger issue is that you post the contents of a text file with a single-line (e.g. "Foo bar!!") and then proceed to explain you want to read the entire file into a variable. For binary input, that makes more sense. For text, you generally want to read and store individual lines rather than a file-at-once.
(you can store an entire text file line-by-line by using a pointer to pointer to char and allocating pointer and then storage for each line)
Now, don't get me wrong, you can do either, but if you need specific information from each line, and the lines differ in length, etc.., it is a whole lot easier to iterate over pointers than it is trying to scan through one giant buffer of text picking out newlines. You can think through what you need to do with the data you read from the file and make the call.
As your question is written, the basic approach is simply to open the file in binary mode, fseek forward to the end of file, use ftell to report the number of bytes in the file, allocate/validate memory to hold the file, and then read the file using fread into the allocated block of memory. (note: mmap provides another option as well)
Putting that pieces together, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
char *read_file (char* fname, size_t *nbytes)
{
long bytes = 0;
char* file_content;
FILE *file = fopen(fname, "rb");
if (!file) /* validate file open for reading */
return NULL;
fseek (file, 0, SEEK_END); /* fseek end of file */
if ((bytes = ftell (file)) == -1) { /* get number of bytes */
fprintf (stderr, "error: unable to determine file length.\n");
return NULL;
}
fseek (file, 0, SEEK_SET); /* fseek beginning of file */
/* allocate memory for file */
if (!(file_content = malloc (bytes))) { /* allocate/validate memory */
perror ("malloc - virtual memory exhausted");
return NULL;
}
/* read all data into file in single call to fread */
if (fread (file_content, 1, (size_t)bytes, file) != (size_t)bytes) {
fprintf (stderr, "error: failed to read %ld-bytes from '%s'.\n",
bytes, fname);
return NULL;
}
fclose (file); /* close file */
*nbytes = (size_t)bytes; /* update nbytes making size avialable */
return file_content; /* return pointer to caller */
}
int main (int argc, char **argv) {
size_t nbytes;
char *content;
if (argc < 2) { /* validate required argument givent */
fprintf (stderr, "error: insufficient input. filename req'd.\n");
return 1;
}
if ((content = read_file (argv[1], &nbytes))) { /* read/validate */
printf ("read %zu bytes of data from %s\n"
"------content------\n%s\n-------------------\n",
nbytes, argv[1], content);
free (content);
}
return 0;
}
Example Input File
$ cat dat/foo.txt
"Foo bar!!"
Example Use/Output
$ ./bin/freadbinfoo dat/foo.txt
read 12 bytes of data from dat/foo.txt
------content------
"Foo bar!!"
-------------------
Don't forget to use a memory use & error checking program (like valgrind on Linux) to insure there are no memory errors and that you have freed all memory you have allocated.
Here's a simple example of how to do this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(int argc, char **argv) {
char *fname = "./someFileNameHere";
struct stat st;
stat(fname, &st);
char *content = malloc(st.st_size+1);
content[st.st_size] = 0;
FILE *infile = fopen(fname, "rb");
size_t read = fread(content, sizeof(char), st.st_size, infile);
fclose(infile);
puts(content);
return 0;
}
I've left all of the necessary error handling to you.

String / char * concatinate, C

Am trying to open a file(Myfile.txt) and concatenate each line to a single buffer, but am getting unexpected output. The problem is,my buffer is not getting updated with the last concatenated lines. Any thing missing in my code?
Myfile.txt (The file to open and read)
Good morning line-001:
Good morning line-002:
Good morning line-003:
Good morning line-004:
Good morning line-005:
.
.
.
Mycode.c
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[])
{
/* Define a temporary variable */
char Mybuff[100]; // (i dont want to fix this size, any option?)
char *line = NULL;
size_t len=0;
FILE *fp;
fp =fopen("Myfile.txt","r");
if(fp==NULL)
{
printf("the file couldn't exist\n");
return;
}
while (getline(&line, &len, fp) != -1 )
{
//Any function to concatinate the strings, here the "line"
strcat(Mybuff,line);
}
fclose(fp);
printf("Mybuff is: [%s]\n", Mybuff);
return 0;
}
Am expecting my output to be:
Mybuff is: [Good morning line-001:Good morning line-002:Good morning line-003:Good morning line-004:Good morning line-005:]
But, am getting segmentation fault(run time error) and a garbage value. Any think to do? thanks.
Specify MyBuff as a pointer, and use dynamic memory allocation.
#include <stdlib.h> /* for dynamic memory allocation functions */
char *MyBuff = calloc(1,1); /* allocate one character, initialised to zero */
size_t length = 1;
while (getline(&line, &len, fp) != -1 )
{
size_t newlength = length + strlen(line)
char *temp = realloc(MyBuff, newlength);
if (temp == NULL)
{
/* Allocation failed. Have a tantrum or take recovery action */
}
else
{
MyBuff = temp;
length = newlength;
strcat(MyBuff, temp);
}
}
/* Do whatever is needed with MyBuff */
free(MyBuff);
/* Also, don't forget to release memory allocated by getline() */
The above will leave newlines in MyBuff for each line read by getline(). I'll leave removing those as an exercise.
Note: getline() is linux, not standard C. A function like fgets() is available in standard C for reading lines from a file, albeit it doesn't allocate memory like getline() does.

Basic read/write clarification in C

I'm trying to understand how to read and write in C. Would this store entries from the binary file into the buffer until the end of file.
unsigned char *buffer = (char*) malloc (sizeof(char) * SIZE);
FILE *file = fopen(FILEPATH, "rb");
if(file == NULL){
//error
} else {
while(!feof(file)){
fread(&buffer, SIZE*sizeof(char), 1, file);
// Print out buffer (should be different everytime assume I have different numbers in the file)
}
}
Or would I have to use fseek somewhere there?
Vice-versa to write something to a document would this work? Thanks
unsigned char *buffer = (char*) malloc (sizeof(char) * SIZE);
FILE *file = fopen(FILEPATH, "wb");
for(int i=0; i<SIZE; i++){
// put something into buffer based on i
fwrite(&buffer, SIZE*sizeof(char), 1, file);
}
No, that would probably crash. :)
You're taking the address of buffer, which is already a pointer: this is wrong. Just pass buffer directly to fread(). The value of buffer and &buffer are only the same when buffer is an array; not when it's allocated on the heap like your is.
Don't use feof(), rely on the return value of fread().
Don't cast the return value of malloc() in C.
Don't scale allocations by sizeof (char), that's always 1 so it adds nothing.

Segmentation fault in file accessing

May I just ask why this piece of code is resulting to a segmentation fault. I'm trying to get input from a text file and I can't figure out what is the problem.
using namespace std;
using namespace cv;
int main()
{
char str[50];
FILE *trainfile;
int k, n, maxval1, maxval2, classnum;
char dataArray[n][3];
trainfile = fopen("training.txt", "r+");
if(trainfile == NULL){
perror("Cannot open file.\n");
}else{
while(!feof(trainfile)){
fscanf(trainfile, "%s", str);
}
}
fclose(trainfile);
return 0;
}
int k, n, maxval1, maxval2, classnum;
char dataArray[n][3];
n is not initialized, so it can be any value and hence your code has an Undefined Behavior.
err...its not used anyways.
The other problem in code is your data buffer:
char str[50];
should be big enough to hold the contents of the file, which it probably is not and causes an Undefined Behavior.
One problem is that your buffer might not be big enough.
You should get the size of the file first, then make a dynamic buffer of that size, and then finally read the file.
fseek(trainfile,0,SEEK_END); //Go to end
int size = ftell(trainfile); //Tell offset of end from beginning
char* buffer = malloc(size); //Make a buffer of the right size
fseek(ftrainfile,0,SEEK_SET); //Rewind the file
//Read file here with buffer

Resources