getline() in C creating an infinite loop and skipping first word? - c

I'm a beginner in C and I'm trying to create a simple todo list program. I'm trying to use getline in a while loop, as I saw on another stack overflow answer and I thought I understood it but it's just creating an infinite loop. Also it seems to be skipping the first word for some reason. Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *list;
int i = 0;
int item = 0;
char items[10];
char chars[1000];
char * line = NULL;
size_t len = 0;
ssize_t read;
int main() {
list = fopen("/Users/bendavies/Documents/C/list.txt", "r");
int letterCount = fscanf(list,"%s",chars);
printf("Welcome to the to-do list. It can hold up to 10 items.\n");
printf("%d\n", letterCount);
if (letterCount == -1) {
printf("The list currently has no items!\n");
} else {
while ((read = getline(&line, &len, list)) != 1) {
item += 1;
printf("%d. %s", item, line);
}
}
fclose(list);
return 0;
}
The output I'm currently getting with the following list.txt:
Eat food
Drink water
Breath air
Is:
1. food
2. Drink water
3. Breath air
4. 18446744073709551615
5. 18446744073709551615
and so on and so forth.
Thank you in advance! :)

but it's just creating an infinite loop.
This line of your code: while ((read = getline(&line, &len, list)) != 1)
Unless a line contains 1 character (just a newline), it will be an infinite loop. The POSIX getline() function will return -1 (not EOF, even though EOF is usually -1) when the file is completely read. So change that line to:
while ((read = getline(&line, &len, list)) != -1)
But, I don't see you using the value of read inside that loop, so this would be better:
Fix 1: while (getline(&line, &len, list) != -1)
And inside that loop, I see: printf("%d. %s", item, line);
You might find very old implementations of getline() that don't include the newline, in which case, if you want your output in separate lines, you need to put a \n:
Fix 2: printf("%d. %s\n", item, line);
However, if you use a more modern implementation, it will preserve the newline in accordance with the POSIX specification.
Also, if the very last 'line' in the file is not terminated with a newline, you might still want to add one. In that case, you could keep the read length and use that to detect whether there is a newline at the end of the line.
Also it seems to be skipping the first word for some reason
Because of int letterCount = fscanf(list,"%s",chars);
That fscanf reads the first word of your file. Now the file pointer is at that position (end of the first word) and further reading of the file will happen from that place.
So, reposition the file pointer to the beginning of the file after reading the first word from the file:
Fix 3:
int letterCount = fscanf(list,"%s",chars);
fseek(list, 0, SEEK_SET); // <-- this will reposition the file pointer as required

Related

It takes very long time to read '.txt file' how can i solve this problem? ( C )

