I am writing some code that inputs grid coordinates of "islands" (connected points on a grid) and finds the center of mass for each island. The code is successful for grids with a few large islands, however, it fails for grids with many small islands.
I've narrowed down the issue to rewind() failing on the 252nd loop-through. I have no idea why it fails as I've verified that island # 252 exists by printing the coordinates prior, and if I skip 252, the code fails on island 253, so I believe it is just rewind failing after 252 uses.
The code is quite large, so I'll try to just post the relevant parts:
FILE *f;
if((f = fopen(argv[1], "r")) == NULL)
{
printf("Could not open file to read.\n");
return 0;
}
while(!feof(f))
{
fscanf(f, "%d %d %d\n", ¤t_x, ¤t_y, &island_number);
if(island_number > number_of_islands)
{
number_of_islands = island_number;
}
}
fclose(f);
This the first instance when f is used, but it's used again later, and again in the following for loop which is where the problem emerges:
for( int i = 0; i < number_of_islands; i++)
{
printf("new loop: %d (number of islands: %d) \n", loop, number_of_islands);
if(loop == 252)
{
printf("putting in x, y at 252...\n");
}
This is where the code fails...
//putting numbers in x and y
rewind(f = fopen(argv[1], "r"));
Here's a bit of the following part (probably not important):
if(loop == 252)
{
printf("rewound at 252...\n");
exit(0);
}
while(!feof(f))
{
fscanf(f, "%d %d %d\n", ¤t_x, ¤t_y, &island_number);
if(island_number == current_island_number)
{
x_array[current_x] += 1;
y_array[current_y] += 1;
}
}
if(loop == 252)
{
printf("finished putting in x, y at 252...\n");
exit(0);
}
A sample of what the output looks like is this:
Everything looks good, except for the sudden segfault.
So my question is, why is rewind() suddenly segfaulting on the 252nd attempt?
this: rewind(f = fopen(argv[1], "r"));
does not rewind f.
instead it assigns a new value for f, opening the same file and rewinding it (although it has just been opened).
on some systems there is a limit to the open file descriptors you can have. why 252? i guess your limit is 256 and the kernel probably uses the remaining 4.
to fix the problem you can either close the file first, or:
rewind(f);
this should work with no reassignment of f.
Related
The C program I am trying to write is meant to take a file of integer values and sum the first number with the second, then the first with the third, the first with the forth, and so on. Then sum the second with the third, the second with the forth, and so on. It is also meant to print a message whenever a predetermined value is met while adding all the numbers (in my case, it's 10), and print out the time it took for this program to execute.
However, when the program starts going through the list of integers in the file I am taking values from (over 10,000 integers are in this file), it seems that it gets to the 124th loop and then gives me a Segmentation Fault (Core Dumped) error. When I reduce the number of integers to be added to under 124, the program works fine.
Why am I getting this Segmentation Fault error? Is it in the way that I set up my While loops? Is there any way I can remedy this?
#include<stdio.h>
#include <time.h>
int main(){
FILE *fptr1,*fptr2,*temp;
fptr1 = fopen("input.txt", "r") ;
int num1,num2;
int sum=0;
int c=0;
if (fptr1 == NULL) {
printf("File not open\n");
return 0;;
}
int count=0;
clock_t t;
t = clock();
// the problem seems to be in this while loop//
while(fscanf(fptr1, "%d", &num1) !=EOF){
count++;
fptr2 = fopen("input.txt", "r") ;
int count1=0;
while(fscanf(fptr2, "%d", &num2) !=EOF){
count1++;
if(count1>count){
sum=num1+num2;
if(sum==10){c++;}
}
}
}
printf("sum of 10 was found in %d iterations of loop",c);
t = clock() - t;
double time_taken = ((double)t)/CLOCKS_PER_SEC; // in seconds
printf("Time taken :%lf", time_taken);
fclose(fptr1);
fclose(fptr2);
return 0;
}
When the file has over 124 integers, it gives me this:
the output when over 124 integers
and when he file has less than 124 integers, it gives me this:
the output when under 124 integers
The problem seems to be opening way too many file handles, but the fix should be simple:
while(fscanf(fptr1, "%d", &num1) !=EOF){
count++;
// This fopen() call might fail, you should check the result
fptr2 = fopen("input.txt", "r");
int count1 = 0;
while(fscanf(fptr2, "%d", &num2) != EOF) {
// ...
}
// If you open a file, you must close it before re-opening
fclose(fptr2);
}
This is quite wasteful, though, there's no reason to open over and over, instead
just rewind the file and use it again:
fptr2 = fopen("input.txt", "r");
while(fscanf(fptr1, "%d", &num1) !=EOF) {
// Move back to the beginning of the file before reading
rewind(fptr2);
count++;
int count1 = 0;
while(fscanf(fptr2, "%d", &num2) != EOF) {
// ...
}
}
fclose(fptr2);
Another thing to note here is your variable names are extremely opaque. fptr2 doesn't communicate anything about what this is supposed to be used for, or what that file might contain. If it correlates with an input source, consider input or finput or even fin. Likewise, count1 and count and an even more mysterious c are confusing. Counting what? For what reason?
I'm trying to read two records form a file, where one is hexadecimal formated number. Well I'm newcomer to C, before when I been reading hexadecimal, generated by ftok(), I just used printf("%x", key) and it worked fine. Now when I try to read it from the file, it does not work that way.
So my code looks like this:
int countRecords(FILE *f_p) {
int tmp_key = 0;
int tmp_msgqid = 0;
int n = 0;
while (!feof(f_p)) {
if (fscanf(f_p, "%x %i", &tmp_key, &tmp_msgqid) != 2)
break;
n = n + 1;
}
return n;
}
Later on i read this value in the code like:
printf("Records: %i \n", countRecords(f_msgList));
And this compiles with no warnings. Anyway when I run the program the value of countRecords(f_msgList) is 0, when the file have a bunch of data in it:
5a0203ff 360448
850203ff 393217
110203ff 425986
EDIT:
Here is the code where the file is opened or created:
FILE *f_msgList;
f_msgList = fopen("../message_queues.list", "a");
// if file does not exist then create one and check for errors
if (f_msgList == NULL) {
FILE *f_tmp;
f_tmp = fopen("../message_queues.list", "w");
if (f_msgList == NULL) {
fprintf(stderr, "Error occurred while creating the file! \n");
exit(1);
} else
f_msgList = f_tmp;
}
Problems
You opened the file in "append" mode. which does not let you read through the file.
If you want to write and then read the file, file pointer must be reset to the starting of the file.
feof(f_p) is worst way of checking whether file pointer is at end of the file.
Solution
Open File in "read" mode by 'r' or in append+read mode 'a+'.
if you are writing in to the file. reset it using rewind(f_p); after writing.
check out this way to read through the file :
int ret, ans, key;
while ((ret = fscanf(fp, "%x %i", &key, &ans))) {
if (ret == EOF)
break;
else
printf("%x %i \n",key, ans);
}
here integer ret is :
EOF, if the pointer is reached end of file.
0, if no input matched with the variable
(greater than 0), that is, number of matched variables with the file input
I've written a code that needs to read in a series of values from a user specified data file (This could be up to 10,000 rows of data) which is done in the first for loop. In each row of values one of the variables is converted to a string which defines another set of input files(each containing ~20,000 rows of data) to load which are needed in the second for loop for calculations. This works well for the first few hundred iterations... it reads in everything correctly, and the resulting calculations (Calculations are omitted in the code below because the code produces the same problme with or without them) are as expected.
The problem is that when the first for loop reaches around 600 iterations it stops and produces the error: segmentation fault(core dumped)
I'm pretty sure this is a memory problem of some sort because if I've tested the code by omitting 4 of the input files in the second loop and it's capable of reaching a higher number of iterations....
This is the code:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int main()
{
int num, i, j;
double X, Y;//
float Z;
char the_data[25], Z_name[10], input_1[50], input_2[50], input_3[50], input_4[50], input_5[50];
double a, b, c, d, e;
printf("Enter the name of the data file you are using:\n");
scanf("%24s", &the_data);
FILE *DATA = fopen(the_data,"r");
for (j=1; j<800; j++)
{
//***************Read data from a file, the variable Z is a floating point number which, when rounded to the nearest decimal place,
//********************determines which directory to load model data from for each value of X and Y
fscanf(DATA, "%lf %lf %f\n", &X, &Y, &Z);
//round Z to the nearest 1 decimal place
Z = Z * 10;
Z = roundf(Z);
Z = Z / 10;
//assign the full directory name to Z_name
sprintf(Z_name, "%.01fdirectory", Z);
//assign Z_name to input name string for path to the appropriate data file locations
sprintf(input_1, "./%s/a.txt", Z_name);
sprintf(input_2, "./%s/b.txt", Z_name);
sprintf(input_3, "./%s/c.txt", Z_name);
sprintf(input_4, "./%s/d.txt", Z_name);
sprintf(input_5, "./%s/e.txt", Z_name);
//Open the files
FILE *input1 = fopen(input_1, "r");
FILE *input2 = fopen(input_2, "r");
FILE *input3 = fopen(input_3, "r");
FILE *input4 = fopen(input_4, "r");
FILE *input5 = fopen(input_5, "r");
for (i=1; i < 10000; i++)
{
//For a given Z value, read in the corresponding values. Usually these input files have ~20000 values in each so the loop would be set to run until the end of the file
fscanf(input1, "%lf", &a);
fscanf(input2, "%lf", &b);
fscanf(input3, "%lf", &c);
fscanf(input4, "%lf", &d);
fscanf(input5, "%lf", &e);
}
//Test to see how far it gets in loop before giving up due to segmentation fault
printf("The iteration number is: %d\n", j);
}
printf("This will print if the program reaches the end of the first loop\n");
}
I'd appreciate any tips or pointers in dealing with this problem. Thanks!
You need to check the return value from fopen(). Since you're never closing the input files, you're probably hitting the limit on open files. Then fopen() returns NULL, and when you try to use that with fscanf() you get a segfault.
//Open the files
FILE *input1 = fopen(input_1, "r");
if (!input1) {
printf("open input_1 failed\n");
exit(1);
}
FILE *input2 = fopen(input_2, "r");
if (!input2) {
printf("open input_2 failed\n");
exit(1);
}
FILE *input3 = fopen(input_3, "r");
if (!input3) {
printf("open input_3 failed\n");
exit(1);
}
FILE *input4 = fopen(input_4, "r");
if (!input4) {
printf("open input_4 failed\n");
exit(1);
}
FILE *input5 = fopen(input_5, "r");
if (!input5) {
printf("open input_5 failed\n");
exit(1);
}
for (i=1; i < 10000; i++)
{
//For a given Z value, read in the corresponding values. Usually these input files have ~20000 values in each so the loop would be set to run until the end of the file
fscanf(input1, "%lf", &a);
fscanf(input2, "%lf", &b);
fscanf(input3, "%lf", &c);
fscanf(input4, "%lf", &d);
fscanf(input5, "%lf", &e);
}
//Test to see how far it gets in loop before giving up due to segmentation fault
printf("The iteration number is: %d\n", j);
fclose(input1);
fclose(input2);
fclose(input3);
fclose(input4);
fclose(input5);
I have a litte problem with the following, simple read function:
printf("File to be opened: ");
scanf("%s", input);
if ((fp = fopen(input, "r")) == NULL) {
printf("ERROR: can't open %s!", input);
}
else {
if (read_pgm_hdr(fp, &w, &h) != -1) {
printf("*** SUCCESS --%s-- opened ***\n", input);
printf("*** PGM file recognized, reading data into image struct ***\n");
for (i = 0; i < w * h; i++) {
img_data[i] = getc(fp);
}
}
In the loop, the img_data array is filled with 8bit-grayscale values of an image in .pgm. With w = 300 and h = 300, the array has the right size.
In most cases, it works fine. But sometimes in the middle of an image, getc() starts filling my array with 255.
I found out that this happens, when the grayscale value is 19. It doesn't matter, where this value occurs. If the 3rd pixel is 19, the 3rd value and every following are 255. If the 127th pixel is 19, the 127th value and every following are 255.
I really have no idea, why this is happening. I hope anyone can help.
UPDATE: Ok, thank you. The combination of opening in binary mode and using fread instead of getc solved the Problem :)
Saku
I could not reproduce under Unix, but could easily reproduce under Windows. The problem is the character Ctrl-Z (code 0x1A) which under windows represents an End Of File for text files.
The problem is that getc is normally used for text files and as some old editors used to explicitely write a Ctrl-Z to delimit the end of a text file, getc still consideres it as a true EOF - BTW this is coherent with Klas Lindbäck's answer. More as you open the file in "r" mode, it is implicetly opened as a text file.
The fix is trivial : open the file as a binary file.
if ((fp = fopen(input, "rb")) == NULL) ...
(note the b) should be enough.
For the character 19 cited in question, I did the test with the table of ASCII characters and the last correct was ... Ctrl-Y = 0x19 ... but the culprit is indeed Ctrl-Z = 0x1A.
Anyway, you should replace the loop reading one character at a time :
for (i = 0; i < w * h; i++) {
img_data[i] = getc(fp);
}
with a simple fread :
n = fread(img_data, w, h, fp); // or fread(img_data, 1, w * h, fp);
and control that n is h in first way or n * h in second.
255 would be the result of getc returning EOF.
To test for EOF you need to store the value in an int:
for (i = 0; i < w * h; i++) {
int tmp = getc(fp);
if (tmp == EOF) {
/* Handle EOF */
printf("EOF after readin %d bytes out of %d!!!\n", i, w*h);
break;
}
img_data[i] = tmp;
}
The thing is that im trying to read some integers to know the levels of the game I have already passed through, then I want to put the integer of the current level to one if t is not already. It creates the file but doesn't write anything. Anyone know why? Now, it does it the first time when creating it with printf but when reading it gives status access violation.
void SaveGame(void)
{
FILE *pFile = fopen("SavedData.txt","rb");
int MyArray[8] = {0};
if(pFile)
{
fscanf(pFile, "%d %d %d %d %d %d %d %d" , MyArray[0], MyArray[1], MyArray[2], MyArray[3], MyArray[4], MyArray[5], MyArray[6], MyArray[7]);
fclose(pFile);
}
if(MyArray[Current] == 0)
MyArray[Current] = 1;
pFile = fopen("SavedData.txt", "wb");
if(pFile)
{
fprintf(pFile, "%d %d %d %d %d %d %d %d" , MyArray[0], MyArray[1], MyArray[2], MyArray[3], MyArray[4], MyArray[5], MyArray[6], MyArray[7]);
fclose(pFile);
}
}
You can do what you want something like this (untested) :
#define SAVE_FILE "SavedData.txt"
#define NUMS_SIZE 8
void SaveGame() {
FILE *f;
f = fopen(SAVE_FILE, "r");
if (!f) {
fprintf(stderr, "Error: Can't open save file for reading.\n");
exit(-1);
}
int nums[NUMS_SIZE] = {0};
int n, i = 0;
while (fscanf(f, "%d", &n) == 1) {
if (i >= NUMS_SIZE) break;
nums[i++] = n;
}
fclose(f);
f = fopen(SAVE_FILE, "w");
if (!f) {
fprintf(stderr, "Error: Can't open save file for writing.\n");
exit(-1);
}
int j = 0;
if (i > 0) fprintf("%d", nums[0]);
for (j = 1; j < i; ++j)
fprintf(" %d", nums[j]);
fclose(f);
}
That's not how you read a file.
For starters if it is a text file, open with mode "r", not "rb".
When you do a read operation you should check to see whether the read operation suceeded or failed. You don't do feof instead. There is a lot of code out there that does feof and most of it is wrong. Be wary when copying off internet code samples.
Also, it's a great idea to read the documentation for any standard function you use. You may learn things about the function that you didn't know. For example, fscanf returns how many items were successfully read.
So in your reading loop, either check that fscanf returns 8 (or loop 8 times as ooga suggested, checking for 1 each time). Don't check feof during the loop.
Once the read fails, THEN you have the option to do feof to find out why the read failed, if you care to know. It could have fail because you hit the end of file (feof), or because of a device error (ferror), or because the file had words in it instead of numbers.
When you do the writing part, make sure you only write numbers which were successfully read.