I'm writing a function that reads the number of lines in the given line. Some text files may not end with a newline character.
int line_count(const char *filename)
{
int ch = 0;
int count = 0;
FILE *fileHandle;
if ((fileHandle = fopen(filename, "r")) == NULL) {
return -1;
}
do {
ch = fgetc(fileHandle);
if ( ch == '\n')
count++;
} while (ch != EOF);
fclose(fileHandle);
return count;
}
Now the function doesn't count the number of lines correctly, but I can't figure out where the problem is. I would be really grateful for your help.
Here is another option (other than keeping track of last character before EOF).
int ch;
int charsOnCurrentLine = 0;
while ((ch = fgetc(fileHandle)) != EOF) {
if (ch == '\n') {
count++;
charsOnCurrentLine = 0;
} else {
charsOnCurrentLine++;
}
}
if (charsOnCurrentLine > 0) {
count++;
}
fgets() reads till newline character or till the buffer is full
char buf[200];
while(fgets(buf,sizeof(buf),fileHandle) != NULL)
{
count++;
}
fgetc() is an issue here because you encounter EOF first and exit your do while loop and never encounter a \n character so count remains untouched for the last line in your file.If it happens to be there is a single line in your file that the count will be 0
Related
the code isn't counting correctly as all the numbers in the output are lower than they should be. I can't find any reason as to why I'm getting these numbers as I still don't understand c very well.
if I read in a file with 25 lines and 20 lines excluding white space and comments the output from my code will be 10 and -13 and I'm not sure why. Any help is greatly appreciated.
#include <stdio.h>
#include <string.h>
#define LINE_LENGTH 1000
int main(int argc, char **argv)
{
FILE *input_file = fopen("cstest.c", "r");
char line [LINE_LENGTH];
//while loop to get
while(fgets(line,LINE_LENGTH,input_file)!=NULL)
{
int ch=0;//ch is the cast
int lines=0;
if (input_file == NULL)
return 0;
while(fgetc(input_file)!= EOF)
{
ch = fgetc(input_file);
if(ch == '\n')
{
lines++;
}
}//end while
printf("lines: %d\n",lines);
}//end while loop
rewind(input_file);
while(fgets(line,LINE_LENGTH,input_file)!=NULL)
{
int ch=0;//ch is the cast
int lines=0;
char c;
if (input_file == NULL)
return 0;
while(fgetc(input_file)!= EOF)
{
ch = fgetc(input_file);
if(ch == '\n')
{
lines++;
}
if(ch == '\n' && ch + 1 == '\n' || ch == '\t')
{
lines--;
}
}//end while
printf("lines excluding white space and comments: %d\n",lines);
}//end while loop
fclose(input_file);
}
You only need one loop, fgets is reading the whole line for you. Barmar fixes it one way , I went the other way.
int lines = 0;
//while loop to get
while (fgets(line, LINE_LENGTH, input_file) != NULL)
{
int ch = 0;//ch is the cast
lines++;
//while (fgetc(input_file) != EOF)
//{
// ch = fgetc(input_file);
// if (ch == '\n')
// {
// lines++;
// }
//}//end while
printf("lines: %d\n", lines);
}//end while loop
You're skipping lots of things.
First, a line is read by this condition:
while(fgets(line,LINE_LENGTH,input_file)!=NULL)
This line won't be read by the later fgetc() calls. So you never count the newline at the end of this line.
Then in your next loop:
while(fgetc(input_file)!= EOF)
{
ch = fgetc(input_file);
if(ch == '\n')
{
lines++;
}
}//end while
you only check every other character to see if it's a newline. You read one character in the while() condition and just check if it's EOF. Then you read another character in the loop body and test if it's `\n'.
You don't need the nested loops or multiple calls to fgetc().
int ch;
while((ch = fgetc(input_file))!= EOF)
{
if(ch == '\n')
{
lines++;
}
}//end while
printf("lines: %d\n",lines);
So, I have a file like this:
12345 name1 18 500.000000
12345 name2 18 500.000000
And I wanted to read the file and each column go to a different variable. So I coded this:
void updateStruct() {
char c;
int lines, i;
accounts account[accMAX];
FILE *acc = fopen("acc.dat", "r+");
if (acc == NULL)
return;
for (c = getc(acc); c != EOF; c = getc(acc))
if (c == '\n')
lines += 1;
fscanf(acc, "%d %s %d %f", &account[0].number, account[0].name,
&account[0].age, &account[0].balance);
}
Somehow, the fscanf() doesn't attribute any value to the variables. What am I doing wrong?
The for loop leaves the file pointer at the end of the file. Call rewind to position the file pointer back at the start of the file before calling fscanf.
The for loop to compute the number of lines reads the whole file. fscanf() fails to convert anything and returns EOF.
You must rewind the position to the beginning of file with rewind(acc) or fseek(acc, 0L, SEEK_SET).
Note also that variable c must have type int for the EOF test to function correctly. Furthermore you should also count the last line that may or may not have a newline.
Here is a modified version:
accounts *updateStruct(int *countp) {
int c, last, lines, i;
FILE *acc = fopen("acc.dat", "r");
if (acc == NULL)
return NULL;
last = EOF;
while ((c = getc(acc)) != EOF) {
if (c == '\n')
lines += 1;
last = c;
}
if (last != '\n') { // last line did not have a newline
lines += 1;
}
rewind(acc);
accounts *account = calloc(lines, sizeof(account));
if (account == NULL) {
fclose(acc);
return NULL;
}
for (i = 0; i < count;) {
if (fscanf(acc, "%d %s %d %f", &account[i].number, account[i].name,
&account[i].age, &account[i].balance) != 4) {
// invalid line: skip to the newline
while ((c = getc(acc)) != EOF && c != '\n')
continue;
if (c == EOF)
break;
} else {
i++;
}
}
fclose(acc);
*countp = i;
return account;
}
it's about reading from a text file.
I have 3 command line arguments:
name of text file
delay time
how many line(s) want to read.
I want to read that text file by user specified line numbers till text file ends.
For example, the first time I read 5 lines and then the program asks how many line(s) do you want to read?. I would enter 7 it reads lines 5 to 12.
This would repeat until the end of the file.
#include <stdlib.h>
#include <stdio.h>
#include<time.h>
#include <string.h>
void delay(unsigned int mseconds)
{
clock_t goal = mseconds + clock();
while (goal > clock());
}
int countlines(const char *filename) {
FILE *fp = fopen(filename, "r");
int ch, last = '\n';
int lines = 0;
if (fp != NULL) {
while ((ch = fgetc(fp)) != EOF) {
if (ch == '\n')
lines++;
last = ch;
}
fclose(fp);
if (last != '\n')
lines++;
}
return lines;
}
int main(int argc, char *arg[])
{
FILE *ptDosya;
char ch;
ch = arg[1][0];
int s2;
int satir = 0;
int spaceCounter=0;
int lineCount, x = 0;
lineCount = atoi(arg[3]);
s2 = atoi(arg[2]);
printf("dosya %d satir icerir.\n", countlines(arg[1]));
ptDosya = fopen(arg[1], "r");
if (ptDosya != NULL)
{
while (ch != EOF&& x < lineCount)
{
ch = getc(ptDosya);
printf("%c", ch);
if (ch == '\n')
{
delay(s2);
x++;
}
}
while (x < countlines(arg[1]))
{
printf("satir sayisi giriniz:");
scanf("%d", &lineCount);
// i don't know what should i do in this loop..
x=x+lineCount;
}
}
else {
printf("dosya bulunamadi");
}
printf("\n\nend of file!\n");
fclose(ptDosya);
return 0;
system("PAUSE");
}
Your delay function uses a busy loop. This is unnecessarily expensive in terms of computing power. It would be very unwelcome to do this on a battery operated device. Furthermore, clock() does not necessarily return a number of milliseconds. The unit used by the clock() function can be determined using the CLOCKS_PER_SEC macro. Unfortunately, there is no portable way to specify a delay expressed in milliseconds, POSIX conformant systems have usleep() and nanosleep().
Your line counting function is incorrect: you count 1 line too many, unless the file ends without a trailing linefeed.
Here is an improved version:
int countlines(const char *filename) {
FILE *fp = fopen(filename, "r");
int ch, last = '\n';
int lines = 0;
if (fp != NULL) {
while ((ch = fgetc(fp)) != EOF) {
if (ch == '\n')
lines++;
last = ch;
}
fclose(fp);
if (last != '\n')
lines++;
}
return lines;
}
There are issues in the main() function too:
You so not verify that enough arguments are passed on the command line.
You do not check for EOF in the main reading loop.
You do not repeat the process in a loop until end of file, nor do you even ask the question how many line(s) do you want to read? after reading the specified number of lines...
First, if the file cannot be found, the countlines method returns zero. You should use that value to write the error message, and skip the rest of the code.
Second, in the next loop, you use
if (ch != '\n') {
printf("%c", ch);
} else {
printf("\n");
delay(s2);
x++;
}
Why the two printf statements? They will print the same thing.
Perhaps something like this:
ch = getc(ptDosya);
/* exit the loop here if you hit EOF */
printf("%c", ch); /* Why not putc() or putchar() ? */
if (ch == '\n') {
x++;
if ( x == lineCount ) {
x = 0;
lineCount = requestNumberOfLinesToRead();
} else {
sleep(s2); /* instead of delay(). Remember to #include unistd.h */
}
}
int periodCount(const char *filename) {
FILE * fp;
int n = 0;
if( (fp=fopen(filename,"r")) != NULL) {
while(fgetc(fp)!= EOF) {
if(fgetc(fp)=='.') n++;
fclose(fp);
}
}
return n;
}
Here is my code, it simply should count the number of periods in the file named filename, which contains 15 periods, yet when I try to print 'n' at the end of the program, it seems to only be reading 1 of the periods. I know that the problem is probably within the while loop, but I'm not sure why it's doing it.
You're closing the file after the first character. Also you're skipping every other character as a result of not storing the return from fgetc(). Change to:
int periodCount(const char *filename) {
FILE * fp;
int n = 0, c = 0;
if( (fp=fopen(filename,"r")) != NULL) {
while( (c = fgetc(fp)) != EOF) {
if( c == '.' )
n++;
}
fclose(fp); /* <---- move this line here */
}
return n;
}
Your fclose(fp) should be outside the while loop.
As it is, the code is reading (& discarding) the first character; reading the 2nd character & comparing it to '.'; and closing the file.
There are two problems:
You have two calls to fgetc() but you only test whether one of them returned a dot.
You close the file stream in the body of the loop.
You need something more like:
if ((fp = fopen(filename,"r")) != NULL)
{
int c;
while ((c = fgetc(fp)) != EOF)
{
if (c == '.')
n++;
}
fclose(fp);
}
So what I'm trying to do is to count blank lines, which means not only just containing '\n'but space and tab symbols as well. Any help is appreciated! :)
char line[300];
int emptyline = 0;
FILE *fp;
fp = fopen("test.txt", "r");
if(fp == NULL)
{
perror("Error while opening the file. \n");
system("pause");
}
else
{
while (fgets(line, sizeof line, fp))
{
int i = 0;
if (line[i] != '\n' && line[i] != '\t' && line[i] != ' ')
{
i++;
}
emptyline++;
}
printf("\n The number of empty lines is: %d\n", emptyline);
}
fclose(fp);
You should try and get your code right when posting on SO. You are incrementing both i and emptyline but the use el in your call to printf(). And then I don't know what that is supposed to be in your code where it has }ine. Please, at least make an effort.
For starters, you are incrementing emptyline for every line because it is outside of your if statement.
Second, you need to test the entire line to see if it contains any character that is not a whitespace character. Only if that is true should you increment emptyline.
int IsEmptyLine(char *line)
{
while (*line)
{
if (!isspace(*line++))
return 0;
}
return 1;
}
Before getting into the line loop increment the emptyLine counter and if an non whitespace character is encountred decrement the emptyLine counter then break the loop.
#include <stdio.h>
#include <string.h>
int getEmptyLines(const char *fileName)
{
char line[300];
int emptyLine = 0;
FILE *fp = fopen("text.txt", "r");
if (fp == NULL) {
printf("Error: Could not open specified file!\n");
return -1;
}
else {
while(fgets(line, 300, fp)) {
int i = 0;
int len = strlen(line);
emptyLine++;
for (i = 0; i < len; i++) {
if (line[i] != '\n' && line[i] != '\t' && line[i] != ' ') {
emptyLine--;
break;
}
}
}
return emptyLine;
}
}
int main(void)
{
const char fileName[] = "text.txt";
int emptyLines = getEmptyLines(fileName);
if (emptyLines >= 0) {
printf("The number of empty lines is %d", emptyLines);
}
return 0;
}
You are incrementing emptyline on every iteration, so you should wrap it in an else block.
Let's think of this problem logically, and let's use functions to make it clear what is going on.
First, we want to detect lines that only consist of whitespace. So let's create a function to do that.
bool StringIsOnlyWhitespace(const char * line) {
int i;
for (i=0; line[i] != '\0'; ++i)
if (!isspace(line[i]))
return false;
return true;
}
Now that we have a test function, let's build a loop around it.
while (fgets(line, sizeof line, fp)) {
if (StringIsOnlyWhitespace(line))
emptyline++;
}
printf("\n The number of empty lines is: %d\n", emptyline);
Note that fgets() will not return a full line (just part of it) on lines that have at least sizeof(line) characters.