fscanf() seg fault Program received signal EXC_BAD_ACCESS - c

16 char* input = (char*) argv[1];
17 FILE *fp = fopen (input, "r");
18 if( fp == NULL)
19 {
20 printf(" reading input file failed");
21 return 0;
22 }
23 fseek(fp,0,SEEK_END);
24 int file_size = ftell(fp);
29 rewind(fp);
30 int i;
31 int totalRun;
32 char * temp;
33 char* model;
34 char* example;
36 fscanf(fp,"%d",&totalRun);
37 fscanf(fp,"%s",model);
Above is my code I get this error at line 37 "fscanf(fp,"%s".model)"
Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5fc00730 0x00007fff8db20bcb in __svfscanf_l ()
What can cause this ?? I looked into *fp in gdb. before reading totalRun _offset = 0 and after reading _offset = 4096. content of totalRun was correct ("3"). I only read one line and why is offset 4096? Also what is _blksize referring to in FILE.
Thank you

You need to allocate memory for model, it is an uninitialised pointer. Also ensure fscanf() does not read beyond the array assigned to model. If model does not need to by dynamically allocated then just use a local array. For example:
char model[1024];
if (1 == fscanf(fp, "%1023s", model))
{
}
Always check the return value of fscanf(), which returns the number of successful assignments, otherwise the program will be processing uninitialised variables if the call to fscanf() fails.

The variable model is not initalized. You must allocated memory for it before it can be used in the fscanf() method. You can do in two ways:
Statically - char model[1024];
Dynamically - char * model = (char*) malloc(1024); Don't forget to use free() to deallocate the buffer once you are done.

Related

Is there a way to stop fread reading characters into an array in a struct following a whitespace?

