I am tried to use read/write/append modes with both fprintf and fscanf, and they'r not working. My The location of the folder where I've saved my file is ''C:\coding projects\test\Assignment Template'' and the name of the file is ''Assignment Template.txt''.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[500];
FILE *ptr;
ptr=fopen("C:\coding projects\test\Assignment Template\Assignment template.txt","r");
fscanf(ptr,"%s",str);
return 0;
}
ps, I also tried to use the location of folder only without file name, also tried to use the name of the file only without folder location, but none of it seems to be working.
As pointed out by others, the several "single '\'" in the pathname to your file are wrong. You need to replace each "\" with "\\" OR with "/". Both these solutions would work.
The second idea is that "not working" is not a helpful diagnostic. To follow that with "nothing happened" does not supply any extra information.
Here is an example showing how to write this functionality so that you can at least understand where a problem might be occurring.
int main()
{
// Separate the filepath so it can be used in error message if necessary.
char *fname = "C:/coding projects/test/Assignment Template/Assignment template.txt";
char str[ 500 + 1 ]; // One extra for trailing '\0'
// temporary debugging report to confirm pathname is as expected.
printf( "Attempt open of '%s'\n", fname );
FILE *fp = fopen( fname, "r" );
// ALWAYS test return values for possible errors
if( fp == NULL ) {
// Able to report what went wrong
fprintf( stderr, "Failed to open %s\n", fname );
exit( EXIT_FAILURE );
}
// fscanf returns how many variables were 'satisfied'
// use that information
// Also, set a limit that won't overflow the buffer being filled
int num = fscanf( fp, "%500s", str );
// 'temporary' diagnostic "debugging" report to the console
printf( "Loaded %d items\n", num );
// clean up
fclose( fp );
return 0;
}
This is not "debugging with print statements"... To move forward developing code, one adds-or-modifies only a VERY few lines of code, then TESTS the consequences of those changes before adding/modifying a few more lines. "Incremental development". 'Testing' involves having clear expectations of what should happen and "seeing" if those expectations have been met. Had you printed the string that is the pathname of the file you want to open, you would have seen a problem before writing one more line of code. "Slowly and methodically, ALWAYS testing/checking."
Related
My code reads line by line from a text file and stores the lines in a massive array of char pointers. When I use an ordinary text file, this works with no issues. However, when I try to read from the 'dictionary.txt' file I'm supposed to be using, my program detects EOF after reading the first of MANY lines in the file.
int i = 0;
while( 1 ) {
size_t size = 50;
fseek( dicFile, 0L, getline( &dictionary[i++], &size, dicFile) );
printf( "%d:\t%s", i, dictionary[i - 1] );
if( feof( dicFile ) ) {
fclose( dicFile );
break;
}
}
puts("finished loading dictionary");
Here is the start of the dictionary file I'm attempting to load:
A
A's
AA's
AB's
ABM's
AC's
ACTH's
AI's
AIDS's
AM's
AOL
AOL's
ASCII's
ASL's
ATM's
ATP's
AWOL's
AZ's
The output is get from this portion of the program is:
1: A
2: finished loading dictionary
Thanks for any help.
Your third argument to fseek() is nuts. I've seen at least one implementation that treated every out of range third argument as SEEK_END. Oops.
You should just call getline() in the loop instead. In fact, just check the return value of getline() for -1 and get rid of that feof().
The following is my code for a method that copies a file from a path to a file to a directory provided as the destination. The copy works perfectly fine, however my chmod call assigns the wrong permissions to the copied file in the destination. If the permission in the source is 644, the copied file has a permission of 170 or 120.
I have been attempting to debug this for hours and it's driving me slightly crazy so any help is greatly appreciated.
void copy_file(char* src, char* dest) {
char a;
//extract file name through a duplicate ptr
char* fname = strdup(src);
char* dname = basename(fname);
//open read and write streams
FILE* read;
FILE* write;
read = fopen(src, "r");
chdir(dest);
write = fopen(dname, "w");
//error checking
if (read == NULL) //|| (write == NULL))
{
perror("Read Error: ");
exit(0);
}
else if (write == NULL)
{
perror("Write Error: ");
exit(0);
}
//write from src to dest char by char
while (1){
a = fgetc(read);
if (a == EOF)
{
break;
}
fputc(a, write);
}
//close files
fclose(read);
fclose(write);
// this is where I attempt to assign source file permissions
//and it goes horribly wrong
struct stat src_st;
if(stat(src, &src_st)){
perror("stat: ");
}
chmod(dname, src_st.st_mode);
printf("%o\n", src_st.st_mode & 0777);
}
You fopen(src, "r"), then you chdir(dest). This means that when you later call stat(src, &src_st), there is no reason to think that stat will access the same file as fopen did, or indeed that stat will access any file at all.
If stat fails, you proceed to call chmod anyway, so you pass whatever random junk was in src_st.st_mode to chmod.
You should use fstat(fileno(read), &src_st) before calling fclose(src), instead of calling stat(src, &src_st).
The basic problem is you have to check your system calls like fopen, chdir, and stat immediately.
For example, first thing I tried was copy_file( "test.data", "test2.data" ) not realizing it expected a destination directory.
char* fname = strdup(src);
char* dname = basename(fname);
dname is now test.data, same as the source.
read = fopen(src, "r"); // succeeds
chdir(dest); // fails
write = fopen(dname, "w"); // blows away test.data, the source
You do eventually check read and write, but after the damage has been done.
Blowing away your source file is really bad. It's important that your code deals with failed system calls. If you don't, it will sail along causing confusion and destruction.
Most system calls in C return 0 for success. This is an anti-pattern where the return value is an error flag, so false is failure, and anything else indicates what kind of error (though stat doesn't use that, it uses errno).
When it fails, stat returns -1 which is true. So this is the wrong way around.
struct stat src_st;
if(stat(src, &src_st)){
perror("stat: ");
}
Instead, you have to check for non-zero.
struct stat src_st;
if(stat(src, &src_st) != 0 ){
// Note that I don't use perror, it doesn't provide enough information.
fprintf(stderr, "Could not stat %s: %s\n", src, strerror(errno));
exit(1);
}
As you can guess this gets tedious in the extreme, and you're going to forget, or do it slightly different each time. You'll want to write wrappers around those functions to do the error handling for you.
FILE *fopen_checked( const char *file, const char *mode ) {
FILE *fp = fopen(file, mode);
if( file == NULL ) {
fprintf(stderr, "Could not open '%s' for '%s': %s", file, mode, strerror(errno));
exit(1);
}
return fp;
}
It's not the best error handling, but it will at least ensure your code appropriately halts and catches fire.
A note about chdir: if you can avoid it don't use it. chdir affects the global state of the program, the current working directory, and globals add complexity to everything. It's very, very easy for a function to change directory and not change back, as yours does. Now your process is in a weird state.
For example, if one did copy_file( "somefile", "foo" ) this leaves the program in foo/. If they then did copy_file( "otherfile", "foo" ) they'd be trying to copy foo/otherfile to foo/foo/otherfile.
And, as #robmayoff pointed out, your stat fails because the process is now in a different directory. So even the function doing the chdir is confused by it.
Ensuring that your functions always chdir back to the original directory in a language like C is very difficult and greatly complicates error handling. Instead, stay in your original directory and use functions like basename to join paths together.
Finally, avoid mixing your file operations. Use filenames or use file descriptors, but try not to use both. That means if you're using fopen, use fstat and fchmod. You might have to use fileno to get a file descriptor out of the FILE pointer.
This avoids having to carry around and keep in sync two pieces of data, the file descriptor and the filename. It also avoids issues with chdir or the file being renamed or even deleted, the file descriptor will still work so long as it remains open.
This is also a problem:
char a;
...
while (1){
a = fgetc(read);
if (a == EOF)
{
break;
}
fputc(a, write);
}
fgetc() returns int, not char. Per the C Standard, 7.21.7.1 The fgetc function:
7.21.7.1 The fgetc function
Synopsis
#include <stdio.h>
int fgetc(FILE *stream);
Assuming sizeof( int ) > sizeof( char ), char values are signed, 2s-complement integers, and EOF is an int defined to be -1 (all very common values), reading a file with char a = fgetc( stream ); will fail upon reading a valid 0xFF character value. And if your implementation's default char value is unsigned char, char a = fgetc( stream ); will never produce a value that matches EOF.
I am trying to make a report in a .txt file, but when my fprintf meets a \n it crashes. This is my code concerning the opening of the file and crashing:
FILE *f;
f = fopen("estructuras.txt", "w");
fprintf(f, "");
printf("3"); //This is the last thing I see.
fprintf(f, "TEXT TO INPUT\n")
fclose(f);
The problem is you didn't check whether the file opened. If it failed, it will return NULL and that will do bad things to fprintf.
Your first fprintf(f, ""); is a no-op. Printing an empty string does nothing, so that "works" (though I doubt that's guaranteed). printf("3"); does to stdout and is unaffected by the failed fopen. fprintf(f, "TEXT TO INPUT\n") finally tries to print to NULL and pukes.
All system calls have to be checked. They all have different return values on error. fopen returns NULL and the error lies in errno. There's many ways to do fopen error handling, here's one that I like which gives the user information to debug the problem.
#include <string.h> // for strerror()
#include <errno.h> // for errno
#include <stdio.h>
#include <stdlib.h>
int main(){
// Put the filename in a variable so it can be used in the
// error message without needing to be copied.
char file[] = "estructuras.txt";
FILE *fp = fopen(file, "w");
if( fp == NULL ) {
// Display the filename, what you were doing with it, and why it wouldn't open.
fprintf(stderr, "Could not open '%s' for writing: %s\n", file, strerror(errno));
exit(-1);
}
}
strerror(errno) turns the numeric errno error code into a human readable string. There are quotes around the filename in case extra whitespace snuck in.
So you'll get an error like Could not open 'estructuras.txt': No such file or directory.
I am new to C programming and just writing a simple program to read all the lines from a text file and replace each number with a new one. Here is my code. It prints to the console for each line but not to the file. Can someone please suggest what is wrong with my code?
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE * file_ptr;
int num;
char line[128];
file_ptr = fopen (argv[1], "a+");
if(file_ptr==NULL)
{
printf("Error opening file");
}
if(file_ptr!=NULL)
{
while(fgets(line,128,file_ptr)!=NULL)
{
fputs("df",file_ptr);
printf("2");
}
}
fclose(file_ptr);
return(0);
}
The problem is that you're reading and writing from the same file, and your reads and writes interact.
Opening the file with the mode a+ (append, allowing reading) sets the file position at the beginning of the file, so the first call to fgets reads the first line. But in append mode, all writes are performed at the end of the file. So the first call to fputs sets the file position to the end of the file, then writes df. Since there's a single file position for both reading and writing, the next call to fgets is performed at the end of the file, and reads nothing.
The behavior of file position makes the mode a+ appropriate mostly when you want to read the whole current content of a file and then add something at the end.
Note that the only way to modify the content in the middle of a file is to replace a sequence of bytes by a sequence of bytes with the same length. So you can replace 12 by df, but you can't replace 123 by df: if you set the file position where 123 is located and write df, you'll end up with df3. To replace numbers by strings of potentially different length, you'll need to rewrite the file as a whole
When you want to completely modify a file, there are three main techniques:
Load the current content in memory, truncate the file to 0, write the new content.
Open the current file for reading, create a new file, write the new content to the new file, close the old file, then move (rename) the new file to overwrite the old file.
Rename the old file, create a new file with the original name, read the current content from the renamed file, write the new content and close the files.
The first method has a major downside: if your program crashes or the computer loses power, the file will be lost. Thus you should almost always use one of the other two approaches: they use more disk space but the added safety is almost always worth it.
The following code, which incorporated several oversights in the OP code
will tell the user about any error conditions that occur
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE * file_ptr;
char line[128];
if( 2 > argc )
{ // then invalid number of parameters
printf( "\nUsage: %s filename\n", argv[0]);
exit(EXIT_FAILURE );
} // end if
// implied else, file name parameter exists
if( NULL == (file_ptr = fopen (argv[1], "a+") ) ) // open for read and append
{ // then fopen failed
perror( "fopen failed" ); // output reason for failure to open file
exit(EXIT_FAILURE );
} // end if
// implied else, fopen successful
// note: second pass through this loop will fail as file pointer will be at end of file
// always put literal first, so compiler will catch syntax errors
while(NULL != fgets(line,sizeof(line),file_ptr) )
{
if( EOF == fputs("df",file_ptr) )// appends 'df' to end of file
{ // then fputs failed
perror( "fputs failed" );
exit( EXIT_FAILURE );
}
// implied else, fputs successful
printf("2");
fflush( stdout );
} // end while
fclose(file_ptr);
return(0);
} // end function: main
The program always ends up exiting. I seem to be running in to this problem frequently and I think I somehow previously fixed it but I'm not sure how. Why does it not create a file?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main (void){
FILE *fp;
int c;
char file_w[100];
char string[100];
printf("Enter filename\n");
fgets(file_w, 100, stdin);
fp = fopen(file_w, "w");
if (fp == NULL){
printf("Can't open file\n");
exit(0);
}
printf("Enter a string");
fgets(string, 100, stdin);
for(c = 0; c <= sizeof(string); c++)
{
fprintf(fp, "%s\n", string);
}
printf("file written");
fclose(fp);
return 0;
}
Try to print the name of the file you have entered:
printf("%s\n", file_w);
just after the line you get file_w, just to be sure to enter what you want. I same cases the terminal could be wrongly configured.
Try to enter an absolute name path, if your computer is a Linux or Unix:
/tmp/newfile.txt
If your computer is Windows... Well try to see if C:\temp\ exist (or create it) and then enter:
C:\temp\newfile.txt
In any case, remember that you can specify an absolute path, and not only the file name. So double check if you have the rights (i.e. the permissions) to write into the directory where the file should be written.
In case you want check the error and have a better description of the problem try to use the following lines instead of your code, just under the fopen
if( fp == NULL ) {
// Error, as expected.
perror( "Error opening file" );
printf( "Error code opening file: %d\n", errno );
printf( "Error opening file: %s\n", strerror( errno ) );
exit(-1);
}
strerror it is a wonderful function just because return you a description of the problem instead of an error code.
I bet the problem is "invisible character after actual name from fgets()". I'll let you figure out exactly what that character is, where it comes from and how to fix it, as "struggling to solve a problem" is part of the learning process when it comes to programming. If it was easy, everyone could do it.
If the return value of fopen is NULL it means some error occurred. I suggest you look into the errno global to see what error has occurred to help you debug why it's not opening the file.
The w flag does the following:
write: Create an empty file for output operations. If a file with the same name already exists, its contents are discarded and the file is treated as a new empty file.
So it should create a file when none exists, or when it does exist, overwrite its content.
If it does not do that, you have another problem, but from the little information you've given, it's hard to tell what it is.
I tried as a name of file the following:
C:\\temp\\test_file.txt
or
fopen("C:\\temp\\employees.txt", "w");
and it works fine, without errors (I made it in Windows 10. GCC win32, Version: 6.3.0).
I think that you have to use an absolute path to create the file.
use gets() instead of fgets()...it will work
.
.
gets(file_w);
.
.