I'm having some trouble with my code. I'm trying to read in some previous commands saved to a file, and place them in my array to use for later.
Here is my relevant piece of code:
if( (pastHist = fopen("history.txt", "r+")) == NULL)
{
pastHist = fopen("history.txt", "w+");
}
else
{
printf("%s", "INSIDE the else!");
pastHist = fopen("history.txt", "r+");
fscanf(pastHist, "%s", fstring);
while (fstring != NULL)
{
printf("%s %s", "the read in string is: ", fstring);
strcpy(cmndLine[cmndIndex], fstring);
strcpy(cmndLinecpy[cmndIndex], fstring);
cmndIndex++;
cmndNum++;
fscanf(pastHist, "%s", fstring);
}
}
Now the code writes to the file fine. (the writing part is held elsewhere). If I read from a file I wrote to before and the file said:
ls
rmdir angel
history
then i use this print statement to double check what i'm reading... it prints out
"INSIDE the else! the read in string is: lsthe read in string is: rmdirthe read in string is: angelthe read in string is: historythe read in string is: historythe read in string is: history
... and it repeats that the last thing read in was history a million times. Why is this the case? I also tried with the while condition
while(getchar() != EOF)
but that gave me the same thing.
please help.
Thanks.
fstring can never be set to NULL by that call to fscanf. What you want to check is the return value of fscanf.
Your getchar() loop likewise does nothing useful - it's reading from the standard input, not from your file.
Related
I have a configuration file that I need to alter.
The structure of the file is:
resolution 12x34
interval 1234
So two strings with a whitespace delimiter. The code I use to alter it is this:
FILE *fp = fopen(configuration_file, "a+");
char str[100], key[100], value[100];
if(fp) {
while(fgets(str, 100, fp) != NULL) {
if(2 == sscanf(str, "%s %s", &key, &value)) {
if(strcmp(key, "resolution") == 0){
if(msg->resolution){
fprintf(fp, "%s %s\r\n", key, msg->resolution);
}
} else if(strcmp(key, "interval") == 0) {
if(msg->interval) {
fprintf(fp, "%s %d\r\n", key, msg->interval);
}
} else {
fputs(str, fp);
}
} else {
fputs(str, fp);
}
}
} else {
(void)printf("-- Configuration file not found (%s)\r\n --", configuration_file);
}
fclose(fp);
The idea was to read it line by line. According to the documentation for fgets says that it stops at newlines. String-scan each line and parse them into a key and value. So far so good, acting as expected. And then print the new line to the file, overwriting the line it had just scanned. This is where the problem comes in. If I use fprintf, only the first value, resolution, is processed. The result of it is:
resolution oldxres
resolution newxres
It overwrites the wrong line and skips the second entirely.
If I remove the fprintf and instead simply print the values it has found, it prints both as it is supposed to.
What am I missing here? Does fprintf push the file pointer?
And then print the new line to the file, overwriting the line it had just scanned.
Files don't work this way. Write to a new file. When finished, rename the new file to the old name. Alternatively, read the entire file into memory, change the contents in memory, then write it back.
You can rewrite individual lines is if the modified line never becomes longer than the original one. Otherwise the modified line will spill over the next line you have not read yet, and destroy it. In order to prevent this you would need some kind of look-ahead buffer, which is just too cumbersome and error-prone. In the worst case you'd need to read the entire file anyway.
for example I have test.txt with
test1
test2
at the end of each line I would like to add some text
my code is:
fp = fopen("test.txt", "w");
while ((ch=getc(fp)) != EOF)
if (ch == '\n')
fprintf(fp, "newText");
my output is:
test1
newText
The outcome should be:
test1newText
test2newText
You cannot do it with a single file.
Here is what you need to do:
Open an auxiliary file for temporary output
Read the actual file line by line
For each line write the copy of the line into the auxiliary output
After writing the line write the suffix that you would like to append
Go to the next line until you process the whole file
Once you finished processing the whole file, close both files, and move the auxiliary file in place of the original input.
How to avoid a new line?, I successfully copy [the text] but when I try to add some text at the end of each line, it starts from new line
This is because you include the end-of-line character in your copied text.
If you read character-by-character, do not copy '\n's when you see them; if you read with fgets, check the last character, and skip it if it happens to be '\n' (fgets includes it in its return value).
You can’t read from your output file like that. It is possible to open a file for reading and writing, but it’s an advanced topic and isn’t really appropriate for text files.
The normal approach is to write to another file, and then replace the original if desired. Note that you’ll have to emit all the characters you read and your extra text.
If this is the whole function of the program, consider making it a filter (by using the standard streams); this is what’s expected by experienced users and saves some error checking.
eventually, I have succeed
if (!strcmp(fileName, SWM_DEBUG))
{
fp = fopen(fileName, "r");
fpOut = fopen("tmp.txt", "w");
while ((ch = fgetc(fp)) != EOF)
{
if (ch == '\n')
fprintf(fpOut, "TEST");
fputc(ch, fpOut);
}
}
Thanks for your support ☺
You need to change the fopen call to read from the file and use the fputc function to re-output the character you read, like this:
fp = fopen("test.txt", "r");
while ((ch=fgetc(stdin)) != EOF) {
if (ch == '\n') {
fprintf(fp, "newText");
}
fputc(ch, fp);
}
fprintf(fp, "newText");
As pointed out elsewhere, you can't simultaneously read and write a file in the way you were trying to do, so i've changed it to read from stdin to illustrate the code
I'm trying to have the program check, that, if a user inputs nothing the print statement will say it cant find the file name, but the issue I'm having is that the command line will just go to a new line after hitting enter instead of saying the print statement.
This is the code here. I was told that Null is the place holder for if nothing is put in so I thought it would work.
int main()
{
FILE *fin;
FILE *fout;
char fInName[50];
char fOutName[50];
printf("pleas type input file, and output file please type legibly\n ");
scanf("%s %s", &fInName, &fOutName);
fin = fopen(fInName, "r");
fout = fopen(fOutName, "r");
if (fInName == NULL && fOutName == NULL)
{
printf("Error: Cannot open input file %s.", fInName);
}
else if (fInName != NULL && fOutName == NULL)
{
printf("file found");
}
}
What im trying to test is if a first file name is entered and the second isnt then print the statement. If both arent entered then print file does not exist.
there is more to the code to see if the file exists or not, but thst would be a bit much, now Im just trying to understand why it wont read unentered data.
Ive tried looking at examples such as: How to detect empty string from fgets
and tried to alter the code to fit that type of style but it didnt work for me so Im giving you the code it was originally so that anything helpful wouldnt confuse me more.
Edit:
okay so I tried to do a simple code in order to see what may be the cause of this issue:
int main()
{
char firstname[50];
char lastname[50];
char nothing [0];
printf("pleas type input file, and output file please type legibly pwease\n ");
scanf("%s" "%s", firstname, lastname);
if (firstname == lastname )
{
printf("Error: Cannot open input file %s.", firstname);
}
else
{
printf("file found");
}
}
I ran the code using adam and either if I typed adam (space) adam or adam(enter) adam the program thinks that the input is not the same, I feel like that would help identify why it doesnt know why nothing is typed in.
The problem is occurring when you try to check if fInName == NULL.
The problem is that fInName is just a variable that you're using to store the name of the file that you want to open. What you actually want to check is that the user gave you a valid filename, and to do so you will want to understand what the return value of functions are.
For example, when you try to open a file using fopen(), if fopen() is unable to successfully open the file, say because the user didn't input anything or misspelled the filename, then fopen() will return NULL, storing it in whatever variable you assigned it to (in your case, *fin and *fout).
Also, scanf() is not recommended for char arrays because if the user inputs more data than you allocated for the array, which in this case is enough space for 50 characters, then scanf() will try to write data to memory that's not yours, causing a buffer overflow.
A much safer option is to use fgets() because you can choose exactly how much data is written into your char array, with the only downside being that fgets() will write newline characters \n (caused by hitting the enter key) into the array, though the simple solution is to overwrite the newline character with '\0'.
Therefore, I would propose:
int main(void)
{
char fInName[50];
char fOutName[50];
// ensure proper usage
do
{
printf("What file would you like to open? ");
// get infile from user and remove trailing newline '\n' character
fgets(fInName, 50, stdin);
fInName[strcspn(fInName, "\n")] = '\0';
}
// prompt for input until user enters something
while (strlen(fInName) < 1);
do
{
printf("What file would you like to output to? ");
// get outfile from user and remove trailing newline '\n' character
fgets(fOutName, 50, stdin);
fOutName[strcspn(fOutName, "\n")] = '\0';
}
// prompt for input until user enters something
while (strlen(fOutName) < 1);
FILE *fin = fopen(fInName, "r");
if (fin == NULL)
{
printf("Error: Cannot open input file %s.", fInName);
return 1;
}
else
{
printf("file found");
}
}
I know this is a dumb question, but how would I load data from a multiline text file?
while (!feof(in)) {
fscanf(in,"%s %s %s \n",string1,string2,string3);
}
^^This is how I load data from a single line, and it works fine. I just have no clue how to load the same data from the second and third lines.
Again, I realize this is probably a dumb question.
Edit: Problem not solved. I have no idea how to read text from a file that's not on the first line. How would I do this? Sorry for the stupid question.
Try something like:
/edited/
char line[512]; // or however large you think these lines will be
in = fopen ("multilinefile.txt", "rt"); /* open the file for reading */
/* "rt" means open the file for reading text */
int cur_line = 0;
while(fgets(line, 512, in) != NULL) {
if (cur_line == 2) { // 3rd line
/* get a line, up to 512 chars from in. done if NULL */
sscanf (line, "%s %s %s \n",string1,string2,string3);
// now you should store or manipulate those strings
break;
}
cur_line++;
}
fclose(in); /* close the file */
or maybe even...
char line[512];
in = fopen ("multilinefile.txt", "rt"); /* open the file for reading */
fgets(line, 512, in); // throw out line one
fgets(line, 512, in); // on line 2
sscanf (line, "%s %s %s \n",string1,string2,string3); // line 2 is loaded into 'line'
// do stuff with line 2
fgets(line, 512, in); // on line 3
sscanf (line, "%s %s %s \n",string1,string2,string3); // line 3 is loaded into 'line'
// do stuff with line 3
fclose(in); // close file
Putting \n in a scanf format string has no different effect from a space. You should use fgets to get the line, then sscanf on the string itself.
This also allows for easier error recovery. If it were just a matter of matching the newline, you could use "%*[ \t]%*1[\n]" instead of " \n" at the end of the string. You should probably use %*[ \t] in place of all your spaces in that case, and check the return value from fscanf. Using fscanf directly on input is very difficult to get right (what happens if there are four words on a line? what happens if there are only two?) and I would recommend the fgets/sscanf solution.
Also, as Delan Azabani mentioned... it's not clear from this fragment whether you're not already doing so, but you have to either define space [e.g. in a large array or some dynamic structure with malloc] to store the entire dataset, or do all your processing inside the loop.
You should also be specifying how much space is available for each string in the format specifier. %s by itself in scanf is always a bug and may be a security vulnerability.
First off, you don't use feof() like that...it shows a probable Pascal background, either in your past or in your teacher's past.
For reading lines, you are best off using either POSIX 2008 (Linux) getline() or standard C fgets(). Either way, you try reading the line with the function, and stop when it indicates EOF:
while (fgets(buffer, sizeof(buffer), fp) != 0)
{
...use the line of data in buffer...
}
char *bufptr = 0;
size_t buflen = 0;
while (getline(&bufptr, &buflen, fp) != -1)
{
...use the line of data in bufptr...
}
free(bufptr);
To read multiple lines, you need to decide whether you need previous lines available as well. If not, a single string (character array) will do. If you need the previous lines, then you need to read into an array, possibly an array of dynamically allocated pointers.
Every time you call fscanf, it reads more values. The problem you have right now is that you're re-reading each line into the same variables, so in the end, the three variables have the last line's values. Try creating an array or other structure that can hold all the values you need.
The best way to do this is to use a two dimensional array and and just write each line into each element of the array. Here is an example reading from a .txt file of the poem Ozymandias:
int main() {
char line[15][255];
FILE * fpointer = fopen("ozymandias.txt", "rt");
for (int a = 0; a < 15; a++) {
fgets(line[a], 255, fpointer);
}
for (int b = 0; b < 15; b++) {
printf("%s", line[b]);
}
return 0;
This produces the poem output. Notice that the poem is 14 lines long, it is more difficult to print out a file whose length you do not know because reading a blank line will produce the output "x�oA". Another issue is if you check if the next line is null by writing
while (fgets(....) != NULL)) {
each line will be skipped. You could try going back a line each time to solve this but i think this solution is fine for all intents.
I have an even EASIER solution with no confusing snippets of puzzling methods (no offense to the above stated) here it is:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string line;//read the line
ifstream myfile ("MainMenu.txt"); // make sure to put this inside the project folder with all your .h and .cpp files
if (myfile.is_open())
{
while ( myfile.good() )
{
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
Happy coding
Here's my dilemma. I have a file, and wish to read in all characters up until the program hits a '#', and ignore everything on that line after the '#'. For example
0 4001232 0 #comment, discard
This is frustrating, as it feels like there is a very simple solution. Thanks!
FILE *f = fopen("file.txt", "r");
int c;
while ((c = getc(f)) != '#' && c != EOF)
putchar(c);
Read a line using fgets, read through this line till you get a '#' character.
Read an another line...
There are plenty of ways and examples of how to do it. Usually, the idea is to have a variable that holds the state (before #, after # , after \n etc.) and run in a while loop until EOF. an example you can see here it's a program to remove C comments, but the idea is the same.
filePointer = fopen("person.txt", "r");
do
{
read = fgetc(filePointer);
//stop when '#' read or when file ends
if (feof(filePointer) || read == '#')
{
break;
}
printf("%c", read);
} while (1);
fclose(filePointer);
also you better check if file opened succesfully
if (filePointer == NULL)
{
printf("person.txt file failed to open.");
}
else
{
file operations
}
The solution depends on how you are "reading" that.
I could, for example, just remove all of those comments with sed 's/#.*//' <infile >outfile in bash.
EDIT: However, if I was parsing it manually, I could simply (in my loop for parsing it) have
if(line[i]=='#') {
continue;
}
which would stop parsing that line by exiting the loop.