I'm having some problems with this little function that can read a file:
void ReadFile(char *name) {
FILE *fr;
int lenght, i;
fr = fopen(name, "r"); //Open the file reader
fseek(fr, 0, 2); //Set the pointer at the EOF
lenght = ftell(fr); //Read the ending position
printf("\nDEBUG lenght:%d\n", lenght);
fseek(fr, 0, 0); //Return at the beginning of the file
printf("File read:\n\n");
for (i = 1; i <= lenght; i++) {
printf("%c", getc(fr));
fseek(fr, i, 0);
}
fclose(fr);
}
This is the file that it reads:
qwerty
asdfgh
zxcvbn
But this is the output of the program:
DEBUG lenght:24
File read:
qwerty
asdfgh
zxcvbn
It is basically reading an extra "\n" when there is one before.
Any ideas of why the code doesn't work?
Thanks
If you open a file in text mode (as you do), then a call to fseek may only contain offset values that have been previously retrieved by an ftell function (cf, for example, cppreference/fseek):
If the stream is open in text mode, the only supported values for
offset are zero (which works with any origin) and a value returned by
an earlier call to ftell on a stream associated with the same file
(which only works with origin of SEEK_SET).
In your for-loop, however, you are passing the value of i, which is not retrieved by ftell.
Besides that, your fseek in the loop is superflous, as fgetc moves the read pointer forward anyway. So for (i = 1; i <= lenght; i++) { printf("%c", getc(fr)); } should do the job.
the following proposed code:
cleanly compiles
performs the desired functionality
properly checks for errors
and now, the proposed code:
#include <stdio.h> // EOF, fopen(), getc(), putc() fclose() puts() perror()
#include <stdlib.h> // exit(), EXIT_FAILURE
// prototype
void ReadFile(char *filename);
void ReadFile(char *filename)
{
FILE *fp = fopen( filename, "r" );
if( !fp )
{
perror( "fopen failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
puts("File read:\n");
int ch;
while( (ch = getc( fp )) != EOF )
{
putchar( ch );
}
fclose(fp);
}
Related
The output is correct when fgets() in included in the while loop, but taking it outside makes it an infinite loop. Can anyone explain why?
main()
{
FILE *fp=fopen("myfile.txt","r");
char s[100];
fgets(s,50,fp);
while(s!=NULL) //infinte loop
puts(s);
/* while((fgets(s,100,fp))!=NULL)
puts(s);
This runs fine */
fclose(fp);
}
s!=NULL compares the address of the array s against NULL, which will never match.
while(fgets(s,100,fp))!=NULL) compares the return of fgets() with NULL, which is NULL on EOF or error.
Search for:
man page fgets
Code 1
main()
{
FILE *fp = NULL;
FILE *fp=fopen("myfile.txt","r");
if(!fp)
{
/*error occured during fopen()! abort*/
printf("Error while openning the file!\n");
return 1;
}
char s[100];
fgets(s,50,fp); /*1*/
while(s != NULL) /*2*/
{
puts(s); /*3*/
}
fclose(fp);
}
Code 2
main()
{
FILE *fp=fopen("myfile.txt","r");
char s[100];
while((fgets(s,100,fp)) != NULL) /*1*/
{
puts(s); /*2*/
}
fclose(fp);
}
In Code 1, when you reach point /*1*/ your buffer s in not empty and contain some string (its not null). so you are entering the while loop with s!=null then in /*3*/ you are printing this in the stdoutput and return to point /*2*/ to ask if s != null and getting again the same answer that s is not null. hence you are stuck in this infinite loop forever.
In Code 2, In point /*1*/ you are redaing a line from the input stream and ask if its not null. fgets() Upon successful completion, fgets() shall return s. If the stream is at end-of-file, the end-of-file indicator for the stream shall be set and fgets() shall return a null pointer. If a read error occurs, the error indicator for the stream shall be set, fgets() shall return a null pointer, and shall set errno to indicate the error. In some point you will reach the eof and fgets() will return null and then you will exit the loop. for further reading please refer to man pages in the link
the following proposed code:
cleanly compiles
performs the desired functionality
properly checks for (and handles) errors from fopen() and from fgets()
Eliminates the use of 'magic' numbers
includes the needed header files
contains a valid signature for main()
passes the proper parameters to fgets()
includes a final call to puts() to assure the output stream buffer is flushed to the terminal
incorporates my comments to the OPs question
and now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
#define BUF_LEN 100
int main( void )
{
FILE *fp = fopen( "myfile.txt", "r" );
if( ! fp )
{
perror( "fopen to read file: myfile.txt failed" );
exit( EXIT_FAILURE );
}
char s[ BUF_LEN ];
while( fgets( s, sizeof(s), fp ) )
{
puts( s );
}
puts( "" );
fclose( fp );
}
I'm trying to read the hex values from an image file using C. In Linux, this code works fine, but with Windows it reads only the first 334 bytes and I don't understand why.
The code to read the file is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
void readHexFile(char* path) {
FILE *fp;
if ((fp = fopen (path, "r")) != NULL) {
struct stat st;
stat(path, &st);
int i;
int ch;
for (i = 0; i < st.st_size; i++) {
ch = fgetc(fp);
printf("%x ", ch);
}
fclose(fp);
}
else {
return NULL;
}
}
st.st_size comes from <sys/stat.h> package and contains the right value (the size, in bytes, of the image file)
This image show what my program outputs, and the actual binary content of the file it is reading:
As you see after the sequence of 17, 18, 19 there is also hex values but my program prints ffffffff repeatedly.
You opened the file in a text mode, and not as binary. Different platforms may behave differently.
In this case, Microsoft Windows decided that this plain text file ends at the first occurrence of Ctrl+Z (0x1A), and returns EOF for all fgetc afterwards.
Explicitly state that you want to open the file as binary:
fp = fopen ("yourfile", "rb");
and the problem goes away.
I think your loop should look like this:
int ch;
while (!feof(fp)) {
ch = fgetc(fp);
printf("%x ", ch);
}
It's completely unclear to me why you are using st.st_size here.
On Windows, the character 0x1A (Ctrl+Z) is the EOF character for text mode; see this question.
If you're reading from a binary file like a JPEG, you should do so with first opening the file as binary (fopen mode "rb"), then fread into a pre-allocated buffer, the size of which you would determine with ftell with the file pointer at the end of the file:
size_t i, len;
char *buffer = NULL;
fp = fopen(argv[1], "rb");
if(!fp)
// handle error
fseek(fp, 0, SEEK_END);
len = ftell(fp);
rewind(fp);
buffer = malloc(len + 1);
if(!buffer)
// handle error
fread(buffer, 1, len, fp);
for(i = 0; i < len; i++)
{
printf("%.2X ", buffer[i]);
}
free(buffer);
buffer = NULL;
i have a c project and i have serious problem , i want to open file and replace line number nb (nb is an int) with "*" . this is my code could some one help me please ? it show me the word i want to replace that's mean that the pointer is pointing on the wanted line but nothing happen .help me please
#include <stdio.h>
int main( void )
{
FILE * f;
char ch[1024];
int i, nb;
i = 0;
scanf( "%d", &nb ) ;
f = fopen( "dict.txt", "r+t" );
while( i < nb )
{
fscanf( f, "%s", ch ) ;
i++;
}
printf( "%s", ch );
fprintf( f, "%s", "****" );
fclose( f );
}
You've opened the file for reading and writing. According to the MSDN man page for fopen (I am assuming from the r+t mode on the file that you are using Visual Studio):
When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for "update"). However, when you switch from reading to writing, the input operation must encounter an EOF marker. If there is no EOF, you must use an intervening call to a file positioning function. The file positioning functions are fsetpos, fseek, and rewind.
Some other things to keep in mind:
When fscanf reads a string with %s, it reads only one word at a time, not a whole line. It is easier to read whole lines of input with fgets than with fscanf.
A file consists of a stream of bytes. If the line you want to replace is 47 characters long, then fprintf(f, "%s", "****") will only replace the first four bytes in the line.
That means that if you want to replace line #nb, you will need to read in the line, figure out how long it is, then seek back to the beginning of the line and print out the correct number of asterisks.
Try something like this instead:
#include <stdio.h>
#include <string.h>
int main()
{
FILE * f;
char ch[1024];
int i,nb ;
fpos_t beginning_of_line;
i=0;
scanf("%d",&nb) ;
f = fopen("dict.txt", "r+t");
while (i<nb)
{
fgetpos(f, &beginning_of_line);
fgets(ch, 1024, f);
i++;
}
fseek(f, beginning_of_line, SEEK_SET); // return to beginning of line
for (i = 0; ch[i] != '\n'; ++i) {
fputc('*', f);
}
fclose(f);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( int argc, char *argv[] )
{
if ( argc != 4 ) /* argc should be 4 for correct execution */
{
/* Print argv[0] assuming it is the program name */
printf( "usage: %s filename\n", argv[0] );
}
else
{
// We assume argv[1] is a filename to open
char* wordReplace = argv[1];
char* replaceWord = argv[2];
FILE *file = fopen( argv[3], "r+" );
/* fopen returns 0, the NULL pointer, on failure */
if ( file == 0 )
{
printf( "Could not open file\n" );
}
else
{
char string[100];
int len = 0;int count = 0;int i = 0;int k = 0;
while ( (fscanf( file, "%s", string ) ) != EOF )
{
len = strlen(string);
count++;
char charray[len+1];
if(count == 1)
{
for (i = 0; i < len; i++)
{
charray[i] = replaceWord[i];
printf("%c\n", charray[i]);
}
}
//printf("%c\n", charray[0]);
printf( "%s\n", string );
if(strcmp(string, wordReplace) == 0)
{
for(k = 0; k < strlen(replaceWord); k++)
{
fseek (file, (-(long)len), SEEK_CUR);
fputc(charray[k],file);
//replaceWord++;
}
//strcpy(string, replaceWord);
//fprintf(file,"%s",replaceWord);
//fputs(string, file);
//printf("\n%d\n", len);
}
}
fclose( file );
}
}
printf("\n");
return 0;
}
This code currently works in replacing the First word properly, but if there are multiple words that i want overwritten with the replace word or the word appears somewhere else in the text it will not properly change it, and it will change it to ram trash etc. I was curious if anyone could lead me to a reason why thank you.
Assuming the words are the same length (if not you have quite a few more issues):
Let's say you have a 4 character word:
fseek (file, (-(long)len), SEEK_CUR); will go back to position 0 (4-4), fputc(charray[k],file); will update to position 1, then you back 4 more which is an error but since you're not checking the return value from fseek you will not know this. At this point the algorithm is not working any more since your assumed file positions are all wrong
EDIT:
if(strcmp(string, wordReplace) == 0)
{
fseek (file, (-(long)len), SEEK_CUR);
for(k = 0; k < strlen(replaceWord); k++)
{
fputc(charray[k],file);
}
}
fflush(file); //you need to flush the file since you are switching from write to read
EDIT 2: reason for flush: from 4.5.9.2 ANSI C, similar paragraph in C99 7.19.5.3):
When a file is opened with update mode ('+' as the second or third character in the mode argument), both input and output may be performed on the associated stream. However, output may not be directly followed by input without an intervening call to the fflush function or to a file positioning function ( fseek , fsetpos , or rewind ), and input may not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.
Between the read and write you have the fseek already so that is not a problem
I am just not sure why my replaceWord isn't going in to the file at all i have used all the commented out and so on and so forth. I am just trying to replace with with the text received from the command line argument. I know i might be far off I was just looking for a relatively easy way to do it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( int argc, char *argv[] )
{
if ( argc != 4 ) /* argc should be 2 for correct execution */
{
/* We print argv[0] assuming it is the program name */
printf( "usage: %s filename\n", argv[0] );
}
else
{
// We assume argv[1] is a filename to open
char* wordReplace = argv[1];
char* replaceWord = argv[2];
FILE *file = fopen( argv[3], "r" );
/* fopen returns 0, the NULL pointer, on failure */
if ( file == 0 )
{
printf( "Could not open file\n" );
}
else
{
char string[100];
int len = 0;
/* read one character at a time from file, stopping at EOF, which
indicates the end of the file. Note that the idiom of "assign
to a variable, check the value" used below works because
the assignment statement evaluates to the value assigned. */
while ( (fscanf( file, "%s", string ) ) != EOF )
{
len = strlen(string);
printf( "%s\n", string );
if(strcmp(string, wordReplace) == 0){
//fseek (file, (-strlen(string) + 1), 1);
//fputc(*replaceWord,file);
//replaceWord++;
//strcpy(string, replaceWord);
fprintf(file,"%s",replaceWord);
fputs(replaceWord, file);
printf("\n%d\n", len);
}
}
fclose( file );
}
}
printf("\n");
return 0;
}
You've opened the file in r ie read mode and trying to write to it.
Also after correcting that, note that, the replaced word and word to be replaced have to be of the same size, if you want to replace the file in place. Else you will end up overwriting other data. And you need to use functions like fseek to reposition the internal file pointer as fp would have moved ahead after fscanf