I'm trying to print lines which starts from given letter to second file but it prints only 1 line and then stops, even if there are more lines which starts with given letter. How to fix it ?
#include <stdio.h>
#include <string.h>
int main()
{
FILE* f = fopen("story.txt","r");
char usr;
printf("enter letter: ");
scanf(" %c",&usr);
FILE* f2=fopen("letter.txt","a+");
char buffer[255];
while(fscanf(f, "%[^\n]s", buffer)==1)
if (*buffer == usr)
fprintf(f2, "%s\n", buffer);
return 0;
}
The second time through the loop, fscanf(f, "%[^\n]s", buffer) fails to scan anything because the previous call left the \n character in the buffer. This can't get past that.
Use fgets() instead of fscanf() to read a whole line.
char buffer[255];
while(fgets(buffer, sizeof buffer, f))
if (buffer[0] == usr)
fprintf(f2, "%s", buffer);
I would not use fscanf to read line of text.
//fi - input file
//fo - output file
int copyLines(FILE *fi, FILE *fo, char c)
{
char line[256];
if(fi && fo)
{
while(fgets(line, sizeof(line), fi))
{
if(*line = c)
if(fputs(line, fo) == EOF) return EOF;
}
}
return 0;
}
For starters the format string in the call of fscanf is incorrect
while(fscanf(f, "%[^\n]s", buffer)==1)
^^^
At least you should remove the letter s.
Another problem is that after such a call of fscanf the new line character '\n' is not read. So the next call of fscanf reads an empty string.
It is better to use another C function fgtes. But you need to use it with a caution.
In general a string stored in the input file can be greater than the size of the array buffer.
That means that you need to read some strings in the input file using more than one call of fgets. Otherwise the output file will be formed incorrectly.
The loop can look the following way
int success = 1;
do
{
success = fgets( buffer, sizeof( buffer ), f ) != NULL;
if ( success )
{
int target = *buffer == usr;
if ( target ) fprintf( f2, "%s", buffer );
while ( success && !strchr( buffer, '\n' ) )
{
success = fgets( buffer, sizeof( buffer ), f ) != NULL;
if ( success && target ) fprintf( f2, "%s", buffer );
}
}
} while ( success );
Related
I am writing a text file parser in C.
I would like to read each line of a text file using fgets, except for the very last line, which I would like to skip.
Also, there is no telling how many characters will be in the file or in the last line, but assume my parser only cares about the first LINEMAXLEN characters in each line.
Currently, the only way I can think to do this is by running two loops, something like the following:
char line[ LINEMAXLEN+1u ];
unsigned int nlines;
unsigned int i;
nlines = 0u;
while ( fgets (line, LINEMAXLEN, file) != NULL )
nlines += 1u;
i = 0u;
while ( fgets (line, LINEMAXLEN, file) != NULL ) {
if ( i >= nlines - 1u )
break;
//...parse the line
i += 1u;
}
But surely, there's got to be a smarter way to do it in only one loop, no?
Instead of using two loops, it would be more efficient to always read two lines in advance and to only process a line once the next line has been sucessfully read. That way, the last line will not be processed.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define LINEMAXLEN 30
//forward function declarations
void process_line( const char *line );
bool read_start_of_line_and_discard_rest( char buffer[], int buffer_size, FILE *fp );
int main( void )
{
FILE *fp;
char lines[2][LINEMAXLEN];
//This index specifies which index in the array "lines"
//represents the newest line. The other index is the
//index of the previous line.
int newest_index = 0;
//attempt to open file
fp = fopen( "input.txt", "r" );
if ( fp == NULL )
{
fprintf( stderr, "Error opening file!\n" );
exit( EXIT_FAILURE );
}
//read first line
if ( !read_start_of_line_and_discard_rest( lines[newest_index], LINEMAXLEN, fp ) )
{
fprintf( stderr, "Error reading first line!\n" );
exit( EXIT_FAILURE );
}
//process one line per loop iteration
for (;;)
{
//swap the index, so that the newest line is now the
//previous line
newest_index = !newest_index;
//read the new line
if ( !read_start_of_line_and_discard_rest( lines[newest_index], LINEMAXLEN, fp ) )
{
//we have reached end-of-file, so we don't process the
//previous line, because that line is the last line
break;
}
//since reading in a new line succeeded, we can be sure that
//the previous line is not the last line, so we can process
//the previous line
//process the previous line
process_line( lines[!newest_index] );
}
//cleanup
fclose( fp );
}
//This function will process a line after it has been read
//from the input file. For now, it will only print it.
void process_line( const char *line )
{
printf( "Processing line: %s\n", line );
}
//This function will read exactly one line of input and remove the
//newline character, if it exists. On success, it will return true.
//If this function is unable to read any further lines due to
//end-of-file, it returns false. If it fails for any other reason, it
//will not return, but will print an error message and call "exit"
//instead.
//If the line is too long to fit in the buffer, it will discard
//the rest of the line and report success.
bool read_start_of_line_and_discard_rest( char buffer[], int buffer_size, FILE *fp )
{
char *p;
//attempt to read one line from the stream
if ( fgets( buffer, buffer_size, fp ) == NULL )
{
if ( ferror( fp ) )
{
fprintf( stderr, "Input error!\n" );
exit( EXIT_FAILURE );
}
return false;
}
//determine whether line was too long for input buffer
p = strchr( buffer, '\n' );
if ( p == NULL )
{
int c;
//discard remainder of line
do
{
c = getchar();
} while ( c != EOF && c != '\n' );
}
else
{
//remove newline character by overwriting it with a null
//character
*p = '\0';
}
return true;
}
For the input
This is line1.
This is line2 which has an additional length longer than 30 characters.
This is line3.
This is line4.
this program has the following output:
Processing line: This is line1.
Processing line: This is line2 which has an ad
Processing line: This is line3.
As you can see, all lines except the last line are being processed, and only the first LINEMAXLEN-1 (30-1 in my example) characters of each line are being processed/stored. The remaining characters are being discarded.
Only LINEMAXLEN-1 instead of LINEMAXLEN characters from each line are being processed/stored because one character is required to store the terminating null character.
This is quite simple to do in a single loop if we use alternating buffers [as others have mentioned].
In the loop below we read a line into the "current" buffer. If not the first line, we process the previous line in the "other" buffer.
By alternating the index into a buffer pool of two buffers, we avoid unnecessary copying.
This introduces a delay in the processing of the buffer. On the last iteration, the last line will be in the current buffer, but it will not be processed.
#define LINEMAXLEN 1000 // line length of buffer
#define NBUF 2 // number of buffers
char lines[NBUF][LINEMAXLEN]; // buffer pool
int previdx = -1; // index of bufs for _previous_ line
int curidx = 0; // index of bufs for _current_ line
char *buf; // pointer to line buffer to process
// read all lines into alternating line buffers
for (; fgets(lines[curidx],LINEMAXLEN,stdin) != NULL;
previdx = curidx, curidx = (curidx + 1) % NBUF) {
// process _previous_ line ...
if (previdx >= 0) {
buf = lines[previdx];
// process line ...
}
}
fgets() will not modify the buffer at all when it reaches EOF, so just read lines until fgets() returns NULL. The last line read will be retained:
#include <stdio.h>
int main( int argc, char **argv )
{
char line[ 1024 ];
FILE *f = fopen( argv[ 1 ], "r" );
if ( NULL == f )
{
return( 1 );
}
for ( ;; )
{
char *p = fgets( line, sizeof( line ), f );
if ( NULL == p )
{
break;
}
}
printf( "last line: %s\n", line );
return( 0 );
}
This relies on the required behavior of fgets():
The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned.
Robust code should check for errors with ferror().
Working that into your text processing is left as an exercise... ;-)
I have this code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE* ptr = fopen("data.txt","r");
char filename[100];
if (ptr==NULL)
{
printf("no such file.");
return 0;
}
char buf[100];
while (fscanf(ptr,"%*s %*s %s ",buf)==1)
printf("%s\n", buf);
printf("Create a file \n");
scanf("%s", filename);
fptr2 = fopen(filename, "w");
if (fptr2 == NULL)
{
printf("Cannot open file %s \n", filename);
exit(0);
}
c = fgetc(fptr1);
while (c != EOF)
{
fputc(c, fptr2);
c = fgetc(fptr1);
}
printf("\nContents copied to %s", filename);
fclose(fptr1);
fclose(fptr2);
return 0;
}
}
It coppies full content from one file to another. I need to copy only strings that have 5 as the last character (3 column)
For example Data.txt looks like that:
Alex 10B 4
John 10A 3
Kate 10C 5
In file that I will create during execution has to be coppied only Kate 10C 5 string. I've been trying for hours but I don't know how to do this. Can you help me?
In the end of each line there is a newline character, (\n) you can use that to read line by line and copy only the ones that you want:
FILE* dest = fopen("out.txt", "w+"); // supressed null check for simplicity
char buf[100];
char* char_to_find;
// parse line by line
while (fscanf(ptr, " %99[^\n]", buf) == 1){
char_to_find = buf;
// reach the end of the line
while(*char_to_find){
char_to_find++;
}
//move one back
char_to_find--;
// if it's 5 save, if not move on
if(*char_to_find == '5' && *(char_to_find - 1) == ' '){
fputs(buf, dest);
}
}
Live demo
The problem is that the function call
while (fscanf(ptr,"%*s %*s %s ",buf)==1)
consumes the input from the input stream, so that it is no longer available for copying. You are only saving the contents of the last field, but all other data is lost.
I suggest that you read one line at a time into a memory buffer, by calling the function fgets in a loop. That way, you will process one line of input per loop iteration, and will be saving the contents of the entire line.
In every loop iteration, you can use sscanf on this memory buffer to determine whether the third field has the desired value, and if it does, then you copy the entire line to the output file. Otherwise, you do nothing and proceed to the next line (i.e. the next loop iteration).
char line[100];
//process one line of input per loop iteration
while ( fgets( line, sizeof line, input_file ) != NULL )
{
char third_field[20];
if (
//third field was successfully extracted
sscanf( line, "%*s%*s%19s", third_field ) == 1
&&
//third field contains the string "5"
strcmp( third_field, "5" ) == 0
)
{
//copy entire line to output file
fputs( line, output_file );
}
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE* ptr = fopen("data.txt","r");
char filename[100];
if (ptr==NULL)
{
printf("no such file.");
return 0;
}
printf("Create a file \n");
scanf("%s", filename);
FILE* dest = fopen(filename, "w+"); // check for null like above
char buf[100];
char* char_to_find;
while (fscanf(ptr,"%99[^\n] ", buf) == 1){
char_to_find = buf;
while(*char_to_find != 0){
char_to_find++;
}
char_to_find--;
if(*char_to_find == '5'){
printf("%s\n", buf); // test ptint
fputs(buf, dest);
}
}
}
I have a file .txt with values of some variable. I need to read them to declarate my variables in main. What is wrong?
#include <stdio.h>
#define INPUT "input.txt"
int main (void){
FILE *open_file = fopen(INPUT, "r");
if (open_file == NULL){
puts("ERROR.");
} else {
puts("SUCCESS.");
}
char *buffer;
int size = ftell(open_file);
int read_file = fread(buffer,size,*open_file);
int Integer1, Integer2;
while (size != EOF){
sscanf("%d%d",Integer1, Integer2);
}
int close_file = fclose(open_file);
if (close_file == -1){
puts("Error in closing file.");
} else {
puts("Closing file: SUCCESS.");
}
return 0;
}
Whats is wrong? I have to read every line of my file. For example if my file contains:
1
2
My scanf should set:
Integer1 = 1;
Integer2 = 2;
One problem is that after the line
char *buffer;
the variable buffer does not point to any valid memory location. It is a wild pointer.
You can either create a fixed size array like this:
char buffer[100];
or you can create a dynamically sized memory buffer, like this:
if ( fseek( open_file, 0, SEEK_END ) != 0 )
DoSomethingToHandleError();
long size = ftell(open_file);
if ( fseek( open_file, 0, SEEK_SET ) != 0 )
DoSomethingToHandleError();
char *buffer = malloc( size );
if ( buffer == NULL )
DoSomethingToHandleError();
Depending on whether you used a fixed-size array or a dynamically allocated buffer, you should change the call to fread to one of the following:
fread( buffer, sizeof(buffer), open_file ); //for fixed size array
fread( buffer, size, open_file ); //for dynamically allocated buffer
Instead of using the function fread, you would probably be better off using the function fgets, especially because sscanf requires a null-terminated string as input, not binary data. The function fread will give you binary data that is not null-terminated, whereas fgets will give you a null-terminated string.
Also, change the line
sscanf("%d%d",Integer1, Integer2);
to
sscanf( buffer, "%d%d", &Integer1, &Integer2);
Before using Integer1 and Integer2 afterwards, you should also check the return value of sscanf to make sure that both integers were found in the string.
However, if you don't want to handle the memory management and reading in of the file yourself, you can simply use fscanf, like this:
if ( fscanf( open_file, "%d%d", &Integer1, &Integer2 ) != 2 )
DoSomethingToHandleError();
But this has the disadvantage that fscanf will just give you the first two numbers that it finds in the file, and won't perform much input validation. For example, fscanf won't enforce that the two numbers are on separate lines. See the following link for more information on the disadvantages of using fscanf:
A beginners' guide away from scanf()
If you use the function fgets as I suggested, then you will need two calls to fgets to read both lines of the file. This means that sscanf will be unable to find both integers in the same string. Therefore, if you use fgets, then you will have to change your program logic a bit, for example like this:
#define MAX_INTEGERS 2
char buffer[100];
int integers[MAX_INTEGERS];
int num_found = 0;
while ( fgets( buffer, sizeof(buffer), open_file ) != NULL )
{
int i;
if ( strchr( buffer, '\n' ) == NULL && !feof( openfile ) )
{
printf( "Error: Line size too long! Aborting.\n" );
break;
}
if ( sscanf( buffer, "%d", &i ) == 1 )
{
if ( num_found == MAX_INTEGERS )
{
printf(
"Error: Found too many integers in file! This "
"program only has room for storing %d integers. "
"Aborting.\n",
MAX_INTEGERS
);
break;
}
//add found integer to array and increment num_found
integers[num_found++] = i;
}
else
{
printf(
"Warning: Line without number encountered. This could "
"simply be a harmless empty line at the end of the "
"file, but could also indicate an error.\n"
);
}
}
printf( "Found the following integers:\n" );
for ( int i = 0; i < num_found; i++ )
{
printf( "%d\n", integers[i] );
}
Instead of using sscanf, you may want to use strtol, as that function allows you to perform stricter input validation.
If you don't want to use the function fgets, which reads input line by line, but really want to read the whole file at once using fread, you can do that, but you would have to add the terminating null character manually.
EDIT: Since you stated in the comments that you didn't want a loop and wanted to store the individual lines each into their own named variable, then you could use the following code instead:
//This function will assume that one number is stored per line, and
//write it to the memory location that "output" points to. Note that
//the return value does not specify the number found, but rather
//whether an error occurred or not. A return value of 0 means no error,
//nonzero means an error occurred.
int get_number( FILE *fp, int *output )
{
char buffer[100];
int i;
//read the next line into buffer and check for error
if ( fgets( buffer, sizeof(buffer), fp ) == NULL )
return -1;
//make sure line was not too long to fit into buffer
if ( strchr( buffer, '\n' ) == NULL && !feof( fp ) )
return -1;
//parse line and make sure that a number was found
if ( sscanf( buffer, "%d", &i ) != 1 )
return -1;
*output = i
return 0;
}
Now, in your function main, you can simply use the following code:
int error_occurred = 0;
if ( get_number( &Integer1 ) != 0 )
{
printf( "Error occured when reading the first integer.\n" );
error_occurred = 1;
}
if ( get_number( &Integer2 ) != 0 )
{
printf( "Error occured when reading the second integer.\n" );
error_occurred = 1;
}
if ( !error_occurred )
{
printf( "The value of Integer1 is: %d\n", Integer1 );
printf( "The value of Integer2 is: %d\n", Integer2 );
}
There are couple of problems in your code
fread(buffer,size,*open_file);, buffer is not allocated
A) you have to allocate memory using malloc or calloc if you use pointers and also free after you are done with it.
If you want to avoid the headache of allocating and freeing, you better use an array sufficient enough to store the contents.
fread takes 4 arguments
A) 4th argument is not FILE , its FILE* , use only open_file not *open_file and you have not used nmemb(number of members) parameter
On success, fread() return the number of items read, so check the return value to avoid errors.
ftell() returns the current offset , Otherwise, -1 is returned
A) you really don't need it, check the return value of fread to find out you have reached the EOF.
check the syntax of sscanf and example
OP's code failed to seek the end of the array, allocate space for buffer and used fread() incorrectly.
Correct version shown with some error checking.
//char *buffer;
//int size = ftell(open_file);
//int read_file = fread(buffer,size,*open_file);
// Seek and report, hopefully, the end position
if (fseek(open_file, 0, SEEK_END)) { fprintf(stderr, "fseek() failed.\n"); return EXIT_FAILURE;
long size = ftell(open_file);
if (size == -1) { fprintf(stderr, "ftell() failed.\n"); return EXIT_FAILURE; }
// Allocate memory and read
if ((unsigned long) size > SIZE_MAX) { fprintf(stderr, "size too big.\n"); return EXIT_FAILURE; }
char *buffer = malloc((size_t) size);
if (buffer == NULL) { fprintf(stderr, "malloc() failed.\n"); return EXIT_FAILURE; }
size_t length = fread(buffer, sizeof *buffer, size, open_file);
// Use `length` as the number of char read
// ...
// when done
free(buffer);
Other problems too.
// while (size != EOF){
// sscanf("%d%d",Integer1, Integer2);
// }
Maybe later, GTG.
I am trying to open a text file inputted by the user and read this text file but print the text file 60 characters at a time so I think in order for me to do this I need to store the text into an array and if it is over 60 characters on a line it should start on a new line. However, when I run the code below an error message shows up saying : C^#
#include <stdio.h>
#include <stdlib.h>
int main()
{
char arr[];
arr[count] = '\0';
char ch, file_name[25];
FILE *fp;
printf("Enter file name: \n");
gets(file_name);
fp = fopen(file_name,"r"); // reading the file
if( fp == NULL )
{
perror("This file does not exist\n"); //if file cannot be found print error message
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name);
while( ( ch = fgetc(fp) ) != EOF ){
arr[count] = ch;
count++;
printf("%s", arr);}
fclose(fp);
return 0;
}
char arr[]; is invalid.you need to specify a size.
array[count] = '\0'; : count is uninitialized.
gets(file_name); : gets is deprecated and dangerous.use another function like scanf.
Try the following code :
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ch , count = 0;
char file_name[25];
FILE *fp;
printf("Enter file name: \n");
scanf(" %24s",file_name);
fp = fopen(file_name,"r"); // reading the file
if( fp == NULL )
{
perror("This file does not exist\n"); //if file cannot be found print error message
exit(EXIT_FAILURE);
}
fseek(fp, 0L, SEEK_END);
long sz = ftell(fp);
fseek(fp, 0L, SEEK_SET);
char arr[sz];
while( ( ch = fgetc(fp) ) != EOF )
{
if( count < sz )
{
arr[count] = ch;
count++;
}
}
arr[sz] = '\0';
printf("The contents of %s file are :\n", file_name);
printf("arr : %s\n",arr);
fclose(fp);
return 0;
}
fgetc always reads the next character until EOF. use fgets() instead:
char *fgets(char *s, int size, FILE *stream)
fgets() reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s. Reading stops after an EOF
or a newline. If a newline is read, it is stored into the buffer. A
terminating null byte (aq\0aq) is stored after the last character in the
buffer.
1) your while loop is not properly delimited. In the absence of a { } block, the instruction arr[count] = ch; is the only repeted one.
I suppose it should include the incrementation of count too
while( ( ch = fgetc(fp) ) != EOF )
{
arr[count] = ch;
count++;
....
}
among other things (testing the counter etc).
2) there's no imperative need to read and store in an array. It is perfectly possible to transfer each character as soon as it is read, and add a line break when needed (new line, limit of 60 exceeded).
Three problems:
The variable count is not initialized, so it's value is indeterminate and using it will lead to undefined behavior.
The call printf(arr) treats arr as a string but arr is not terminated which again leads to undefined behavior.
The increment of count is outside the loop.
To solve the two first problems you must first initialize count to zero, then you must terminate the string after the loop:
arr[count] = '\0';
However, your printf(arr) call is still very problematic, what if the user enters some printf formatting codes, what will happen then? That's why you should never call printf with a user-provided input string, instead simply do
printf("%s", arr);
You also have a very big problem if the contents of the file you read is longer than 59 characters, and then you will overflow the array.
A very simple c program which reads from a file and outputs on terminal.
What is the difference between result and line here?
For example if I print (result) or (line) inside the while loop the output of both is same.
printf("%s", line);
printf("%s", result);
but inside the condition of while loop if I replace
while(result !=NULL)
with
while(line != NULL)
it does not stop.
source code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
const int LINE_SIZE = 1000;
FILE *infile;
char *result;
char line[LINE_SIZE];
infile = fopen("in.txt", "r");
result = fgets(line, LINE_SIZE, infile);
while(result != NULL)
{
//printf("%s", line);
printf("%s", result);
result = fgets(line, LINE_SIZE, infile);
}
return 0;
}
while(line != NULL)
line is an array. If you just write line, it will always return a pointer to its first element (here, a character). Therefore the condition above will be always true.
The fgets function returns your data pointer on success, NULL on failure (e.g when the end of file has been reached and it couldn't read any character).
fgets On success, the function returns string.
If end of file (EOF) is found, the pointer returned is a null pointer (so your pointer result will become null) and the contents of string remain unchanged ( in your case line remains unchanged).
Hence
while(line != NULL)
will continue to execute since line remains unchanged.
char line[LINE_SIZE], line is an array name, it's a constant, never to be null, if you write line = fgets(line, LINE_SIZE, infile);, it will tell an error! fgets() changes line[0], line[1], line[2]... not line.