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;
}
Related
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 have a c code, simply reads a line from a txt file. The file has only one line which is as below:
The code snippet to read this line is:
int** readFile(char* filename){
int col=0, row =0;
int i=0;
int* numList[2048];
for(int i = 0; i<2048; i++)
numList[i] = (int*) malloc(6*sizeof(int));
if(NULL == numList){
printf("Memory error!");
}
char * token = NULL;
char currentLine[25] = {'\0'};
FILE* file = fopen(filename, "r");
if(NULL != file){
printf("File is opened successfully\n");
if( NULL != fgets (currentLine, 60, file) )
{
int i = 0;
while (NULL != currentLine[i]){
printf("%d ", currentLine[i]);
i++;
}
}
}
else
{
printf("File I/O Error");
return NULL;
}
fclose(file);
return numList;
}
When this code runs, I get the following output:
I observed something suspicious, which is, as you can see in the first screenshot (Content of txt file), Notepad++ shows CR LF at the end of the line. But in the output, I see 10 as the last character which is LF.
Probably I am missing a very primitive point but, I couldn't understand why CR character is not there.
Needless to say, platform is windows and this is a console program.
Thanks&Regards.
You're opening the file in text mode. This mode ensures you can handle text files the same on any platform.
C specifies '\n' as the end of line. In Windows, the end of line is the sequence "\r\n". C (in this case, the standard library implementing stdio) will automatically translate this for you. Reading from a file on Windows in text mode will give you just \n for \r\n.
If you want to see exactly the byte contents of the file, you have to open it in binary mode instead:
FILE* file = fopen(filename, "rb");
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.
I am taking a course on C and have been faced with the following task: 1. Load XCode and start a new C project. If you wish, remove
any extraneous code from the project so that you are left
with only what’s necessary to run the main function in your
project.
2. Prompt the user to enter two values-- the first a char
value of ‘D’ or ‘C’. The second value should be a floating
point value representing an amount of money.
3. As each value is entered record it to a text file that
saves it in the following format:
D, 250\n
C, 500\n
4. Test your program and examine the text file that it creates
to insure that it is in the required format.
5. Write a second program that assumes a starting balance of
$1,000.00 and outputs a completed ledger and final balance
for the account, adding or subtracting each entry from the
text file you previously created. Entries marked as a ‘C’
should be added to the account and entries marked as a ‘D’
should be debited (subtracted).
I have already created the file and am now onto step 5, I believe i know how to obtain the first character from the file to check if it is a 'c' or 'd', but after that i am not sure how to obtain the numerical value from the same line. How do I do this? This is my code so far(I am unsure what to put in the if/else if statements):
FILE *pFile = fopen("Users/Justin/Desktop/Ledger.txt", "r");
float startingBalance = 1000.00;
char action;
if(pFile != NULL)
{
while(!(feof(pFile)))
{
fgets(action, 1, pFile);
if(action == 'D' || action == 'd')
{
}
else if(action == 'C' || action == 'c')
{
}
else
printf("IO Error: Problem with file");
}
}
return 0;
}
Your file is organised in lines, so it's best to read it line-wise. The function for that is fgets, which will read a whole line of a certain maximum length into a char buffer. It keeps the terminating newline (unless the line is truncated because of the max length, but let's not deal with that right now). fgets returns the line buffer or NULL if the end of the file is reached.
Once you have a line, you must examine that line. Your lines all have the same syntax, namely
<action>, <amount>
so you could use sscanf, which isn't nice but quick and dirty. (scanfs error handling, for example, is very basic, so a good strategy is to ignore badly formatted lines altogether.)
The skeleton of your function might look like this:
int ledger(const char *fn)
{
FILE *f;
char line[80]; /* char buffer for line */
int lineno = 0; /* for error reporting */
f = fopen(fn, "r");
if (f == NULL) return -1; /* error */
while (fgets(line, sizeof(line), f)) {
char action;
double amount;
int n;
lineno++;
n = sscanf(line, " %c, %lf", &action, &amount);
if (n < 2) {
printf("Skipping badly formatted line %d\n", lineno);
continue;
}
/* Do stuff, e.g. just print */
printf("%c, %16.2f\n", action, amount);
}
fclose(f);
return 0; /* success */
}
The code is supposed to read a user-inputted text file name, copy every character into a multidimensional array, then display it with standard output. It compiles, but produces unintelligible text. Am I missing something?
for (i = 0; i < BIGGEST; i++) {
for (j = 0; j < BIGGESTL; j++) {
if (fgetc(array, fp) ) != EOF)
array[i][j] = c;
else array[i][j] = '\0'
}
fclose(fp);
return 0;
}
You stop filling the array when you encounter EOF, but you print the full array out no matter what.
If the data read from the file is smaller than the input array, you will read that data in and then print that data out, plus whatever random characters were in the memory locations that you do not overwrite with data from the file.
Since the requirement seems to be to print text data, you could insert a special marker in the array (e.g. '\0') to indicate the position where you encountered EOF, and stop displaying data when you reach that marker.
You had better read each line from file
For example:
int i = 0;
while(fgets(text[i],1000,fp))
{
i++;
}
Though the question is edited and only part of the code is left in question. I am posting more than what is required for the question at the moment.
Reason being, there can be numberous improvements to originally posted full code.
In main() function:
You need to check for the argc value to be equal to 2 for your purpose and only then read in value of argv[1] . Else if program executed without the command-line-argument which is file_name in this case, invalid memory read occurs, resulting in segmentation fault if you read in argv[1].
In read_file_and_show_the contents() function:
Stop reading file if end of file is reached or maximum characters is read and store in the character array.
Below Program will help you visualize:
#include <stdio.h>
/*Max number of characters to be read/write from file*/
#define MAX_CHAR_FOR_FILE_OPERATION 1000000
int read_and_show_the_file(char *filename)
{
FILE *fp;
char text[MAX_CHAR_FOR_FILE_OPERATION];
int i;
fp = fopen(filename, "r");
if(fp == NULL)
{
printf("File Pointer is invalid\n");
return -1;
}
//Ensure array write starts from beginning
i = 0;
//Read over file contents until either EOF is reached or maximum characters is read and store in character array
while( (fgets(&text[i++],sizeof(char)+1,fp) != NULL) && (i<MAX_CHAR_FOR_FILE_OPERATION) ) ;
//Ensure array read starts from beginning
i = 0;
while((text[i] != '\0') && (i<MAX_CHAR_FOR_FILE_OPERATION) )
{
printf("%c",text[i++]);
}
fclose(fp);
return 0;
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("Execute the program along with file name to be read and printed. \n\
\rFormat : \"%s <file-name>\"\n",argv[0]);
return -1;
}
char *filename = argv[1];
if( (read_and_show_the_file(filename)) == 0)
{
printf("File Read and Print to stdout is successful\n");
}
return 0;
}