there is very long "dict.txt" file.
the size of this file is about 2400273(calculated by fseek, SEEK_END)
this file has lots of char like this 'apple = 사과'(simillar to dictionary)
Main problem is that reading file takes very long time
I couldn't find any solution to solve this problem in GOOGLE
The reason i guessed is associated with using fgets() but i don't know exactly.
please help me
here is my code written by C
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int line = 0;
char txt_str[50];
FILE* pFile;
pFile = fopen("dict_test.txt", "r");
if (pFile == NULL) {
printf("file doesn't exist or there is problem to open your file\n");
}
else {
do{
fgets(txt_str, 50, pFile);;
line++;
} while (txt_str != EOF);
}
printf("%d", line);
}
Output
couldn't see result because program was continuosly running
Expected
the number of lines of this txt file
Major
OP's code fail to test the return value of fgets(). Code needs to check the return value of fgets() to know when to stop. #A4L
do{
fgets(txt_str, 50, pFile);; // fgets() return value not used.
Other
Line count should not get incremented when fgets() returns NULL.
Line count should not get incremented when fgets() read a partial line. (I. e.) the line was 50 or longer. Reasonable to use a wider than 50 buffer.
Line count may exceed INT_MAX. There is always some upper bound, yet trivial to use a wider type.
Good practice to close the stream.
Another approach to count lines would use fread() to read chunks of memory and then look for start of lines. (Not shown)
Recommend to print a '\n' after the line count.
int main(void) {
FILE* pFile = fopen("dict_test.txt", "r");
if (pFile == NULL) {
printf("File doesn't exist or there is problem to open your file.\n");
return EXIT_FAILURE;
}
unsigned long long line = 0;
char txt_str[4096];
while (fgets(txt_str, sizeof txt_str, pFile)) {
if (strlen(txt_str) == sizeof txt_str - 1) { // Buffer full?
if (txt_str[sizeof txt_str - 1] != '\n') { // Last not \n?
continue;
}
}
line++;
}
fclose(pFile);
printf("%llu\n", line);
}
fgets returns NULL on EOF.
You are never assigning the result of
fgets(txt_str, 50, pFile);
to txt_str, your program never sees the end of the file and thus enters an endless loop.
try something like this:
char* p_str;
do{
p_str = fgets(txt_str, 50, pFile);
} while (p_str != NULL);

there is some text in a file and I have to put '\n' after every ending of a sentence. I am stuck

char text[1024];
fgets(text, 1024, stdin); //Foydanaluvchi kiritadi matn
FILE * file = fopen("my.txt", "w"); //yozish uchun file degan fayl ochiladi
for(int i=0; i<strlen(text); i++){
if(text[i] == 46){
fseek(file, 0, SEEK_CUR);
fputc(text[i]='\n', file);
}else{
fputc(text[i+1], file);
}
}
fclose(file);
Your logic does not make sense. Work it out on paper with a simple example to see that
here:
fputc(text[i]='\n', file);
you are writing a newline instead of the period, not after it; and
here:
fputc(text[i+1], file);
you are writing a different character than the one you just tested. Moreover,
this:
fseek(file, 0, SEEK_CUR);
asks to adjust the file position to its own current value. There may be circumstances where that's actually useful, but yours are not among them.
I think you're making it harder than it should be. All you really need to do to implement the behavior described is loop through the data, write each character, and if that character was a period ('.') then additionally write a newline.
Although the question does not say so, possibly you are expected to avoid adding extra newlines where there already is one after a sentence. That would require looking ahead at least one character, but it is doable.
You might also consider reading the file one character at a time (with getchar(), say). That would actually make your logic a little simpler, and it might smooth out some technical details if you have to avoid adding duplicate newlines, or if you need some other extra behavior such as eliminating space characters between sentences.
It is difficult to modify the file in place as you are trying to do, because there is no standard function or system call to insert bytes in the middle of a file.
The recommended approach it to write a simple filter that reads the text from stdin and writes the modified contents to stdout:
#include <stdio.h>
int main() {
int c;
while ((c = getchar()) != EOF) {
putchar(c);
if (c == '.')
putchar('\n');
}
return 0;
}
Note however that the above code will add a newline after each ., some of which might not end a sentence, eg: I paid $3.49 for each bug and some of which may already be followed by a newline, thereby doubling them.
To avoid both of the above pitfalls, you might only output the newline if the . is followed by a space. In this case, you can replace the space after each . with a newline, so you could operate in place on systems where newline is a single byte:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
FILE *fp;
int c, last = 0, count = 0;
if (argc < 2) {
fprintf(stderr, "missing file name\n");
return 1;
}
if ((fp = fopen(argv[1], "rb+")) == NULL) {
fprintf(stderr, "cannot open file %s: %s\n", argv[1], strerror(errno));
return 1;
}
while ((c = getc(fp)) != EOF) {
if (c == ' ' && last == '.') {
// call fseek to move back one byte
fseek(fp, -1L, SEEK_CUR);
// overwrite the space with a newline
putc('\n', fp);
// call fseek to allow switching back to read mode
fseek(fp, 0L, SEEK_CUR);
count++;
}
last = c;
}
fclose(fp);
printf("%d changes\n", count);
return 0;
}

read from .pas file to buffer and display content in c