I'm attempting to do homework for my second-semester programming class in which we have to read data from a file like this:
Fred 23 2.99
Lisa 31 6.99
Sue 27 4.45
Bobby 456 18.844
Ann 7 3.45
using structs in fread. I'll eventually have to create a loop to read all of the data then convert it to binary and write it to a file but this is as far as I've gotten before running into a problem:
struct data
{
char name[25];
int iNum;
float fNum;
};
int main(int argc, char *argv[])
{
struct data mov;
FILE *fp;
fp = fopen(argv[1], "r");
fread(&mov, sizeof(struct data), 1, fp);
printf(" name: %s\n int: %d\n float: %f\n", mov.name, mov.iNum, mov.fNum);
return 0;
}
The problem I'm having is that fread will read the first 25 characters into the array instead of stopping at the first whitespace, so it produces output like this:
name: Fred 23 2.99
Lisa 31 6.99
Sue 27 4.4
int: 926031973
float: 0.000000
instead of the desired result, which would be something more like:
name: Fred
int: 23
float: 2.99000
From what I've read, I believe this is how fread is supposed to function, and I'm sure there's a better way of going about this problem, but the assignment requires we use fread and a 25 character array in our struct. What's the best way to go about this?
Is there a way to stop fread reading characters into an array in a
struct following a whitespace?
Answer: Yes (but not with fread directly, you'll need a buffer to accomplish the task)
The requirement you use fread to parse formatted-text from an input file is certainly an academic exercise (a good one at that), but not something you would normally do. Why? Normally when you are concerned with reading lines of data from a file, you use a line-oriented input function such as fgets() or POSIX getline().
You could also use the character-oriented input function fgetc() and simply read from the file, buffering the input, until the '\n' is found, do what you need with the buffer and repeat. Your last normal option (but discouraged due to it fragility) is to use a formatted-input function like fscanf() -- but its misuse accounts for a significant percentage of questions on this site.
But, if for an academic challenge, you must use fread(), then as mentioned in the comments you will want to read the entire file into an allocated buffer, and then parse that buffer as if you were reading it a line-at-a-time from the actual file. sscanf would be used if reading with fgets() and it can be used here to read from the buffer filled with fread(). The only trick is keeping track of where you are within the buffer to start each read -- and knowing where to stop.
With that outline, how do you approach reading an entire file into a buffer with fread()? You first need to obtain the file length to know how much space to allocate. You do that either by calling stat or fstat and utilizing the st_size member of the filled struct stat containing the filesize, or you use fseek to move to the end of the file and use ftell() to report the offset in bytes from the beginning.
A simple function that takes an open FILE* pointer, saves the current position, moves the file-position indicator to the end, obtains the file-size with ftell() and then restores the file-position indicator to its original position could be:
/* get the file size of file pointed to by fp */
long getfilesize (FILE *fp)
{
fpos_t currentpos;
long bytes;
if (fgetpos (fp, &currentpos) == -1) { /* save current file position */
perror ("fgetpos");
return -1;
}
if (fseek (fp, 0, SEEK_END) == -1) { /* fseek end of file */
perror ("fseek-SEEK_END");
return -1;
}
if ((bytes = ftell (fp)) == -1) { /* get number of bytes */
perror ("ftell-bytes");
return -1;
}
if (fsetpos (fp, &currentpos) == -1) { /* restore file positon */
perror ("fseek-SEEK_SET");
return -1;
}
return bytes; /* return number of bytes in file */
}
(note: above each step is validated and -1 is returned on error, otherwise the file-size is returned on success. Make sure you validate each step in your program and always provide a meaningful return from your functions that can indicate success/failure.)
With the file-size in hand, all you need to do before calling fread() is to allocate a block of memory large enough to hold the contents of the file and assign the starting address to that block of memory to a pointer that can be used with fread(). For example:
long bytes; /* size of file in bytes */
char *filebuf, *p; /* buffer for file and pointer to it */
...
if ((bytes = getfilesize (fp)) == -1) /* get file size in bytes */
return 1;
if (!(filebuf = malloc (bytes + 1))) { /* allocate/validate storage */
perror ("malloc-filebuf");
return 1;
}
(we will talk about the + 1 later on)
Now you have adequate storage for your file and the address for the storage is assigned to the pointer filebuf, you can call fread() and read the entire file into that block of memory with:
/* read entire file into allocated memory */
if (fread (filebuf, sizeof *filebuf, bytes, fp) != (size_t)bytes) {
perror ("fread-filebuf");
return 1;
}
Now your entire file is stored in the block of memory pointed to by filebuf. How do you parse the data line-by-line into your struct (or actually an array of struct so each record is stored within a separate struct)? It's actually pretty easy. You just read from the buffer and keep track of the number of characters used to read up until a '\n' is found, parsing the information in that line into a struct element of the array, add the offset to your pointer to prepare for the next read and increment the index on your array of struct to account for the struct you just filled. You are essentially using sscanf just as you would if you read the line from the file with fgets(), but you are manually keeping track of the offset within the buffer for the next call to sscanf, e.g.
#define NDATA 16 /* if you need a constant, #define one (or more) */
#define MAXC 25
struct data { /* your struct with fixed array of 25-bytes for name */
char name[MAXC];
int iNum;
float fNum;
};
...
struct data arr[NDATA] = {{ .name = "" }}; /* array of struct data */
int used; /* no. chars used by sscanf */
size_t ndx = 0, offset = 0; /* array index, and pointer offset */
...
filebuf[bytes] = 0; /* trick - nul-terminate buffer for sscanf use */
p = filebuf; /* set pointer to filebuf */
while (ndx < NDATA && /* while space in array */
sscanf (p + offset, "%24s %d %f%n", /* parse values into struct */
arr[ndx].name, &arr[ndx].iNum, &arr[ndx].fNum, &used) == 3) {
offset += used; /* update offset with used chars */
ndx++; /* increment array index */
}
That's pretty much it. You can free (filebuf); now that you are done with it and all the values are now stored in your array of struct arr.
There is one important line of code above we have not talked about -- and I told you we would get to it later. It is also something you wouldn't normally do, but it mandatory where you are going to process the buffer as text with sscanf, a function normally used to process strings. How will you ensure sscanf knows were to stop reading and doesn't continue reading beyond the bounds of filebuf?
filebuf[bytes] = 0; /* trick - nul-terminate buffer for sscanf use */
That's where the + 1 on the allocated size comes into play. You don't normally terminate a buffer -- there is no need. However, if you want to process the contents of the buffer with functions normally used to process strings -- then you do. Otherwise, sscanf will continue to read past the final '\n' in the buffer off into memory you cannot validly access until it finds a random 0 somewhere in the heap. (with the potential of filling additional additional structs with garbage if they happen to satisfy the format-string)
Putting it altogether, you could do:
#include <stdio.h>
#include <stdlib.h>
#define NDATA 16 /* if you need a constant, #define one (or more) */
#define MAXC 25
struct data { /* your struct with fixed array of 25-bytes for name */
char name[MAXC];
int iNum;
float fNum;
};
long getfilesize (FILE *fp); /* function prototype for funciton below */
int main (int argc, char **argv) {
struct data arr[NDATA] = {{ .name = "" }}; /* array of struct data */
int used; /* no. chars used by sscanf */
long bytes; /* size of file in bytes */
char *filebuf, *p; /* buffer for file and pointer to it */
size_t ndx = 0, offset = 0; /* array index, and pointer offset */
FILE *fp; /* file pointer */
if (argc < 2) { /* validate at least 1-arg given for filename */
fprintf (stderr, "error: insufficient arguments\n"
"usage: %s <filename>\n", argv[0]);
return 1;
}
/* open file / validate file open for reading */
if (!(fp = fopen (argv[1], "rb"))) {
perror ("file open failed");
return 1;
}
if ((bytes = getfilesize (fp)) == -1) /* get file size in bytes */
return 1;
if (!(filebuf = malloc (bytes + 1))) { /* allocate/validate storage */
perror ("malloc-filebuf");
return 1;
}
/* read entire file into allocated memory */
if (fread (filebuf, sizeof *filebuf, bytes, fp) != (size_t)bytes) {
perror ("fread-filebuf");
return 1;
}
fclose (fp); /* close file, read done */
filebuf[bytes] = 0; /* trick - nul-terminate buffer for sscanf use */
p = filebuf; /* set pointer to filebuf */
while (ndx < NDATA && /* while space in array */
sscanf (p + offset, "%24s %d %f%n", /* parse values into struct */
arr[ndx].name, &arr[ndx].iNum, &arr[ndx].fNum, &used) == 3) {
offset += used; /* update offset with used chars */
ndx++; /* increment array index */
}
free (filebuf); /* free allocated memory, values stored in array */
for (size_t i = 0; i < ndx; i++) /* output stored values */
printf ("%-24s %4d %7.3f\n", arr[i].name, arr[i].iNum, arr[i].fNum);
return 0;
}
/* get the file size of file pointed to by fp */
long getfilesize (FILE *fp)
{
fpos_t currentpos;
long bytes;
if (fgetpos (fp, &currentpos) == -1) { /* save current file position */
perror ("fgetpos");
return -1;
}
if (fseek (fp, 0, SEEK_END) == -1) { /* fseek end of file */
perror ("fseek-SEEK_END");
return -1;
}
if ((bytes = ftell (fp)) == -1) { /* get number of bytes */
perror ("ftell-bytes");
return -1;
}
if (fsetpos (fp, &currentpos) == -1) { /* restore file positon */
perror ("fseek-SEEK_SET");
return -1;
}
return bytes; /* return number of bytes in file */
}
(note: approximately 1/2 the lines of code are devoted to validating each step. That is normal and critical to ensure you don't invoke Undefined Behavior by blindly continuing forward in your code after a failure occurs that prevents you from processing valid data.)
Example Use/Output
With that you program is complete and you should be able to parse the data from the buffer filled by fread() having stopped at all appropriate times following a whitespace.
$ ./bin/freadinumfnum dat/inumfnum.txt
Fred 23 2.990
Lisa 31 6.990
Sue 27 4.450
Bobby 456 18.844
Ann 7 3.450
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/freadinumfnum dat/inumfnum.txt
==5642== Memcheck, a memory error detector
==5642== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==5642== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==5642== Command: ./bin/freadinumfnum dat/inumfnum.txt
==5642==
Fred 23 2.990
Lisa 31 6.990
Sue 27 4.450
Bobby 456 18.844
Ann 7 3.450
==5642==
==5642== HEAP SUMMARY:
==5642== in use at exit: 0 bytes in 0 blocks
==5642== total heap usage: 2 allocs, 2 frees, 623 bytes allocated
==5642==
==5642== All heap blocks were freed -- no leaks are possible
==5642==
==5642== For counts of detected and suppressed errors, rerun with: -v
==5642== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.

Reading file line by line with fgets in C, invalid read of size [duplicate]

This question already has answers here:
Valgrind on OS X Yosemite, giving bogus errors? [duplicate]
(4 answers)
Closed 7 years ago.
I keep getting a valgrind error in my code, and after three hours I remain clueless so I need your help people.
So I basically just read files contained in a directory and parse them, So I copied the shortest example of my code still producing the error:
int main(int argc, char** argv) {
parse_files_dir("/Users/link_to_dir_example/");
return (EXIT_SUCCESS);
}
void parse_files_dir(char *dirLink){
int dLink_l =strlen(dirLink);
int max_len = dLink_l*2;
char* full_path=malloc(sizeof(char)*(max_len+1));
//check if null pointer...
strncpy(full_path, dirLink, dLink_l);
DIR *dir;
struct dirent *dir_con;
dir=opendir(dirLink);
if (dir == NULL){
fprintf(stderr, "Problem opening directory: \"%s\". Aborting...\n", dirLink);
exit(EXIT_FAILURE);
}
while((dir_con = readdir(dir)) != NULL){
if (dir_con->d_name[0] == '.') continue;
if (dLink_l+strlen(dir_con->d_name)>max_len) //realloc full path..
strncpy(&full_path[dLink_l], dir_con->d_name, strlen(dir_con->d_name));
full_path[dLink_l+strlen(dir_con->d_name)] = '\0';
parse_one_file(full_path); // (*) <=== valgrind complain
full_path[dLink_l] = '\0';
}
free(full_path);
closedir(dir);
}
So now the actual problem method:
void parse_one_file(char* link) {
FILE *file = fopen(link, "r");
if (file == NULL) //error message
int line_len=0;
int line_max=1000;
char* line= malloc(sizeof(char)*line_max);
line[0] = '\0';
char* line_full= malloc(sizeof(char)*line_max);
line_full[0] = '\0';
int line_full_len = 0;
//check all allocations for null pointers
while(fgets(line, line_max, file) != NULL){ // <=== Here is where valgrind complains !!!!
line_len = strlen(line);
if (line[line_len-1] == '\n'){
strncpy(&line_full[line_full_len], line, line_len);
line_full_len+=line_len;
}
else{
//Check if line_full has enough memory left
strncpy(&line_full[line_full_len], line, line_len);
line_full_len+=line_len;
}
line[0] = '\0';
}
free(line);
free(line_full);
fclose(file);
}
I keep getting the error:
==4929== Invalid read of size 32
==4929== at 0x1003DDC1D: _platform_memchr$VARIANT$Haswell (in /usr/lib/system/libsystem_platform.dylib)
==4929== by 0x1001CF66A: fgets (in /usr/lib/system/libsystem_c.dylib)
==4929== by 0x100000CD8: parse_one_file (main.c:93)
==4929== by 0x100000B74: parse_files_dir (main.c:67)
==4929== by 0x100000944: main (main.c:28)
==4929== Address 0x100804dc0 is 32 bytes before a block of size 4,096 in arena "client"
So i really dont see where my mistake is, I keep emptying the buffer line, I never read more bytes than allocated there.
The interesting thing I noticed is, if the directory "dirLink" has only one file, the error does not occur, however if I have two or more, the error occurs, so I thought the mistake is how I generate the path "full_path", but then I replaced line "*" with (just for testing reasons)
parse_one_file("another/example/path/");
and the error remained..
Unless your file is less than 1000 bytes in total you are writing over the end of the line_full buffer which is only 1000 bytes total in size. This will invariably clobber your memory and lead to spurious errors like the one you experience in fgets.
if(line[line_len-1] == '\n'){
strncpy(&line_full[line_full_len], line, line_len);
line_full_len+=line_len;
}
This is not quite correct, you can only strncpy() (line_max - line_full_len) bytes, there is no guarantee that you can copy line_len bytes. Or in other words. starting from position line_full[500], you can't write another 1000 bytes.
The same error is in the else branch.

Access violation when searching through a file

This is my algorithm for searching a term into a file.
void ricerca_file(char* frase){
char* prelievo = "";
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
if((strstr(prelievo, frase)) != NULL)
printf("frase trovata!\n");
}
fclose(file);
printf("%s", prelievo);}
i ask the input of frase in this way:
char* frase = "";
printf("insert the term that you want to search..");
scanf("%s", frase);
and then i call the function with:
ricerca_file(frase);
The compiler gives me this error after i write the input (e.g the number 2):
prove1.exe: 0xC0000005: Access violation writing location 0x00F67BC3.
If there is a handler for this exception, the program may be safely
continued.
What am i doing wrong?
if it wasn't clear, i'm learning. But i didn't really got how to manage the search of a term into a file.
I guess that with this algorithm i can miss lots of matches because if i search for "hello", with the strstr function that moves 5 characters per cycle if i have a file with a text like this "abchelloabc" he will first find "abche" and will not find anything, while after the first cycle it will go to the "lloab" part and then "c". Am i right thinking that it works like that and this is wrong?
prelievo points to a string literal. This is constant data that cannot be written to. And sizeof(prelievo) will be 2 or 4 (or whatever size pointers are on your system), which is not what you want.
You'll need to instead point prelievo to an array of characters that can be modified:
char prelievo[1000];
The same problems and solution apply to frase:
char frase[1000];
You need to actually provide memory to save the string you scan into. Try something like this instead:
char frase[80];
printf("insert the term that you want to search..");
fgets(frase, 80, stdin);
This allocates enough space for 80 characters and then reads one line of input.
Please also check the results of all these functions: If they return an error, you should act appropriately.
what am I doing wrong:
regarding:
char* prelievo = "";
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
...
The call to fgets() needs to have a pointer to a buffer as its' first parameter.
The 'prelievo' is only an uninitalized pointer.
suggestion 1)
char* prelievo = malloc( 1024 );
if ( prelievo ) {
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
suggestion 2)
char prelievo[1024];
file = fopen("*userpath*\\file.bin", "rb");
while((fgets(prelievo, sizeof(prelievo), file)) != NULL){
This answer is not exactly related to your problem, but because you already got your Answers i will try to explain you about some problems if you ignore them.
If we do not check for errors/return and the program works fine this does not mean that the program is ok or safe.
Let's take the following scenario as an Example.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char *printFile(char *fileName){
size_t length,size;
char *buffer;
FILE *file;
file = fopen (fileName , "r" );
fseek (file , 0 , SEEK_END);
length = (size_t)ftell (file);
fseek (file , 0 , SEEK_SET);
buffer = malloc(length);
if (buffer == NULL){
fputs ("Memory error",stderr);
exit (2);
}
size = fread (buffer,1,length,file);
if (size != length){
fputs ("Reading error",stderr);
exit(3);
}
fclose (file);
return buffer;
}
int main (void) {
char *fileName = "test.txt";
char *stringToSearch = "Addams";
char *fileContent = printFile(fileName);
if (strstr(fileContent, stringToSearch)){
printf("%s was Found\n",stringToSearch);
}else{
printf("%s was not Found\n",stringToSearch);
}
free(fileContent);
return 0;
}
The file test.txt has the following content:
Michael Jackson
Bryan Addams
Jack Sparrow
So now if I run this program I get:
Addams was Found
Everything seems to be ok, but what happens if I try to share this program with someone ? Or what happens if I try to run it on another computer ?
well:
Segmentation fault (core dumped)
OMG, what did just happen now ? Simple,the file test.txt is missing and i did not check that in my program that's why.
Lets move on and create that file and run that program again:
Addams was not Found
Huh, I succeeded isn't ? Well not, valgrind has another opinion:
==3657== Invalid read of size 1
==3657== at 0x4C32FF4: strstr (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3657== by 0x400A2D: main (in /home/michi/program)
==3657== Address 0x54202b0 is 0 bytes after a block of size 0 alloc'd
==3657== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3657== by 0x40095E: printFile (in /home/michi/program)
==3657== by 0x400A16: main (in /home/michi/program)
What happens is that I try to read a file which was newly created without thinking if that file has some content and i performed a lot of codding on it.

fscanf fails to read data from txt file

I am trying to run my code on eclipse with ubuntu.
I have dumped the data using fprintf into one txt file and reading that file by using fscanf. I am not able to read that values into data array.
Below is my code :
#include <stdio.h> /* printf, scanf, NULL */
#include <stdlib.h> /* malloc, free, rand */
int main(){
char* data;
FILE *fp;
size_t result;
data = (char*) malloc (sizeof(char)*(1280*800));//Size of one frame
if (data==NULL){
printf("NOt able to allocate memory properly\n");
exit (1);
}
fp = fopen ("\\home\\studinstru\\Desktop\\filedump.txt", "r");
if(fp==NULL){
printf("Error in creating dump file\n");
exit (1);
}
for(int m = 0;m<1280;m++){
for(int n = 0;n<800;n++){
fscanf(fp,"%d/t",data[m*800 + n]);
}
}
fclose(fp);
return 0;
}
This is my filedump.txt data :
79 78 78 77 78 79 81 95
82 81 81 81 82 82 82 82
79 78 78 77 78 79 81 95
82 81 81 81 82 82 82 82
79 78 78 77 78 79 81 95
82 81 81 81 82 82 82 82 ....
Can you tell what is wrong in this?
Your code has a couble of problems
Your fscanf() format is wrong and you are passing the value instead of it's address, you should use
fscanf(fp, "%d", &data[n + 800 * m]);
if you meant "\t" whcih is the tab character, it's not needed anyway and passing the value instead of it's address is Undefined Behavior, because fscanf() will treat the value as a pointer, and it's not likely pointing to a valid memory address, moreover, it's unintialized which is another reason for undefined behavior.
You declared data as char *data and store int's in it, that is also Undefined Behavior.
You must check the return value of fscanf() beacuse if it fails, then the value will be uninitialized and there will be once again, Undefined Behavior and also you are going to read past the end of the file because you will never know if you reached it.
You are writing into the file and you open it for reading, this
fprintf(fp, "\n");
is wrong, you don't need it to read from the file.
Don't cast the result of malloc() though this is not causing problems in this case, it will improve the quality of your code.
Don't use sizeof(char) it makes your code harder to read and it's completely unnecessary since the standard mandates that sizeof(char) == 1.
You don't need the nested loop to read the data, because the shape of the data is irrelevant since fscanf() ignores all whitespace characters.
It is sufficient to read throug the file and use a counter to move through the array, at the end you can check how many values where read to verify the integrity of the data.
This is a fixed version of your code
#include <stdio.h> /* printf, scanf, NULL */
#include <stdlib.h> /* malloc, free, rand */
int main()
{
FILE *fp;
size_t index;
int *data;
data = malloc(1280 * 800);
if (data == NULL)
{
printf("NOt able to allocate memory properly\n");
return 1;
}
fp = fopen("\\home\\studinstru\\Desktop\\filedump.txt", "r");
if (fp == NULL)
{
printf("Error in creating dump file\n");
free(data);
return 2;
}
while (fscanf(fp, "%d", &data[index]) == 1)
{
fprintf(stdout, "%d ", data[index]);
index += 1;
if (index % 800 == 0)
printf("\n");
}
fclose(fp);
return 0;
}
Note: I recommend the use of compiler warnings, they would help prevent silly mistakes and some other mistakes like char *data and reading int's into it.
Also, from your file path "\\home\\studinstru\\Desktop\\filedump.txt" it seems you are on a non-windows system, and very likely the directory separator is / instead of \, so the correct path has to be
"/home/studinstru/Desktop/filedump.txt"
Replace
fscanf(fp,"%d/t",data[m*800 + n]);
with
fscanf(fp,"%d/t",&data[m*800 + n]);
fscanf() needs address of destination variable as argument and not the variable itself.
Also I am not getting why are doing this:
fprintf(fp,"\n");

EOF and PAGESIZE in mmap in C

I have this code to read a file using mmap and print it using printf. The file has 10 lines, and contains nos 0-9 on each line.
My questions are:
1. Why my code doesn't terminate on EOF ? i.e. why doesn't it stop at while (data[i]!=EOF) ?
2. When I run it with while (data[i]!=EOF), the program always terminates at data[10567] ? where as the page size is 4096 bytes. Does 10567 bytes have any significance ?
Edit: I am not looking for alternative like using fscanf, fgets.
Thanks!
Code:
10 int main(int argc, char *argv[])
11 {
12 FILE *ifp, *ofp;
13 int pagesize, fd, i=0;
14 char *data;
15 struct stat sbuf;
16
18 if ((ifp = fopen("/home/t/workspace/lin", "r"))==NULL)
19 {
20 fprintf(stderr, "Can't open input file\n");
21 exit(1);
22 }
28 fd = fileno(ifp);
29 if (stat("/home/t/workspace/lin", &sbuf) == -1)
30 {
31 perror("stat");
32 exit(1);
33 }
34 pagesize = getpagesize();
35 printf("page size: %d\n", pagesize);
36 printf("file size: %d\n", sbuf.st_size);
37 if((data = mmap((caddr_t)0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == (caddr_t)(-1))
38 {
39 perror("mmap");
40 exit(1);
41 }
43 //while (data[i]!=EOF)
44 while (i<=sbuf.st_size)
45 {
46 printf("data[%d]=%c\n", i, data[i]);
47 i++;
48 }
50 return 0;
51 }
Output:
page size: 4096
file size: 21
data[0]=0
data[1]=
data[2]=1
data[3]=
data[4]=2
data[5]=
data[6]=3
data[7]=
data[8]=4
data[9]=
. . . .
data[18]=9
data[19]=
data[20]=
data[21]= // truncated my output here,
// it goes till data[10567] if I use `while (data[i]!=EOF)`
EOF is not stored in files. So there's no point comparing a byte from the file with EOF. If you use mmap, as opposed to getchar or equivalent, then you need to stat the file to find out how big it is.
Note that getc, fgetc and getchar return an int. Quoting the manpage (or the Posix standard), these functions return the next byte "as an unsigned char cast to an int, or EOF on end of file or error." The value of EOF must be such that it cannot be confused with "an unsigned char cast to an int"; typically, it is -1. It is possible for a random (signed) char to be equal to -1, so your test data[i]!=EOF may eventually turn out to be true as you scan through uninitialized memory, if you don't segfault before you hit the random byte.
In Unix, text files are not necessarily terminated with NULs either. In short, you should only try to reference bytes you know to be inside the file, based on the file's size.
You output looks correct. The only bug I see is that:
while (i<=sbuf.st_size)
should have <.
There is no EOF, such as a Control-Z, stored in the actual data. All standard functions such as getc will return EOF when their internal counter equivalent to your i is past but their own sbuf.st_size. That is to say, EOF is a fictitious character generated by getc and/or the OS.
The confusion perhaps arises because, if I recall correctly, MS-DOS text files actually contain a ^Z, and if you inadvertently fopen one in binary mode, you can see this unwanted ^Z. Unix does not have this distinction.
With respect to your question:
Does 10567 bytes have any significance ?
I would say no. My guess is that data[10567] happens to be the first byte of memory equal to 0xFF, which is promoted to -l (assuming your char is signed), which matches EOF.

Resources