char string[50], s[50];
File *f = tmpfile();
count = 1;
while (fgets(string, 50, stdin)) {
if (string[0] == '!') {
rewind(f);
} else {
fwrite(string, 50, 1, f);
}
if (strcmp("history\n", string) == 0) {
rewind(f);
while(fgets(s, 50, f)) {
printf("\t%d %s", count, s);
count++;
}
count = 1;
}
}
The context of this code is not hugely important. The problem is that let's say fgets takes in "ls", "date", and "history". The resulting output is:
1 ls
2 3 te
4 5 ory
6
It should be:
1 ls
2 date
3 history
Since feature requests to mark a comment as an answer remain declined, I copy the above solution here.
Looks like you get some '\r's in your buffer. And you should probably only fwrite strlen(string) bytes. – Daniel Fischer
Related
I have a problem on my code which return the n last line from file, when I enter 8 it return 4 lines, 6 -> 3 last lines, 4 -> 2 last line and so on.
this is my code:
FILE* file;
int count = 0;
int pos;
char s[1000];
int numberOfline;
printf("Enter the number of last line to return: ");
scanf_s("%d", &numberOfline);
file = fopen("lines.txt", "rt+");
if (file == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
fseek(file, 0, SEEK_END);
pos = ftell(file);
while (pos) {
fseek(file, --pos, SEEK_SET);
if (fgetc(file) == '\n') {
if (count++ == numberOfline) break;
}
}
while (fgets(s, sizeof(s), file) != NULL) {
printf("%s", s);
}
fclose(file);
what is the problem and why he accept only even number and return the half of it, and how can i fix that?
Undefined behavior
fseek() on a text file is well defined for the beginning and positions from previous ftell().
OP is attempting an fseek() from every file position.
OP's woe of double counting is that an fget() sees "\r\n: and "\n: both as '\n.
I'm currently working on making a tiny computer in C for a programming assignment and I'm stuck on one part.
I'm stuck on how to correctly ignore comments in a text file that I'm reading in. (Example of file input below).
Input File
5 5 //IN 5
6 7 //OUT 7
3 0 //STORE 0
5 5 //IN 5
6 7 //OUT 7
3 1 //STORE 1
1 0 //LOAD 0
4 1 //SUB 1
3 0 //STORE 0
6 7 //OUT 7
1 1 //LOAD 1
6 7 //OUT 7
7 0 //END
The first input on each new line is an operation, the 2nd input being an address. I am planning to have a switch statement for each op and then calling the appropriate function. This is my current layout for reading in the file:
//file handling
int c;
FILE * file;
file = fopen(name, "r");
if (file){
printf("Run.\n");
while ((c = getc(file)) != EOF){
op = c;
switch (op){
case 5:
print("Inside case 5\n");
}
}
fclose(file);
}
How can I ignore the // on each line and skip to the next line in the file?
Call fgets to get a full line:
fgets(buffer, 100, file);
and then extract the two numbers from the line:
sscanf(buffer, "%d%d", &instruction, &address);
how to correctly ignore comments in a text file that I'm reading in
How can I ignore the // on each line and skip to the next line in the file?
Read the line using fgets()
char buf[80];
if (fgets(buf, sizeof buf, file)) {
Look for the // with strstr() #Steve Summit and lop off the string at that point.
char *slash_slash = strstr(buf, "//");
if (slash_slash) {
*slash_slash = '\0';
}
Continue processing the line as desired.
...
}
By using fgets and strtok you can read line by line and split the string acording to the // delimiter. Here's an example (it is not fully checked, but it's the main idea):
FILE *f = fopen("file.txt", "r");
if (f== NULL)
{
printf("opening file failed\n");
return 1;
}
char buf[256] = { 0 };
while (fgets(buf, 256, f))
{
char *s = strtok(buf, "//");
if (s == NULL)
{
printf("s == NULL\n");
}
else
{
printf("%s\n", s);
}
memset(buf, 0, 256);
}
fclose(f);
EDIT: I just realized that this is not exactly what you were looking for. However, you can still use it in order to first ignore the comment, and then break the given string into operation and address, or whatever that is...
So basically the text file would look like this
Starting Cash: 1500
Turn Limit (-1 for no turn limit): 10
Number of Players Left To End Game: 1
Property Set Multiplier: 2
Number of Houses Before Hotels: 4
Must Build Houses Evenly: Yes
Put Money In Free Parking: No
Auction Properties: No
Salary Multiplier For Landing On Go: 1
All I need from the file is basically anything after ":"
I'm just confused how to only read anything after a ":"?
This is what I have right now. I just can't seem to think of a way to only scan for the numbers/yesorno.
void readRules(char*file_name)
{
Rules r;
FILE *file = NULL;
file = fopen(file_name, "r");
if (file == NULL) {
printf("Could not open %s\n", file_name);
return;
}
char c=fgetc(file);
fscanf(file, "%c", &c);
while (!feof(file))
{
fscanf(file, "%c", &c);
if(c==':')
{
r.startCash=c;
}
}
printf("There are %c word(s).\n", r.startCash);
fclose(file);
}
Thank you.
This program will read integers following a colon in each line of the file given. I imagine this is appropriate? You also have some strings after colons. If you want to read those, you can try scanning for a string "%s" and testing if the function returns nonzero (for at least one format pattern matched).
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 1000
void readRules (const char *filename) {
FILE *fp;
char *lp, line[MAXLINE];
int n;
// Return early if file cannot be opened.
if ((fp = fopen(filename, "r")) == NULL) {
fprintf(stderr, "Error: Couldn't open \"%s\"!\n", filename);
return;
}
// Use fgets to read consecutive lines. Returns NULL on error or EOF.
while (fgets(line, MAXLINE, fp) != NULL) {
// Read until newline is hit or buffer size exceeded.
for (lp = line; *lp != '\n' && (lp - line) < MAXLINE; lp++) {
// If encounter colon and sccanf reads at least 1 integer..
if (*lp == ':' && sscanf(lp + 1, "%d", &n) == 1) {
fprintf(stdout, "%d\n", n);
break;
}
}
}
// Clean up.
fclose(fp);
}
int main (int argc, const char *argv[]) {
readRules("test.txt");
return 0;
}
When run with your example input, it produces:
1500
10
1
2
4
1
Supposed to swap every two lines in a file until just one line remains or all lines are exhausted. I don't want to use another file in doing so.
Here's my code:
#include <stdio.h>
int main() {
FILE *fp = fopen("this.txt", "r+");
int i = 0;
char line1[100], line2[100];
fpos_t pos;
fgetpos(fp, &pos);
//to get the total line count
while (!feof(fp)) {
fgets(line1, 100, fp);
i++;
}
i /= 2; //no. of times to run the loop
rewind(fp);
while (i-- > 0) { //trying to use !feof(fp) condition to break the loop results in an infinite loop
fgets(line1, 100, fp);
fgets(line2, 100, fp);
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fgetpos(fp, &pos);
}
fclose(fp);
return 0;
}
content in this.txt:
aaa
b
cc
ddd
ee
ffff
gg
hhhh
i
jj
content after running the program
b
aaa
ddd
cc
ddd
c
c
c
i
jj
I've even tried using fseek in place of fgetpos just to get the same wrong result.
From what I figured, after the second while loop has run two times (i.e the first four lines have been processed), the cursor is rightfully at 17th byte where it is supposed to be (as returned by the call to ftell(fp)) and even the file contents after the 4th line are unchanged and somehow for some reason when fgets is called when the loop is running for the third time, the contents read into arrays line1 and line2 are "c\n" and "ddd\n" respectively.
AGAIN, I don't want to use another file to accomplish this, I just need to figure out what exactly is going wrong behind the screen
Any leads would be appreciated. Thank you.
There are multiple problems in your code:
You do not check if fopen() succeeds, risking undefined behavior.
The loop to determine the total number of lines is incorrect.Learn why here: Why is “while ( !feof (file) )” always wrong?
You do not actually need to compute the total number of lines.
You should call fflush() to write the contents back to the file before changing from writing back to reading.
The C Standard specifies this restriction for files open in update mode:
7.21.5.3 The fopen function
[...] output shall 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 shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.
This explains why just reading the file position after writing the lines in reverse order causes problems. Calling fflush() should solve this issue.
Here is a corrected version:
#include <stdio.h>
int main(void) {
FILE *fp;
char line1[100], line2[100];
fpos_t pos;
fp = fopen("this.txt", "r+");
if (fp == NULL) {
fprintf(stderr, "cannot open this.txt\n");
return 1;
}
while (fgetpos(fp, &pos) == 0 &&
fgets(line1, sizeof line1, fp) != NULL &&
fgets(line2, sizeof line2, fp) != NULL) {
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fflush(fp);
}
fclose(fp);
return 0;
}
The buffer may not necessarily be flushed when changing the current position of the file. So it must be explicitly flushed.
E.g Use fflush(fp);
Change
fputs(line2,fp);
fputs(line1,fp);
to
fputs(line2,fp);
fputs(line1,fp);
fflush(fp);
Why not use two file pointers, both pointing to the same file, one to read and one to write? No need to keep track of the file position, no need to seek around, no need to flush then.
This approach spares you a lot of complicated stuff. Those unnecessary efforts are better invested in some sophisticated error checking/logging like below ;-):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
int result = EXIT_SUCCESS;
size_t blocks = 0;
int l1_done = 0;
int l2_done = 0;
FILE *fpin = fopen("this.txt", "r");
FILE *fpout = fopen("this.txt", "r+");
if (NULL == fpin)
{
result = EXIT_FAILURE;
perror("fopen() to for reading failed");
}
if (NULL == fpout)
{
result = EXIT_FAILURE;
perror("fopen() for writing failed");
}
while (EXIT_SUCCESS == result && !l1_done && !l2_done)
{
result = EXIT_FAILURE;
char line1[100];
char line2[100];
if ((l1_done = (NULL == fgets(line1, sizeof line1, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks);
break;
}
}
if ((l2_done = (NULL == fgets(line2, sizeof line2, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks + 1);
break;
}
}
{
size_t len = strlen(line1);
if (((sizeof line1 - 1) == len) && ('\n' != line1[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks);
break;
}
}
{
size_t len = strlen(line2);
if (((sizeof line2 - 1) == len) && ('\n' != line2[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks + 1);
break;
}
}
if (!l2_done)
{
if (EOF == fputs(line2, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks + 1, 2*blocks);
break;
}
}
if (!l1_done)
{
if (EOF == fputs(line1, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks, 2*blocks + 1);
break;
}
}
++blocks;
result = EXIT_SUCCESS;
}
if (EXIT_SUCCESS == result && !ll_done && l2_done)
{
fprintf(stderr, "Odd number of lines.\n");
}
fclose(fpin); /* Perhaps add error checking here as well ... */
fclose(fpout); /* Perhaps add error checking here as well ... */
return result;
}
I have made a program which handles and stores records of movies in a library. This is how my library looks like when I print it out to a file.
So basicly my problem is to read this file and save those columns in my struct of variables and dynamically increase the size of the struct for every entry.
Right now I have a while loop reading line by line into a buffert and I am then trying to scan the values from the buffert.
I know the format of the spacings in between the columns if that helps.(No it's not tabs, would that help?)
Else i thought about once it finds "two spaces" it could parse onto the next one...
What I'm looking for is something like this:
("%s %d %d %d %s %d", name, &id, &qty, &price, genre, &year)
This is how the textfile looks like: "test.txt" (UPDATED version below)
-------------------------------------------------------------------------------
NAME ID QTY PRICE GENRE YEAR
-------------------------------------------------------------------------------
THE SHAWSHANK REDEMPTION 1 25 99 Crime 1994
THE GODFATHER 2 65 199 Crime 1972
PULP FICTION 3 265 99 Drama 1994
THE LORD OF THE RINGS 4 1024 199 Action 2003
THE DARK KNIGHT 5 99 99 Action 2008
And this is how my code looks like:
void read_from_file(struct movies *movie)
{
FILE *fp;
char buffer[1024];
int line_num = 0;
int index = 0;
fp = fopen("test.txt", "r");
if ( fp == NULL )
{
printf("Error opening file!\n");
exit(1);
}
fgets(buffer, 1024, fp); fgets(buffer, 1024, fp); fgets(buffer, 1024, fp); // Skip 3 first lines (header)
while(fgets(buffer, 1024, fp) != NULL) // read one line to buffer at a time
{
printf("%s", buffer); //DEBUG
// Trying here to read only the names which i know should be no longer than 40chars. first row goes well, then it's messed up
sscanf(buffer, "%40[^\0]" , movie[index].name);
index++;
}
fclose(fp);
getch();
}
Update: I changed the format of the storage file to the following:
THE SHAWSHANK REDEMPTION,1,25,99,Crime,1994
THE GODFATHER,2,75,199,Crime,1972
PULP FICTION,3,512,99,Drama,2000
THE LORD OF THE RINGS,4,1024,199,Action,2003
THE DARK KNIGHT,5,99,99,Action,2008
The main problem is that there is no single char delimiter. So process the first 45 char;
while(fgets(buffer, sizeof buffer, fp) != NULL) {
printf("%s", buffer); //DEBUG
if (strlen(buf < 80)) {
handle_short_line_error();
}
size_t len;
for (len = 45; len > 0; len--) {
if (!isspace(buf[len-1])) {
break;
}
}
if (!IsAGoodLength(len)) {
handle_format_error();
}
memcpy(movie[index].name, buf, len);
movie[index].name[len] = '\0';
if (5 != sscanf(&buffer[45], "%d%d%d%9s%d", &id, &qty, &price, genre, &year)) {
handle_format_error();
}
// Use other fields scanned
index++;
}