I have a buffer and I want to read a pascal file and put content in the buffer. Then I want to add '$' sign in the end of buffer. When I tried to do it i get only the last row from my pascal file into buffer I don't why. please help. Here is my code!
FILE *fp = fopen("test.pas", "r");
while(!feof(fp)){
fscanf(fp, "%s", buffer);
}
strcat(buffer,"$"); fclose(fp);
You are reading the lines, the problem is that you are overwriting them over and over again in your buffer, so only the last one stays.
A good way to do this is to use fscanf in the while condition, this way you'll have a sound stop condition and you can verify the read results, which should allways be done.
You can do something like this:
Live demo
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINES 100 //nr of lines
int main() {
//array of 100 pointers to char, so 100 lines max, adapt it to you needs
//should be the equal or larger than the max number of lines to be read
char *buffer[LINES];
FILE *fp;
int i = 0;
//checking the opened file is also a good practice
if (!(fp = fopen("test.pas", "r"))) {
perror("Not able to open file!");
return 1;
}
do {
if (!(buffer[i] = malloc(100))) { //allocate memory for each line
perror("Memory allocation failed"); //checking memory allocation
return 1;
}
}while (fscanf(fp, "%99s", buffer[i]) == 1 && strcat(buffer[i], "$") && i++ < LINES - 1);
buffer[i] = NULL; // sentinel, marks the end of the array of strings
i = 0; //reset i
while (buffer[i]) {
puts(buffer[i]); //print each line
free(buffer[i]); //free memory
i++;
}
fclose(fp);
}
Note that fscanf() reads until the next blank space, so for strings with more than 1 word you should use something like fgets or you if you use UNIX, getline().
feof is not the best option as you can see in
Why is “while ( !feof (file) )” always wrong?
The standard actually exemplifies the correct usage of feof ISO/IEC9899:2017 N2176 § 7.21.6.2 - 19

Find end of text in a text file padded with NULL characters in C [duplicate]

file looks like this:
abcd
efgh
ijkl
I want to read the file using C so that it read the last line first:
ijkl
efgh
abcd
I cannot seem to find a solution that does not use an array for storage. Please help.
edit0:
Thanks for all the answers. Just to let you know, I am the one creating this file. So, can I create in a way its in the reverse order? Is that possible?
It goes like this:
Seek to one byte before the end of the file using fseek. There's no guarantee that the last line will have an EOL so the last byte doesn't really matter.
Read one byte using fgetc.
If that byte is an EOL then the last line is a single empty line and you have it.
Use fseek again to go backwards two bytes and check that byte with fgetc.
Repeat the above until you find an EOL. When you have an EOL, the file pointer will be at the beginning of the next (from the end) line.
...
Profit.
Basically you have to keep doing (4) and (5) while keeping track of where you were when you found the beginning of a line so that you can seek back there before starting your scan for the beginning of the next line.
As long as you open your file in text mode you shouldn't have have to worry about multibyte EOLs on Windows (thanks for the reminder Mr. Lutz).
If you happen to be given a non-seekable input (such as a pipe), then you're out of luck unless you want to dump your input to a temporary file first.
So you can do it but it is rather ugly.
You could do pretty much the same thing using mmap and a pointer if you have mmap available and the "file" you're working with is mappable. The technique would be pretty much the same: start at the end and go backwards to find the end of the previous line.
Re: "I am the one creating this file. So, can I create in a way its in the reverse order? Is that possible?"
You'll run into the same sorts of problems but they'll be worse. Files in C are inherently sequential lists of bytes that start at the beginning and go to the end; you're trying to work against this fundamental property and going against the fundamentals is never fun.
Do you really need your data in a plain text file? Maybe you need text/plain as the final output but all the way through? You could store the data in an indexed binary file (possibly even an SQLite database) and then you'd only have to worry about keeping (or windowing) the index in memory and that's unlikely to be a problem (and if it is, use a "real" database); then, when you have all your lines, just reverse the index and away you go.
In pseudocode:
open input file
while (fgets () != NULL)
{
push line to stack
}
open output file
while (stack no empty)
{
pop stack
write popped line to file
}
The above is efficient, there is no seek (a slow operation) and the file is read sequentially. There are, however, two pitfalls to the above.
The first is the fgets call. The buffer supplied to fgets may not be big enough to hold a whole line from the input in which case you can do one of the following: read again and concatenate; push a partial line and add logic to the second half to fix up partial lines or wrap the line into a linked list and only push the linked list when a newline/eof is encountered.
The second pitfall will happen when the file is bigger than the available ram to hold the stack, in which case you'll need to write the stack structure to a temporary file whenever it reaches some threshold memory usage.
The following code should do the necessary inversion:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fd;
char len[400];
int i;
char *filename = argv[1];
int ch;
int count;
fd = fopen(filename, "r");
fseek(fd, 0, SEEK_END);
while (ftell(fd) > 1 ){
fseek(fd, -2, SEEK_CUR);
if(ftell(fd) <= 2)
break;
ch =fgetc(fd);
count = 0;
while(ch != '\n'){
len[count++] = ch;
if(ftell(fd) < 2)
break;
fseek(fd, -2, SEEK_CUR);
ch =fgetc(fd);
}
for (i =count -1 ; i >= 0 && count > 0 ; i--)
printf("%c", len[i]);
printf("\n");
}
fclose(fd);
}
The following works for me on Linux, where the text file line separator is "\n".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void readfileinreverse(FILE *fp)
{
int i, size, start, loop, counter;
char *buffer;
char line[256];
start = 0;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
buffer = malloc((size+1) * sizeof(char));
for (i=0; i< size; i++)
{
fseek(fp, size-1-i, SEEK_SET);
buffer[i] = fgetc(fp);
if(buffer[i] == 10)
{
if(i != 0)
{
counter = 0;
for(loop = i; loop > start; loop--)
{
if((counter == 0) && (buffer[loop] == 10))
{
continue;
}
line[counter] = buffer[loop];
counter++;
}
line[counter] = 0;
start = i;
printf("%s\n",line);
}
}
}
if(i > start)
{
counter = 0;
for(loop = i; loop > start; loop--)
{
if((counter == 0) && ((buffer[loop] == 10) || (buffer[loop] == 0)))
{
continue;
}
line[counter] = buffer[loop];
counter++;
}
line[counter] = 0;
printf("%s\n",line);
return;
}
}
int main()
{
FILE *fp = fopen("./1.txt","r");
readfileinreverse(fp);
return 0;
}
Maybe , The does the trick , It reverse content of the file in whole
just like a string
Define a variable of type string with size of your file
Get Contents of the file and store in the variable
Use strrev() to reverse the string.
You can later on display the output or even write it to a file. The code goes like this:
#include <stdio.h>
#include <String.h>
int main(){
FILE *file;
char all[1000];
// give any name to read in reverse order
file = fopen("anyFile.txt","r");
// gets all the content and stores in variable all
fscanf(file,"%[]",all);
// Content of the file
printf("Content Of the file %s",all);
// reverse the string
printf("%s",strrev(all));
fclose(file);
return 0;
}
I know this question has been awnsered, but the accepted awnser does not contain a code snippet and the other snippets feel too complex.
This is my implementation:
#include <stdio.h>
long file_size(FILE* f) {
fseek(f, 0, SEEK_END); // seek to end of file
long size = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file
return size;
}
int main(int argc, char* argv[]) {
FILE *in_file = fopen(argv[1], "r");
long in_file_size = file_size(in_file);
printf("Got file size: %ld\n", in_file_size);
// Start from end of file
fseek(in_file, -1, SEEK_END); // seek to end of file
for (int i = in_file_size; i > 0; i--) {
char current_char = fgetc(in_file); // This progresses the seek location
printf("Got char: |%c| with hex: |%x|\n", current_char, current_char);
fseek(in_file, -2, SEEK_CUR); // Go back 2 bytes (1 to compensate)
}
printf("Done\n");
fclose(in_file);
}

