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.
Related
I am trying to pass a file to my program however it always gives error, cannot open file.
My command is: (I am on desktop path, I am using ubuntu)
./out < /usr/share/dict/words > out.txt 2> out2.txt
Output files are created but file input seems empty. I am getting file path as:
char *infile;
scanf("%s", infile);
printf("file: %s\n", infile);
I also tried:
fscanf(stdin, "%s", infile);
Nothing changed. Also, I have to take input as shown above, I know < means stdin but I cannot read its content somehow.
This is file opening part and error message:
file = fopen(infile, "r");
if (file == 0) {
fprintf(stderr, "File failed\n");
return 1;
}
There seem to be some confusion in your approach:
you redirect input to your program from a text file containing words, the classic /usr/share/dict/words file. This file is the input to your program, you can read the contents with getchar(), scanf(), fgets() and other stream input functions, but the name of the file is not available to your program, nor do you need to fopen this file to read its contents.
scanf("%s", buf) is an unsafe way to read a word from stdin. You must pass a pointer to a char array, not an uninitialized pointer as you do in the fragment posted. scanf() will write to the memory pointed to by this pointer, so an uninitialized pointer will cause undefined behavior, probably a crash.
To use scanf() safely, you must provide the maximum number of characters to store into the destination array, otherwise a long enough word in the inoput file will cause scanf() to write beyond the end of the array, causing undefined behavior as well. Here is an example of this:
// filtering 4 letter words:
char buf[100];
while (scanf("%99s", buf) == 1) {
if (strlen(buf) == 4)
printf("%s\n", buf);
}
If you want to pass the path of the input file, use command line arguments.
The bash command would become:
./a.out /usr/share/dict/words > out.txt 2> out2.txt
And the main function:
#include <errno.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[) {
FILE *fp;
if (argc < 2) {
fprintf(stderr, "%s: missing file name argument\n", argv[0]);
return 1;
}
if ((fp = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "%s: cannot open file %s: %s\n",
argv[0], argv[1], strerror(errno));
return 1;
}
// for example's sake: filtering 4 letter words:
char buf[100];
while (fscanf(fp, "%99s", buf) == 1) {
if (strlen(buf) == 4)
printf("%s\n", buf);
}
fclose(fp);
return 0;
}
char *infile is just a pointer and does not allocate space for the string, so the input will not be saved. Try something like char infile[50]. Increase the size if needed for your input.
For an assignment I have to input text from 2 files line by line into a 3rd file. So file 1 line 1 would be file 3 line 1 and file 2 line would would be file 3 line 2. I have attempted to this but can not seem to get the lines from each file to alternate. I am only able to get lines from each file separately. Please help with any suggestions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
FILE *file1, *file2, *file3;
char line [1000]; /* or other suitable maximum line size */
// check to make sure that all the file names are entered
if (argc != 4) {
perror("Error: ");
printf("Not enough files were entered!\n");
exit(0);
}
file1 = fopen(argv[1],"r");;
file2 = fopen(argv[2],"r");
file3 = fopen(argv[3],"w");
// check whether the file has been opened successfully
if (file1 == NULL)
{
perror("Error: ");
printf("Cannot open file1 %s!\n", argv[1]);
exit(-1);
}
// check whether the file has been opened successfully
if (file2 == NULL)
{
perror("Error: ");
printf("Cannot open file2 %s!\n", argv[2]);
exit(0);
}
// check whether the file has been opened successfully
if (file3 == NULL)
{
perror("Error: ");
printf("Cannot open file3 %s!\n", argv[3]);
exit(0);
}
int count = 0;
while (1)
{
if(fgets(line, sizeof line, file1) != NULL)
{
count+=1;
fprintf(file3, line);
}
else
{
break;
}
if(fgets(line, sizeof line, file2) != NULL)
{
count++;
fprintf(file3, line);
}
else
{
break;
}
}
fclose (file1);
fclose (file2);
fclose (file3);
}
fprintf(FILE *, const char *format, ...) expects a format as the 2nd argument.
Using fprintf(file3, line); will invoke undefined behavior (UB) should line contain a '%' or at least a missing % if "%%" was encountered.
Use fputs()
// fprintf(file3, line);
fputs(line, file3);
Additional concerns for advanced coding:
If the source file contains a null character, using fgets() is insufficient as it does not report the length read. Other approaches include using fgetc(), fread() or non-standard C getline().
If an input file does not end with a '\n', that rump line may look like a pre-fix to the line read from the other file.
As OP has noted, line length's of about 1000+ are a problem.
Source files line-endings, should they not match the code's understanding of line-ending can cause issues.
TODO: If a certain word exists in the .txt file, copy that word to another txt file
PROBLEM: It won't write the word after it is found in "from.txt" to "to.txt".
ERROR:
This line: while ((fscanf(ifp, "%s", line)) != EOF)
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define MAX_LINE 256
void main()
{
FILE *ifp;
FILE *ofp;
char line[MAX_LINE];
char word[MAX_LINE];
if ((ifp = open("from.txt", "r")) == NULL)
{
printf("Can't open input file.");
exit(1);
}
if ((ofp = open("to.txt", "w")) == NULL)
{
printf("Can't open output file.");
exit(1);
}
printf("Enter your word: ");
gets(word);
while ((fscanf(ifp, "%s", line)) != EOF)
{
if (strcmp(line, word) == 0)
{
fputs(line, ofp);
break;
}
}
fclose(ifp);
fclose(ofp);
getch();
}
You are using a wrong API for opening a file. API which you use -- open -- is for low-level, descriptor based access. You'll get an int value out of it, and ifp and ofp won't be correct.
You must use a stream based API, called fopen. It returns a pointer to the FILE structure, which in turn you can pass to fscanf() etc.
Very important: compile this program with all compiler warnings and observe the output. I'm pretty sure you're getting a log of warning messages from the compiler already.
PROBLEM: It won't write the word after it is found in "from.txt" to "to.txt".
As noted in comments and other answers, and for other reasons, open() may not be the best choice for writing strictly ANSI portable code.
But this is not the reason for the stated problem.
The function strcmp(...) is not doing what is needed.
In this line:
if (strcmp(line, word) == 0)
A single word is being compared with the entire line. And the single word is never identified. Even if the line in the file appears to have only a single word, white space, such as a space, tab or new line character ( " ". \n, \t) would cause the two arguments of strcmp to be unequal.
strcmp(string1, string2) possible return values are:
Positive integer when string1 is greater than string2
Zero when string1 is equal to string2
Negative integer when string1 is less than string2
The function strstr would be a better fit. Change the strcmp line to use strstr :
if (strstr(line, word)){...
strstr(...) looks for the existence of a sub-string within a string. And, with the other changes that have been discussed, made your code do as you described it should.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define MAX_LINE 256
void main()
{
FILE *ifp;
FILE *ofp;
char line[MAX_LINE];
char word[MAX_LINE];
//**************************************************************** it's fopen not open ***********************************************************
if ((ifp = fopen("from.txt", "r")) == NULL)
{
printf("Can't open input file.");
exit(1);
}
if ((ofp = fopen("to.txt", "w")) == NULL)
{
printf("Can't open output file.");
exit(1);
}
printf("Enter your word: ");
gets(word);
while ((fscanf(ifp, "%s", line)) != EOF)
{
if (strcmp(line, word) == 0)
{
fputs(line, ofp);
break;
}
}
fclose(ifp);
fclose(ofp);
getch();
}
its working fine ...
First off I am creating a program that will read lines of characters and find words (they don't have to have meaning, i.e 'ab' could be word ) and storing them in the appropriate data structure. I used trie structure to store the words. I am given a mapping file as a command line argument yet inside the mapping file I have two data files I need to gain information from. The usage interface is as follows: first(program name) <mappingfile>.
Inside the mapping file, there exists two data files: <dictFile> and <dataFile>. Im not sure how to read and store the information presented the two data files. So far I have the following:
#include <stdio.h>
#include<stdlib.h>
void readDict(FILE *dict_file){
}
int main(int argc, char *argv[]){
FILE* file;
if(argc != 2){ //error in inputing, not 2 files
printf("error\n");
return 0;
}
file = fopen(argv[1],"r" ); //reading the mapping file
input;
if(file == NULL){ //nothing inside file
printf("file does not exist\n");
return 0;
}
}
My goal is to have pointers point to respective data files in the mapping file which I can use for reading their contents.
I will be given the following input in the command line:
first(program name) <mappingfile>.
Inisde the mapping file contains the lines of two plain .txt files in the form
<dictFile> <dataFile>.
I wish to access both contents of <dictFile> and <dataFile>.. with pointers to the respective file.
If I understand your question correctly you want to parse a file where each line contains the filenames of two other files and then read from these. What you can do is use fgets to read your mapping file line by line. What you can do next is use the function strtok to split your string on a whitespace. I'll break it down for you step by step.
Firstly we want to open the mapping file for reading
if((file = fopen(argv[1],"r")) == NULL) {
perror("error opening file");
return 1;
}
This will try to open the mapping file specified by the command line arguments of your program and if it fails it will print a corresponding error message.
while(fgets(buf, sizeof(buf), file) != NULL) {
After we've opened the file we want to iterate through all the lines until we reach the end of the file and fgets will return NULL. fgets will put the current line into buf.
dictfilename = strtok(buf, " ");
datafilename = strtok(NULL, " ");
strtok(dictfilename, "\n"); /* Remove any trailing newlines */
strtok(datafilename, "\n");
We need to split the line read by fgets by a delimter (a whitespace) so we know which part corresponds to the dictfile and the datafile. This is done by using the strtok function which returns a pointer to the substring before the whitespace and when passing in NULL it will return a pointer to the substring after the whitespace. A slightly weird way of removing any trailing newlines is to use strtok and the newline as a delimiter.
if((dictfile = fopen(dictfilename,"r")) == NULL) {
fprintf(stderr, "error opening file %s: %s\n", dictfilename, strerror(errno));
return 1;
}
if((datafile = fopen(datafilename,"r")) == NULL) {
fprintf(stderr, "error opening file %s: %s\n", datafilename, strerror(errno));
return 1;
}
Very similiarly to how we open the mapping file, we now open the two files found on the current line read by fgets with "r" mode which opens for reading. If the file does not exist or cannot be found, the fopen call fails.
printf("Content of %s:\n", dictfilename);
while ((c = getc(dictfile)) != EOF)
putchar(c);
printf("\nContent of %s:\n", datafilename);
while ((c = getc(datafile)) != EOF)
putchar(c);
This is a very simple method of "dumping" the content of the files. It uses getc to read the next char from the file and prints it until it reads EOF. This is where you should do your own function.
fclose(dictfile);
fclose(datafile);
And don't forget to close the files afterwards or you will leak resources.
Finally here is the code on what I just described
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define MAX_LENGTH 100 // change this to the actual maximum length of your lines.
int main(int argc, char **argv){
FILE* file, *dictfile, *datafile;
char c;
char buf[MAX_LENGTH];
char *dictfilename, *datafilename;
if(argc != 2) {
fprintf(stderr, "Usage: %s <mapping file>\n", argv[0]);
return 0;
}
if((file = fopen(argv[1],"r")) == NULL) {
perror("error opening file");
return 1;
}
while(fgets(buf, sizeof(buf), file) != NULL) {
dictfilename = strtok(buf, " ");
datafilename = strtok(NULL, " ");
strtok(dictfilename, "\n"); /* Remove any trailing newlines */
strtok(datafilename, "\n");
if((dictfile = fopen(dictfilename,"r")) == NULL) {
fprintf(stderr, "error opening file %s: %s\n", dictfilename, strerror(errno));
return 1;
}
if((datafile = fopen(datafilename,"r")) == NULL) {
fprintf(stderr, "error opening file %s: %s\n", datafilename, strerror(errno));
return 1;
}
// do something with the files (e.g read all the content)
printf("Content of %s:\n", dictfilename);
while ((c = getc(dictfile)) != EOF)
putchar(c);
printf("\nContent of %s:\n", datafilename);
while ((c = getc(datafile)) != EOF)
putchar(c);
printf("\n");
// don't forget to close the files when you're done with them.
fclose(dictfile);
fclose(datafile);
}
fclose(file);
}
If I understand you correctly this should do it. Note that it assumes your filenames don't have any spaces. And if you want to use the "non secure" api's you need to add _CRT_SECURE_NO_WARNINGS to the project properties under Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions.
#include <stdio.h>
#include<stdlib.h>
void readDict(FILE *dict_file){
}
int main(int argc, char *argv[]){
FILE* file;
if(argc != 2){ //error in inputing, not 2 files
printf("error\n");
return 1;
}
file = fopen(argv[1],"r" ); //reading the mapping file
//input;
if(file == NULL){ //nothing inside file
printf("file does not exist\n");
return 1;
}
char dictFileString[256], dataFileString[256];
fscanf( file, "%255s %255s", dictFileString, dataFileString );
FILE *dictFile, *dataFile;
dictFile = fopen( dictFileString, "r" );
if (dictFile == NULL) {
printf( "%s does not exist\n", dictFileString );
fclose(file);
return 1;
}
dataFile = fopen( dataFileString, "r" );
if (dataFile == NULL) {
printf( "%s does not exist\n", dataFileString );
fclose(file);
fclose(dictFile);
return 1;
}
readDict(dictFile);
// The additional logic would be placed here.
fclose( dictFile );
fclose( dataFile );
// If you need to read additional file names then loop
// back up to read the next line of 'file'
fclose( file );
return 0;
}
I am using a basic C code to print to a text file:
FILE *file;
file = fopen("zach.txt", "a+"); //add text to file if exists, create file if file does not exist
fprintf(file, "%s", "This is just an example :)\n"); //writes to file
fclose(file); //close file after writing
printf("File has been written. Please review. \n");
My question is regarding the above code: I have multiple lines I have printed that I would like to be saved to the text document. How can I easily include multiple lines of code to be printed in my file using the above code?
Move file writing into a procedure:
void write_lines (FILE *fp) {
fprintf (file, "%s\n", "Line 1");
fprintf (file, "%s %d\n", "Line", 2);
fprintf (file, "Multiple\nlines\n%s", "in one call\n");
}
int main () {
FILE *file = fopen ("zach.txt", "a+");
assert (file != NULL); // Basic error checking
write_lines (file);
fclose (file);
printf ("File has been written. Please review. \n");
return 0;
}
There are lots of ways to do this, here's one:
#include<stdio.h>
#include<string.h>
int appendToFile(char *text, char *fileName) {
FILE *file;
//no need to continue if the file can't be opened.
if( ! (file = fopen(fileName, "a+"))) return 0;
fprintf(file, "%s", text);
fclose(file);
//returning 1 rather than 0 makes the if statement in
//main make more sense.
return 1;
}
int main() {
char someText[256];
//could use snprintf for formatted output, but we don't
//really need that here. Note that strncpy is used first
//and strncat used for the rest of the lines. This part
//could just be one big string constant or it could be
//abstracted to yet another function if you wanted.
strncpy(someText, "Here is some text!\n", 256);
strncat(someText, "It is on multiple lines.\n", 256);
strncat(someText, "Hooray!\n", 256);
if(appendToFile(someText, "zach.txt")) {
printf("Text file ./zach.txt has been written to.");
} else {
printf("Could not write to ./zach.txt.");
}
return 0;
}
notice the strncpy and strncat functions since you aren't really utilizing the formatted input that comes with the xprintf functions.