How would I be able to reset a pointer to the start of a commandline input or file. For example my function is reading in a line from a file and prints it out using getchar()
while((c=getchar())!=EOF)
{
key[i++]=c;
if(c == '\n' )
{
key[i-1] = '\0'
printf("%s",key);
}
}
After running this, the pointer is pointing to EOF im assuming? How would I get it to point to the start of the file again/or even re read the input file
im entering it as (./function < inputs.txt)
If you have a FILE* other than stdin, you can use:
rewind(fptr);
or
fseek(fptr, 0, SEEK_SET);
to reset the pointer to the start of the file.
You cannot do that for stdin.
If you need to be able to reset the pointer, pass the file as an argument to the program and use fopen to open the file and read its contents.
int main(int argc, char** argv)
{
int c;
FILE* fptr;
if ( argc < 2 )
{
fprintf(stderr, "Usage: program filename\n");
return EXIT_FAILURE;
}
fptr = fopen(argv[1], "r");
if ( fptr == NULL )
{
fprintf(stderr, "Unable to open file %s\n", argv[1]);
return EXIT_FAILURE;
}
while((c=fgetc(fptr))!=EOF)
{
// Process the input
// ....
}
// Move the file pointer to the start.
fseek(fptr, 0, SEEK_SET);
// Read the contents of the file again.
// ...
fclose(fptr);
return EXIT_SUCCESS;
}
Piped / redirected input doesn't work like that. Your options are:
Read the input into an internal buffer (which you already seem to be doing); or
Pass the file name as a command-line argument instead, and do with it as you please.
Related
How would I be able to reset a pointer to the start of a commandline input or file. For example my function is reading in a line from a file and prints it out using getchar()
while((c=getchar())!=EOF)
{
key[i++]=c;
if(c == '\n' )
{
key[i-1] = '\0'
printf("%s",key);
}
}
After running this, the pointer is pointing to EOF im assuming? How would I get it to point to the start of the file again/or even re read the input file
im entering it as (./function < inputs.txt)
If you have a FILE* other than stdin, you can use:
rewind(fptr);
or
fseek(fptr, 0, SEEK_SET);
to reset the pointer to the start of the file.
You cannot do that for stdin.
If you need to be able to reset the pointer, pass the file as an argument to the program and use fopen to open the file and read its contents.
int main(int argc, char** argv)
{
int c;
FILE* fptr;
if ( argc < 2 )
{
fprintf(stderr, "Usage: program filename\n");
return EXIT_FAILURE;
}
fptr = fopen(argv[1], "r");
if ( fptr == NULL )
{
fprintf(stderr, "Unable to open file %s\n", argv[1]);
return EXIT_FAILURE;
}
while((c=fgetc(fptr))!=EOF)
{
// Process the input
// ....
}
// Move the file pointer to the start.
fseek(fptr, 0, SEEK_SET);
// Read the contents of the file again.
// ...
fclose(fptr);
return EXIT_SUCCESS;
}
Piped / redirected input doesn't work like that. Your options are:
Read the input into an internal buffer (which you already seem to be doing); or
Pass the file name as a command-line argument instead, and do with it as you please.
In this code I opened my files in my open_file function. Then the process_file function needs to copy the text from my in file and Copy it to an out file. Right now it produces a new file but it is blank. It does not give me any error messages. I do not know what is wrong.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_LEN 100
FILE* open_file(char prompt[], char mode[]);
FILE* process_file(FILE* in, FILE* out);
int main(int argc, const char * argv[]) {
FILE* in = NULL;
FILE* out = NULL;
printf("MAD-LIBS Text Processor\n");
printf("The Program will open a mad-libs file, ask you to fill various words, and produce a funny story.\n");
open_file("Enter mad-lib file name:\n", "r");
open_file("Enter file name for resulting story:\n", "w");
process_file(in, out);
fclose(in);
fclose(out);
return 0;
}
/* open_file = prompts user for file name & and attempts to open it, if it fails it prompts the user again. */
FILE* open_file(char prompt [], char mode[]) {
char filename[255];
FILE* in;
do {
printf("%s", prompt);
scanf("%s", filename);
in = fopen(filename, mode);
if (in == NULL) {
printf("Unable to open file: %s. Try Again!\n", filename);
}
} while(in == NULL);
return in;
}
/* process_file = processes entire input file and writes it to output file */
FILE* process_file(FILE* in, FILE* out) {
char content[MAX_LEN];
char NewContent[MAX_LEN];
//gets whats in file in
while(fgets(content, content[MAX_LEN], in) != NULL) {
fputs (content, stdout);
strcat(NewContent, content);
}
// copies it
while (fgets(content, content[MAX_LEN], in) != NULL) {
fprintf(out, "%s", content);
}
printf("Successfully copied file\n");
return in;
}
You never assign the FILE* from open_file function to your variable, so it never gets processed.
in = open_file("Enter mad-lib file name:\n", "r");
out = open_file("Enter file name for resulting story:\n", "w");
You are not storing the FILE pointers that open_file is returning, so in
and out remain uninitialized.
You have to do:
in = open_file("Enter mad-lib file name:\n", "r");
out = open_file("Enter file name for resulting story:\n", "w");
process_file(in, out);
Also your process_file is wrong. NewContent is not initialized, when you do
strcat(NewContent, content);
this yields undefined behaviour. Declare NewContent like this:
char NewContent[MAX_LEN] = { 0 };
so that it is properly \0-terminated.
Also depending on the size of the file you are copying, MAX_LEN might not be
long enough to hold the whole file. In that case you would overflow the buffer.
It would be better not to use NewContent in the first place and write to out
in the same reading loop:
FILE* process_file(FILE* in, FILE* out) {
char content[MAX_LEN];
//gets whats in file in
while(fgets(content, MAX_LEN, in) != NULL) { //<- your fgets was wrong
fputs (content, stdout);
fprintf(out, "%s", content); // or fputs(content, out);
}
printf("Successfully copied file\n");
return in;
}
And you were calling fgets incorrectly (look at my corrected code)
Also bear in mind, that you did have 2 loop doing while(fgets(...) != NULL.
Well, the first loop ends, that's because fgets returns NULL, most likely
because the whole file was read or there was an I/O error. In either case
subsequent calls of fgets will return NULL as well, so your second loop
would not even be executed at all.
I am trying to repeatedly read a string from the command line and print it to a file. This is my code:
int main ()
{
FILE* fp=fopen("test.txt","w");
char* tofile[10];
while(1){
printf("cat: ");
scanf("%s",tofile);
fprintf(fp,"%s\n",tofile);
}
return 0;
}
It works just fine outside the loop. But inside, it just doesn't print.
The fprintf function returns the correct amount of characters it has to print.
Note: I know there's a similar question out there, but it hasn't been answered yet, and I hope my code can help in this matter since it's simpler.
Well first it doesn't seem that what you want is reading on the command line.
The command line what you write right when you execute your program such as:
./main things that are on the command line
What it seems you want to do is to read on the standard input.
What you should consider is to use the fgets function, as it has a limit of characters to be read, so that you can store them "safely" into a buffer, like your tofile.
As you want to read on the standard input you can use the stdin stream (which is a FILE* that is automatically created for every program)
The line goes
fgets(tofile, 10, stdin);
Your loop becoming :
while (fgets(tofile, 10, stdin) != NULL) {
printf("cat: ");
fprintf(fp, "%s\n", tofile);
}
meaning: as long as we can read on the standard input, print "cat :" and store what we just read in the file controlled by the stream pointer fp.
Some important stuff
When you try to open a stream it may fail and you should test it:
char filename[] = "test.txt";
FILE *fp = fopen(filename, "w");
if (fp == NULL) {
fprintf(stderr, "Failed to open the file of name : %s", filename);
return EXIT_FAILURE;
}
Right before exiting your main, you should also close the file and check if it has succeeded, like that for example:
if (fclose(fp) != 0) {
fprintf(stderr, "Failed to close the file of name : %s", filename);
return EXIT_FAILURE;
}
The whole thing becomes:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char filename[] = "test.txt";
FILE *fp = fopen(filename, "w");
if (fp == NULL) {
fprintf(stderr, "Failed to open the file of name : %s", filename);
return EXIT_FAILURE;
}
char tofile[10];
printf("cat: ");
while (fgets(tofile, 10, stdin) != NULL) {
printf("cat: ");
fprintf(fp, "%s\n", tofile);
}
if (fclose(fp) != 0) {
fprintf(stderr, "Failed to close the file of name : %s", filename);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Improvements
I don't know if it is just a little program or it aspires to become a greater program.
In the last case you should consider using defines and not a magical number such as
#define BUFFER_MAX_SIZE 10
char tofile[BUFFER_MAX_SIZE];
while (fgets(tofile, BUFFER_MAX_SIZE, stdin) != NULL) { ... }
This helps for readability and makes the program less apt to debug when modifying such a size. Because with the define all the part of the code needing the size will still be fully functional without modifying them.
Please also keep in mind that your tofile acts as a buffer, and it's really a small buffer that can easily be overflowed.
This will work. fgets() returns the string it reads from the specified file pointer. If this string returns only a newline ("\n"), that means nothing was entered at stdin.
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *fp = fopen("test.txt","w");
// always check if fopen() == null
if (!fp) {
fprintf(stderr, "Could not write to file\n");
return 1;
}
char tofile[30];
printf("cat: ");
while (fgets(tofile, 30, stdin)) {
if (strcmp(tofile, "\n") == 0)
break;
fprintf(fp, "%s", tofile);
printf("cat: ");
}
// always fclose()
fclose(fp);
return 0;
}
Edited code.
I have to write a program witch reads from a file received by line and then it overwrites it with the read words uppercased.
This is my code
void toUpperCase(char* string) {
int i=0;
while(string[i])
{
string[i]=toupper(string[i]);
i++;
} }
int main(int argc, char** argv) {
if(argc==1)
{
puts("Error: INSERT PATH");
exit(0);
}
char* file=argv[1];
FILE* fd=fopen(file,"r+");
if(fd<0)
{
perror("Error opening file: ");
exit(0);
}
char buffer[30][30];
int i=0;
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
int j=0;
for(j=0; j<i; j++)
{
toUpperCase(buffer[j]);
fwrite(buffer[j],strlen(buffer[j]),1,fd);
}
fclose(fd);
return 0; }
but this program appends the words contained in buffer[][] instead of overwriting the file.
If the file contain was something like pippo pluto foo then, after the execution is pippo pluto fooPIPPOPLUTOFOO instead of PIPPO PLUTO FOO.
Where am i wrong? Thank you
You have to reset the file position indicator using fseek, as fscanf will advance it. Something like
fseek(fd, length_of_read_string, SEEK_CUR);
This allows you to read the file in chunks, but it will be tricky to get right. Or of course reset it to the file start because you read everything in 1 go:
fseek(fd, 0L, SEEK_SET);
I strongly recommend writing the modified data into a new file, and then after the program has run, delete the initial file and rename the new one. That will also take care of another issue with your program, you are reading the entire file into memory before handling it.
If you want to do in-place translation that doesn't change lengths, you can open the source file in two streams and then do read-chunk, write-chunk in lockstep. That has the advantage of being super-easy to convert to a non-in-place version that will work with nonseekable files too (stdin/stdout, pipes, and sockets).
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h> //toupper
inline void upcaseStr(char* str){
for(;*str;str++) { *str=toupper(*str); }
}
int upcaseStream(FILE* in, FILE* out){
char buf[BUFSIZ]; //BUFSIZ is an implementation-defined constant for an optimal buffer size
while(fgets(buf, BUFSIZ, in)){
upcaseStr(buf);
if(fputs(buf, out) == EOF){ return 1; }
}
if(!feof){ return 1; }
return 0;
}
int main(int argc, char **argv)
{
//default in and out
FILE* in = stdin;
FILE* out = stdout;
if(argc == 2) {
in = fopen(argv[1], "r"); //for reading
out = fopen(argv[1], "r+"); //for writing (and reading) starting at the beginning
if(!(in && out)){
fprintf(stderr, "Error opening file %s for reading and writing: %s\n", argv[1], strerror(errno));
}
}
return upcaseStream(in, out);
}
If you do use the in-place version, then in the unlikely event that the if(fputs(buf, out) == EOF){ return 1; } line should return, you're screwed unless you have a backup copy of the file. :)
Note:
You shouldn't name your FILE pointers fd because C people will tend to think you mean "file descriptor". FILE is a struct around a file descriptor. A file descriptor is just an int that you can use for FILE access with the raw system calls. FILE streams are an abstraction layer on top of file descriptors--they aren't file descriptors.
As you read from the file, its internal position indicator gets moved. Once you start writing, you start writing from that position on, which happens to be at the end of the file. So you effectively append the data to the file.
Rewind the handle to reset the position indicator before writing into the file:
rewind(fp);
On a side note, you are reading the file incorrectly:
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
When you reach the end of the file, fscanf will return an error and not read anything, yet you still increment variable i, as if the read was successful. And then you check feof() for end-of-file, but i was already incremented.
Check feof() and return of fscanf() immediately after calling fscanf():
while(1)
{
int read = fscanf(fd,"%s",buffer[i]);
if( read != 1 )
//handle invalid read
if( feof(fd) )
break;
i++;
}
Think about what happens if the string is longer than 29 characters and/or the file contains more than 30 strings. char buffer[30][30];
Welcome to StackOverflow!
Reopening the stream with fopen with the "w" parameter:
fd=fopen(file, "w");
It opens the file and if there are any contents in the file, it clears them.
How do I determine if a file is empty? The file is opened by a C program running on the Windows platform. I want to open a file in append mode, and, if empty, first print a header to it.
// Open CSV & write header
report_csv = fopen("SNR.csv", "a+");
if (!report_csv) {
fprintf(stderr, "Unable to open CSV output file...");
return -1;
}
if (!ftell(report_csv)) {
fprintf(report_csv, "Column A;Column B;Column C\n");
}
// ... print data to file
fclose(report_csv);
I was expecting ftell to return the current file size if the file was not empty, which happens because the code above is looped.
However, ftell always returns 0 and the header is printed multiple times.
I know I could fopen it with r and use fseek/ftell/fclose and then fopen it again with a+, but I think it's possible to do this without opening and closing the file multiple times.
Actually, when fopening a file in append mode, the file pointer is initially at the begining of the file. It moves to the end of it as soon as you write something or use fseek.
I just needed to add fseek(report_csv, 0, SEEK_END); before my if (!ftell(report_csv)).
Let's check this.
Code:
#include <stdio.h>
int main(int argc, char **argv) {
FILE *test;
size_t size;
char buf[100];
/* Truncate file */
test = fopen("test", "w");
if (!test) {
fprintf(stderr, "Cannot open file `test`!\n");
return 1;
}
/* Write something */
fprintf(test, "Something. ");
fclose(test);
/* Open in append */
test = fopen("test", "a+");
if (!test) {
fprintf(stderr, "Cannot open `test` in append mode!\n");
return 1;
}
/* Try to get the file size */
size = ftell(test);
printf("File pointer is: %d\n", size);
fseek(test, 0, SEEK_END);
size = ftell(test);
printf("After `fseek(test, 0, SEEK_END)`, the file pointer is: %d\n", size);
/* Append */
fprintf(test, "And that. ");
fclose(test);
/* Same without fseek */
test = fopen("test", "a+");
if (!test) {
fprintf(stderr, "Cannot open `test` in append mode!\n");
return 1;
}
fprintf(test, "Hello! ");
size = ftell(test);
printf("File size is now: %d\n", size);
fclose(test);
/* Try to read */
test = fopen("test", "r");
if (!test) {
fprintf(stderr, "Unable to open `test` for reading!\n");
return 1;
}
printf("File contents:\n\t");
while (test && !feof(test)) {
fgets(buf, sizeof(buf), test);
printf("%s", buf);
}
/* Cleanup & exit */
fclose(test);
printf("\n\nExiting.\n");
return 0;
}
Output:
File pointer is: 0
After `fseek(test, 0, SEEK_END)`, the file pointer is: 11
File size is now: 28
File contents:
Something. And that. Hello!
Exiting.
When opening a file with fopen with the a+ mode, all writing operations will be performed at the end of the file. You can reposition the internal pointer to anywhere in the file for reading, but writing operations will move it back to the end of file. The initial pointer position for reading is at the beginning of the file.
So you need to call an fseek(pFile, 0, SEEK_END) on your FILE pointer.
You can call _stat() and get the value st_size into struct _stat (you dont need open the file).Declared in sys/types.h followed by sys/stat.h
I donĀ“t know Windows programming, but it can help you: http://msdn.microsoft.com/en-us/library/14h5k7ff.aspx