read file backwards (last line first)

file looks like this:
abcd
efgh
ijkl
I want to read the file using C so that it read the last line first:
ijkl
efgh
abcd
I cannot seem to find a solution that does not use an array for storage. Please help.
edit0:
Thanks for all the answers. Just to let you know, I am the one creating this file. So, can I create in a way its in the reverse order? Is that possible?
It goes like this:
Seek to one byte before the end of the file using fseek. There's no guarantee that the last line will have an EOL so the last byte doesn't really matter.
Read one byte using fgetc.
If that byte is an EOL then the last line is a single empty line and you have it.
Use fseek again to go backwards two bytes and check that byte with fgetc.
Repeat the above until you find an EOL. When you have an EOL, the file pointer will be at the beginning of the next (from the end) line.
...
Profit.
Basically you have to keep doing (4) and (5) while keeping track of where you were when you found the beginning of a line so that you can seek back there before starting your scan for the beginning of the next line.
As long as you open your file in text mode you shouldn't have have to worry about multibyte EOLs on Windows (thanks for the reminder Mr. Lutz).
If you happen to be given a non-seekable input (such as a pipe), then you're out of luck unless you want to dump your input to a temporary file first.
So you can do it but it is rather ugly.
You could do pretty much the same thing using mmap and a pointer if you have mmap available and the "file" you're working with is mappable. The technique would be pretty much the same: start at the end and go backwards to find the end of the previous line.
Re: "I am the one creating this file. So, can I create in a way its in the reverse order? Is that possible?"
You'll run into the same sorts of problems but they'll be worse. Files in C are inherently sequential lists of bytes that start at the beginning and go to the end; you're trying to work against this fundamental property and going against the fundamentals is never fun.
Do you really need your data in a plain text file? Maybe you need text/plain as the final output but all the way through? You could store the data in an indexed binary file (possibly even an SQLite database) and then you'd only have to worry about keeping (or windowing) the index in memory and that's unlikely to be a problem (and if it is, use a "real" database); then, when you have all your lines, just reverse the index and away you go.
In pseudocode:
open input file
while (fgets () != NULL)
{
push line to stack
}
open output file
while (stack no empty)
{
pop stack
write popped line to file
}
The above is efficient, there is no seek (a slow operation) and the file is read sequentially. There are, however, two pitfalls to the above.
The first is the fgets call. The buffer supplied to fgets may not be big enough to hold a whole line from the input in which case you can do one of the following: read again and concatenate; push a partial line and add logic to the second half to fix up partial lines or wrap the line into a linked list and only push the linked list when a newline/eof is encountered.
The second pitfall will happen when the file is bigger than the available ram to hold the stack, in which case you'll need to write the stack structure to a temporary file whenever it reaches some threshold memory usage.
The following code should do the necessary inversion:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fd;
char len[400];
int i;
char *filename = argv[1];
int ch;
int count;
fd = fopen(filename, "r");
fseek(fd, 0, SEEK_END);
while (ftell(fd) > 1 ){
fseek(fd, -2, SEEK_CUR);
if(ftell(fd) <= 2)
break;
ch =fgetc(fd);
count = 0;
while(ch != '\n'){
len[count++] = ch;
if(ftell(fd) < 2)
break;
fseek(fd, -2, SEEK_CUR);
ch =fgetc(fd);
}
for (i =count -1 ; i >= 0 && count > 0 ; i--)
printf("%c", len[i]);
printf("\n");
}
fclose(fd);
}
The following works for me on Linux, where the text file line separator is "\n".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void readfileinreverse(FILE *fp)
{
int i, size, start, loop, counter;
char *buffer;
char line[256];
start = 0;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
buffer = malloc((size+1) * sizeof(char));
for (i=0; i< size; i++)
{
fseek(fp, size-1-i, SEEK_SET);
buffer[i] = fgetc(fp);
if(buffer[i] == 10)
{
if(i != 0)
{
counter = 0;
for(loop = i; loop > start; loop--)
{
if((counter == 0) && (buffer[loop] == 10))
{
continue;
}
line[counter] = buffer[loop];
counter++;
}
line[counter] = 0;
start = i;
printf("%s\n",line);
}
}
}
if(i > start)
{
counter = 0;
for(loop = i; loop > start; loop--)
{
if((counter == 0) && ((buffer[loop] == 10) || (buffer[loop] == 0)))
{
continue;
}
line[counter] = buffer[loop];
counter++;
}
line[counter] = 0;
printf("%s\n",line);
return;
}
}
int main()
{
FILE *fp = fopen("./1.txt","r");
readfileinreverse(fp);
return 0;
}
Maybe , The does the trick , It reverse content of the file in whole
just like a string
Define a variable of type string with size of your file
Get Contents of the file and store in the variable
Use strrev() to reverse the string.
You can later on display the output or even write it to a file. The code goes like this:
#include <stdio.h>
#include <String.h>
int main(){
FILE *file;
char all[1000];
// give any name to read in reverse order
file = fopen("anyFile.txt","r");
// gets all the content and stores in variable all
fscanf(file,"%[]",all);
// Content of the file
printf("Content Of the file %s",all);
// reverse the string
printf("%s",strrev(all));
fclose(file);
return 0;
}
I know this question has been awnsered, but the accepted awnser does not contain a code snippet and the other snippets feel too complex.
This is my implementation:
#include <stdio.h>
long file_size(FILE* f) {
fseek(f, 0, SEEK_END); // seek to end of file
long size = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file
return size;
}
int main(int argc, char* argv[]) {
FILE *in_file = fopen(argv[1], "r");
long in_file_size = file_size(in_file);
printf("Got file size: %ld\n", in_file_size);
// Start from end of file
fseek(in_file, -1, SEEK_END); // seek to end of file
for (int i = in_file_size; i > 0; i--) {
char current_char = fgetc(in_file); // This progresses the seek location
printf("Got char: |%c| with hex: |%x|\n", current_char, current_char);
fseek(in_file, -2, SEEK_CUR); // Go back 2 bytes (1 to compensate)
}
printf("Done\n");
fclose(in_file);
}

Resources