I'm following a book on c, and I come to some code that reads a file with 3 lines of text.
#include <stdio.h>
int main (int argc, const char * argv[]) {
FILE *fp;
int c;
fp = fopen( "../../My Data File", "r" );
if ( NULL == fp ) {
printf( "Error opening ../My Data File" );
} else {
while ( (c = fgetc( fp )) != EOF )
putchar ( c );
fclose( fp );
}
return 0;
}
I tried to modify it, to detect each line and print the current line number by making these modifications.
int line = 1;
while ( (c = fgetc( fp )) != EOF ){
if (c == '\n'){
printf(" LINE %d", line);
putchar( c );
line++;
}
else {
putchar ( c );
}
}
But it failed to print the line #, till I changed the type of the variable c to a char. Is there a way to check for a newline while still using c as an int?
What is the proper way to check for a newline?
Your code prints line numbers at the end of a line, right before printing the '\n', because of the way you have written the loop. Otherwise, your code should work.
If you want your code to print the line numbers at the beginning, you can do something like (untested):
int line_num_printed = 0; /* indicating if we printed a line number */
int line = 1;
while ((c = fgetc(fp)) != EOF) {
if (!line_num_printed) {
printf("LINE %d: ", line);
line_num_printed = 1;
}
putchar(c);
if (c == '\n'){
line++;
line_num_printed = 0;
}
}
If there is something else that "doesn't work", you should post complete code and tell us what doesn't work.
Edit: The proper way to check a character for a newline is to test against '\n'. If the character came from a file, you should also make sure you open the file in text mode, i.e., without a b in the second argument to fopen().
Also, you want c to be of type int, not char. This is because in C, EOF is a small negative number, and if char is unsigned, comparing it against a negative number convert the value of EOF to a positive value (equal to EOF + UCHAR_MAX + 1 most likely). Therefore, you should not change c to char type. If you do, the comparison c != EOF might be false even when fgetc() returns EOF.
Usually the integer code for a new line ('\n') is 13. So you could do ( if (c == 13) ), but also note that windows files use 2 characters to define a new line '\r' and '\n'. The integer character for '\r' is 10. But basically yes you can keep 'c' as an int and just compare against 13.
Related
The exact problem that I am having is that we were assigned to make a program that had 2 command line arguments, both being text files. The code that I have for arg[1] works fine, it reads in the text file and stores it into an array. Once it is stored into the array called key it goes through a loop that only leaves alpha characters and makes uppercase change to lowercase. Once again this works fine when i test it and print out the final array called key. When I use the same code for arg[2] the first loop (while(!feof(file2))) does not even copy the contents of the other text file into the array called plain correctly. It copies all the content but adds ▒ at the end when i print out the plain array to test to see if I have all the characters in there before running it through the loop that only leaves alphacharacters in it. If I switch the order of the files when I enter them in the terminal then the second file works fine with the arg[1] code but then the other file does not work with the arg[2] code. I'm using mobaxterm so I enter it like "./a.out k1.txt p1.txt" without the quotations of course. I also commented out the code that strips the nonalpha characters in arg[2] just to try and figure out why the while loop before it is not storing the file contents correctly.
Here are the contents of the text files
k1.txt (instead of a space imagine it goes to the next line):
bbbbbbbbb
bbbbbbbbb
bbbbbbbbb
bbbbbbbbb
bbbbbbbbb
bbbbbbbbb
bbbbbbbbb
bbbbbbbbb
p1.txt:
"If you find that you're spending almost all your time on theory, start turning some attention to practical things; it will improve your theories. If you find that you're spending almost all your time on practice, start turning some attention to theoretical things; it will improve your practice." - Donald Knuth
This is an encryption assignment by the way and k1 is the key and p1 is the plain text.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char **argv) {
printf( "\ncommandline arguments including program name:\n\n");
int i;
for ( i = 0; i < argc; i++ ) {
printf( "argument %d: %s\n", i, argv[ i ] );
}
printf( "\n");
char* fname = argv[ 1 ];
FILE *file = fopen( fname, "r" );
char key[512];
int x,y, z=0;
if ( file == 0 )
{
printf( "Could not open file\n" );
} else {
printf( "File opened successfully\n" );
while(!feof(file))
{
fscanf(file, "%c", &key[z]);
z++;
}fscanf(file, "%c", &key[z]);
for(x=0; key[x] != '\0'; x++)
{
while(!((key[x] >= 'a' && key[x] <= 'z') || (key[x] >= 'A' && key[x] <= 'Z') || key[x] == '\0'))
{
for(y=x; key[y] != '\0'; ++y)
{
key[y]=key[y+1];
}
key[y] = '\0';
}
key[x] = tolower(key[x]);
}
printf("Key text:\n%s\n", key);
fclose( file );
}
char* fname2 = argv[ 2 ];
FILE *file2 = fopen( fname2, "r" );
char plain[512];
int j,k, l=0;
if ( file2 == 0)
{
printf("Could not open file\n");
}else {
printf("File opened successfully\n");
while(!feof(file2))
{
fscanf(file2, "%c", &plain[l]);
l++;
}fscanf(file2, "%c", &plain[l]);
/* for(j=0; key[j] != '\0'; j++)
{
while(!((plain[j] >= 'a' && plain[j] <= 'z') || (plain[j] >= 'A' && plain[j] <= 'Z') || plain[j] == '\0'))
{
for(k=j; plain[k] != '\0'; ++k)
{
plain[k]=plain[k+1];
}
plain[k] = '\0';
}
plain[j] = tolower(plain[j]);
}*/
printf("Plain text:\n%s\n", plain);
fclose(file2);
}
return 0;
}
feof
Check end-of-file indicator
Checks whether the end-of-File indicator associated with stream is set, returning a value different from zero if it is.
This indicator is generally set by a previous operation on the stream that attempted to read at or past the end-of-file.
Notice that stream's internal position indicator may point to the end-of-file for the next operation, but still, the end-of-file indicator may not be set until an operation attempts to read at that point.
[emphasis mine]
Now, lets see the how this loop will work:
while(!feof(file))
{
fscanf(file, "%c", &key[z]);
z++;
}fscanf(file, "%c", &key[z]);
Assume that fscanf() has read the last character of file. After this, the stream internal position indicator is pointing to EOF but feof() will return 0 because there is no read operation attempted on the stream which will set the end-of-file indicator. Hence the control go inside the loop and fscan() will attempt to read from file. Since EOF is reached, fscan() will set the end-of-file indicator. Now the EOF is set, so the feof() will return non-zero value and loop will end. Hence, the way you are using feof(), you will always have this extra iteration of while loop.
After encountering EOF, you are still trying to read from stream file:
fscanf(file, "%c", &key[z]);
Here, also fscanf() will return the EOF because there is nothing remain to read from stream file. This statement is meaning less.
In C, strings are actually one-dimensional array of characters terminated by a null character \0. fscanf() does not automatically append null character at the end when you read from stream using %c format specifier. So, the character array key and plain does not have null character at the end of characters read and if you try to print them using %s, you may get some junk character's in the output.
You can do:
while ((ret = fscanf(file, "%c", &key[z])) != EOF) {
z++;
}
key[z] = '\0';
You can also read the string of characters from file using %s format specifier, like this:
fscanf(file, "%511s", key);
With %s format specifier you dont need loop and a terminating null character is automatically added at the end of the stored sequence.
It is good to add check for max character modifier that is 1 less than the length of the input buffer (which is 511, in your case).
Alternatively, you can also use fgets() to read from file.
Check this:
while ( !feof (file) ) is always wrong?
Reading from file using fgets
a new empty file:
touch /file.txt
read. print.
fp = fopen("/file.txt", "r");
char text[1000];
int i=0;
while(!feof(fp)){
text[i++] = getc(fp);
}
text[i]='\0';
printf("%s\n", text);
result:
ÿ
EXTRA INFO : if file.txt had many lines.. it would have appended that strange character at the very bottom of it. so perhaps it is not something that happens on every "while loop".
If you're using ISO 8859-15 or 8859-1 code set, the ÿ (LATIN SMALL LETTER Y WITH DIAERESIS, U+00FF in Unicode) has code 25510 or 0xFF. When you store EOF in the array, it gets converted to ÿ.
Don't store EOF in a char. And remember that getchar() returns an int, not a char. It has to be able to return every value that can be stored in an unsigned char, plus EOF which is negative (usually but not necessarily -1).
And, as noted in the comments, while (!feof(file)) is always wrong. This is just another reason why.
This code is fixed, more or less. It really should report an error if it fails to open the file. Note that it also ensures you don't overflow the buffer.
FILE *fp = fopen("/file.txt", "r");
if (fp != 0)
{
char text[1000];
int i=0;
int c;
while ((c = getc(fp)) != EOF && i < sizeof(text)-1)
text[i++] = c;
text[i]='\0';
printf("%s\n", text);
fclose(fp);
}
See also while ((c = getc(file)) != EOF) loop won't stop executing.
The ÿ is the byte 255 in your codepage, which is the constant EOF coerced into a char. Instead of using feof, you must store the return value of getc into an int, then compare it against EOF, here's an easy-to-read example (notice that you'd have to have bounds-checking too):
while (1) {
int c = getc(fp);
if (c == EOF) {
break;
}
text[i++] = c;
}
I want program count lines in text file by function. It used to work ,but it always return 0 now.
What am I doing wrong?
#include <stdio.h>
int couLineF(FILE* fp){ //count lines in file
int count = 0,ch;
while((ch = fgetc(fp)) != EOF){
if(ch == (int)"\n" ) count++;
}
rewind(fp);
return count;
}
int main(){
FILE *fp = fopen("book.txt","r");
int lines;
if(fp){
lines = couLineF(fp);
printf("number of lines is : %d",lines);
}
return 0;
}
Another question
Are there any other ways to get number of lines in text file?
Your problem is here:
if(ch == (int)"\n" )
You are casting the address of "\n", a string literal, into an int and comparing it with ch. This doesn't make any sense.
Replace it with
if(ch == '\n' )
to fix it. This checks if ch is a newline character.(Use single quotes(') for denoting a character and double quotes(") for a string)
Other problems are:
Not closing the file using fclose if fopen was successful.
Your program won't count the last line if it doesn't end with \n.
There is absolutely no reason to use rewind(fp) as you never use the FILE pointer again.
I am trying to get fgetc to read through a file and skip from a certain indicator until a new line. This seems like a simple question, but I can't find any documentation on it.
Here is an example of my question:
read this in ; skip from semicolon on to new line
My best guess at a solution would be to read in the entire file, and for each line use strtok to skip from ; to the end of the line. Obviously this is horrible inefficient. Any ideas?
*I need to use fgetc or something like fgetc that will parse the file character by character
Easiest thing to do is read the entire line in, then truncate if there a ;.
char buffer[1024], * p ;
if ( fgets(buffer, sizeof(buffer), fin) )
{
if (( p= strchr( buffer, ';' ))) { *p = '\0' ; } // chop off ; and anything after
for ( p= buffer ; ( * p ) ; ++ p )
{
char c= * p ;
// do what you want with each character c here.
}
}
When you do the read, buffer will initially contain:
"read this in ; skip from semicolon on to new line\n\0"
After you find the ; in the line and stick a '\0' there, the buffer looks like:
"read this in \0 skip from semicolon on to new line\n\0"
So the for loop starts at r and stops at the first \0.
//Function of compatible fgets to read up to the character specified by a delimiter.
//However file stream keep going until to newline.
//s : buffer, n : buffer size
char *fgets_delim(char *s, int n, FILE *fp, char delimiter){
int i, ch=fgetc(fp);
if(EOF==ch)return NULL;
for(i=0;i<n-1;++i, ch=fgetc(fp)){
s[i] = ch;
if(ch == '\n'){
s[i+1]='\0';
break;
}
if(ch == EOF){
s[i]='\0';
break;
}
if(ch == delimiter){
s[i]='\0';//s[i]='\n';s[i+1]='\0'
while('\n'!=(ch = fgetc(fp)) && EOF !=ch);//skip
break;
}
}
if(i==n-1)
s[i] = '\0';
return s;
}
Given a requirement to use fgetc(), then you are probably supposed to echo everything up to the first semicolon on the line, and suppress everything from the semicolon to the end of the line. I note in passing that getc() is functionally equivalent to fgetc() and since this code is about to read from standard input and write to standard output, it would be reasonable to use getchar() and putchar(). But rules are rules...
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
int c;
bool read_semicolon = false;
while ((c = fgetc(stdin)) != EOF)
{
if (c == '\n')
{
putchar(c);
read_semicolon = false;
}
else if (c == ';')
read_semicolon = true;
else if (read_semicolon == false)
putchar(c);
/* else suppressed because read_semicolon is true */
}
return 0;
}
If you don't have C99 and <stdbool.h>, you can use int, 0 and 1 in place of bool, false and true respectively. You can use else if (!read_semi_colon) if you prefer.
I am reading a file of integers. I want to save integers from each line to a new array. For this I want to detect a new line of a file. If anybody knows this please help.
The file to be read is as follows
1 2 4 5 6
7 3 2 5
8 3
9 7 6 2
Why not use fgets() to get one line at a time from the file? You can then use sscanf() instead of fscanf() to extract the integers.
#include <stdio.h>
int main ( int argc, char **argv ) {
FILE *fp = fopen ( "d:\\abc.txt", "r");
char line[1024];
char ch = getc ( fp );
int index = 0;
while ( ch != EOF ) {
if ( ch != '\n'){
line[index++] = ch;
}else {
line[index] = '\0';
index = 0;
printf ( "%s\n", line );
}
ch = getc ( fp );
}
fclose ( fp );
return 0;
}
Use fgets() to read a single line of input at a time. Then use strtol() to parse off an integer, using its "end pointer" feature to figure out where to try again, and loop until you've parsed all the values.
Using getc() for this action is fine but do not forget that getc() returns type is int. Retype to char "works" but you can have a problem with non strict-ASCII input file because EOF = -1 = 0xFF after retype to char (on most C compilers), i.e. 0xFF characters are detected as EOF.
#include<stdio.h>
void main()
{
FILE *p;
int n;
int s=0;
int a[10];
p=fopen("C:\\numb.txt","r");
if(p!=NULL)
printf("file opened");
while((n=getc(p))!=EOF)
{ if(n!=NULL && n!='\n')
{
printf("\n%d",n);
a[s]=n;
++s;
}
}
fclose(p);
getchar();
}
I'm not sure of the int to char and vice versa conversion but program works for non zero numbers. I tried on visual basic.
If you use reading char by char then recognizing whitespace with '32' and 'enter' by '13' and/or '10'