I need to write a program to read from a file, then save the words into a linked list for further use. I decided to read the text character by character using fgetc, then save all into the list each time a newline ('\n') or space (' ') is detected, indicating one word.
Sorry I'm a newbie in file pointers, this is what I've gotten so far:
struct list { //global
char string[30];
struct list *next;
};
int main(void) {
FILE *filePtr;
char file[] = "text.txt";
char tempStr[30];
list *curr, *header;
char c;
int i = 0;
curr = NULL;
header = NULL;
if((filePtr = fopen(file, "r")) == NULL) {
printf("\nError opening file!");
getchar();
exit(101);
}
printf("\nFile is opened for reading.\n");
while(!EOF) {
while((c = fgetc(filePtr) != ' ') && (c = fgetc(filePtr) != '\n')) {
curr = (list*)malloc(sizeof(list));
//c = fgetc(filePtr);
tempStr[i] = fgetc(filePtr);
i++;
}
tempStr[i] = '\0';
strcpy(curr->string, tempStr);
curr->next = header;
header = curr;
i = 0;
}
while(curr!=NULL) {
printf("%s - ", curr->string); //This will not print.
curr = curr->next;
}
if(fclose(filePtr) == EOF) {
printf("\nError closing file!");
getchar();
exit(102);
}
printf("\nFile is closed.\n");
getchar();
getchar();
}
If the text file:
have a nice day
Desired output:
have - a - nice - day
But, I could not print out anything except the file opened and closed.
Thanks.
Value of the macro EOF is -1, which is a system macro defined in stdio.h. File read APIs(fgetc, fread, fscanf) will return -1 once it reaches end of file. So in your program you have while(!EOF) this will be always false, because NOT of -1 is always 0. -1 will be represented in 2's complement so all bits of that variable will be 1. (If size of int is 2, -1 will be stored as 0xFFFF in int variable).
Use the below sample code.
while(EOF != (c = fgetc(filePtr)))
{
if ((c == ' ') || (c == '\n'))
{
if (i == 0)
{
continue;
}
tempStr[i] = '\0';
i = 0;
//here do your linklist node creation and insertion operation
continue;
}
tempStr[i] = c;
i++;
}
while(!EOF) {
This is a constant condition that is always false, so you never read anything.
Your code also has other problems, such as doing
curr = (list*)malloc(sizeof(list));
in a loop but using curr outside the loop.
You should replace the while condition with whatever function you're using to read the file - are you sure fgets isn't horrendously more efficient than this?
IE read the string into a much larger buffer than you expect, then copy it into an appropriately sized buffer and attach that to the node.
This is always false:
while(!EOF)
Review your memory allocation code.
curr = (list*)malloc(sizeof(list))
Files may not have newlines at the end of the file.
while((c = fgetc(filePtr) != ' ') && (c = fgetc(filePtr) != '\n'))
Spoiler:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
struct list *next;
char string[30];
};
int main(void) {
FILE *fp;
char file[] = "llist4.c";
/* in C you CANNOT omit the "struct keyword" from a declaration or definition. */
struct list *head=NULL, **pp= &head;
int ch; /* getc() returns an int */
size_t len ;
char buff[30];
fp = fopen(file, "r");
if (!fp) {
fprintf(stderr, "\nError opening file!");
exit(EXIT_FAILURE);
}
printf("\nFile has been opened for reading.\n");
for (len=0; len < sizeof buff; ) {
ch = fgetc(fp);
if (ch == EOF && !len) break;
if (ch == ' ' || ch == '\n' || ch == EOF) {
if (!len) continue;
buff[len] = '\0';
*pp = malloc(sizeof **pp);
if (!*pp) break;
strcpy((*pp)->string, buff);
(*pp)->next = NULL;
pp = &(*pp)->next ;
len=0; continue;
}
buff[len++] = ch;
}
if (len) {
fprintf(stderr, "\nWord was too large, or out of memory\n");
}
for( ;head; head= head->next) {
printf("%s - ", head->string);
}
if (fclose(fp) == EOF) {
fprintf(stderr, "\nError closing file!\n");
exit(EXIT_FAILURE);
}
printf("\nFile has been closed.\n");
exit(EXIT_SUCCESS);
}
Related
I am working on a management system project and want to clear the file before adding data to it. I am using this code as a reference. I have rewritten the code from the reference and instead of writing the data from the temporary file(tmp) back to the original(FILE_NAME), I have printed it out to the terminal.
When I compile and run the program, it prints all the content and a few more lines after the end of the file. After this it stops and doesn't finish execution. I have added to comments to help understand my thought process better.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define BUFFER_SIZE 1000
#define FILE_NAME "data.csv"
int main()
{
FILE* file;
char buffer[BUFFER_SIZE];
// Opening file
if(file = fopen(FILE_NAME, "r+"))
{
char c; // To get character from buffer
int i = 0; // Index for the buffer character
int isEmpty = 1; // If the line is empty
FILE* tmp;
if(tmp = tmpfile())
{
while(1)
{
buffer[i++] = c;
if(c != '\n') // Checking for blank lines
{
isEmpty = 0;
}
else
{
if(c == '\n' && isEmpty == 0) // Read a word; Print to tmp file
{
buffer[i] = '\0';
fprintf(tmp, "%s", buffer);
i = 0;
isEmpty = 1;
}
else if(c == '\n' && isEmpty == 1) // NOT SURE WHY THIS IS IMPORTANT
{
buffer[i] = '\0';
i = 0;
isEmpty = 1;
}
}
if(c == EOF)
{ break; }
while(1) // Loop to print contents of tmp file onto terminal
{
c = getc(tmp);
printf("c: %c", c);
if(c == EOF)
{ break; }
}
}
}
else
{
printf("Unable to open temporary file\n");
}
fclose(file);
}
else
{
printf("Unable to open file.");
}
getchar();
return 0;
}
UPDATE:
I've modified a few lines and have got it working.
I'd forgotten to assign c in the above program. Also #Barmar won't char c work just as well as int c. Characters can be integers as well right?
Why would large indentations lead to bugs? I find the blocks of code to be more differetiated.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define BUFFER_SIZE 1000
#define FILE_NAME "data.csv"
int main()
{
// Variable Declaration
FILE* file;
char buffer[BUFFER_SIZE];
// Opening file
if( file = fopen(FILE_NAME, "r+") )
{
char c; // Reading characters from the file
int i; // Index of the characters
int isEmpty = 1; // 1-> character is empty; 0-> character is not empty
FILE* tmp;
if( tmp = fopen("tmp.csv", "a+") )
{
char c; // Reading characters from files
int i = 0; // Index
int isEmpty = 1; // 1->previous word is empty; 0->previous word is not empty
while( (c = getc(file)) != EOF)
{
if( c != '\n' && c != ' ' && c != '\0' && c != ',')
{
isEmpty = 0;
buffer[i++] = c;
}
else
{
if( c == '\n' && isEmpty == 0 )
{
buffer[i] = '\0';
fprintf(tmp, "%s", buffer);
i = 0;
isEmpty = 1;
}
else if( c == '\n' && isEmpty == 1 )
{
buffer[i] = '\0';
i = 0;
}
}
}
fclose(tmp);
}
else
{
printf("Unable to open temporary file\n");
}
fclose(file);
}
else
{
printf("Unable to open file\n");
}
return 0;
}
Are there are ways to simplify the program and make it more compact or less error prone?
I've been trying to merge the contents of two .txt files into a third .txt file that combines the output. All I know how to do (and all I have been able to find answers for), however, is to merge them by putting the contents of the first file first, and the second file second. However, I would prefer the output to list the first line of the first file, then the first line of the second file -- followed on a new line by the second line of the first file and the second line of the second file.
To make this clearer visually, the code is currently appearing as:
file1-line1
file1-line2
file1-line3
file2-line1
file2-line2
file2-line3
... When I'd like it to appear as:
file1-line1 file2-line1
file1-line2 file2-line2
file1-line3 file2-line3
The code I have is very basic and executes the first example fine:
int main()
{
FILE *pointer1 = fopen("file1.txt", "r");
FILE *pointer2 = fopen("file2.txt", "r");
FILE *pointer3 = fopen("combined.txt", "w");
int ch;
if (pointer1 == NULL || pointer2 == NULL || pointer3 == NULL)
{
puts("Could not open files");
exit(0);
}
while ((ch = fgetc(pointer1)) != EOF)
fputc(ch, pointer3);
while ((ch = fgetc(pointer2)) != EOF)
fputc(ch, pointer3);
printf("Merged file1.txt and file2.txt into combined.txt");
fclose(pointer1);
fclose(pointer2);
fclose(pointer3);
return 0;
}
Is there a way to output the described situation? I am aware that E0F refers to the end of a file, and is likely causing an issue. Is there a similar condition for an end of a line (like E0L)?
Edit: Changed char ch to int ch.
First, if you have a Unix-like system, the paste command already does that. Next as you want to process lines, you should use fgets. Here you have to loop over input files one line at a time, copy the lines to the output file without the newline, and add the new line after copying everything.
As the processing for both input files is the same, and as I am lazy, I wrote a function to only write it once. In the end code could be:
FILE *copyline(FILE *in, FILE *out) {
char line[256];
if (in != NULL) {
for (;;) { // loop if the line is larger that sizeof(line)
if (NULL == fgets(line, sizeof(line), in)) { // EOF on file1
fclose(in);
in = NULL;
break;
}
size_t end = strcspn(line, "\n");
if (end != 0) fwrite(line, 1, end, out); // smth to write
if (end != strlen(line)) break; // \n found: exit loop
}
}
return in;
}
int main()
{
FILE *pointer1 = fopen("file1.txt", "r");
FILE *pointer2 = fopen("file2.txt", "r");
FILE *pointer3 = fopen("combined.txt", "w");
const char sep[] = " "; // a separator between lines of both file
if (pointer1 == NULL || pointer2 == NULL || pointer3 == NULL)
{
puts("Could not open files");
exit(0);
}
for (;;) {
pointer1 = copyline(pointer1, pointer3);
fwrite(sep, strlen(sep), 1, pointer3);
pointer2 = copyline(pointer2, pointer3);
if (pointer1 == NULL && pointer2 == NULL) break;
fputc('\n', pointer3); // if smth was written, add a newline
printf(".");
}
printf("Merged file1.txt and file2.txt into combined.txt");
fclose(pointer3);
return 0;
}
Here's one way to approach it:
#include <err.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int
main(int argc, char **argv)
{
if( argc < 3 ) {
printf("usage: %s file1 file2\n", basename(argv[0]));
}
FILE *pointer1 = xfopen(argv[1], "r");
FILE *pointer2 = xfopen(argv[2], "r");
FILE *current = pointer1;
int ch;
while( ( ch = fgetc(current)) != EOF ) {
if( ch == '\n' ) {
if( current == pointer1 ) {
int k;
current = pointer2;
if( (k = fgetc(current)) != EOF ) {
ungetc(k, current);
ch = ' ';
}
} else {
current = pointer1;
}
}
putchar(ch);
}
if( ferror(current) ) {
err(EXIT_FAILURE, "Error reading %s",
current == pointer1 ? argv[1] : argv[2]);
}
current = current == pointer1 ? pointer2 : pointer1;
while( (ch = fgetc(current)) != EOF) {
putchar(ch);
}
fclose(pointer1);
fclose(pointer2);
return 0;
}
#include <stdio.h>
int main()
{
FILE *pointer1 = fopen("file1.txt", "r");
FILE *pointer2 = fopen("file2.txt", "r");
FILE *pointer3 = fopen("combined.txt", "w");
char ch1, ch2;
if (pointer1 == NULL || pointer2 == NULL || pointer3 == NULL)
{
puts("Could not open files");
return 0;
}
do
{
char c1 = fgetc(pointer1);
char c2 = fgetc(pointer2);
if (feof(pointer1) || feof(pointer2))
break;
while(c1!='\n')
{
fputc(c1,pointer3);
c1=fgetc(pointer1);
if(feof(pointer1)) break;
}
fputc(' ',pointer3);
while(c2!='\n')
{
fputc(c2,pointer3);
c2=fgetc(pointer2);
if(feof(pointer2)) break;
}
fputc('\n',pointer3);
} while (1);
printf("Merged file1.txt and file2.txt into combined.txt");
fclose(pointer1);
fclose(pointer2);
fclose(pointer3);
return 0;
}
This works like you want.
Output: Combined file.txt
file1-line1 file2-line1
file1-line2 file2-line2
file1-line3 file2-line3
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void handle(FILE *np)// this is to handle newline characters
{
putc('\n', np);
}
/* skip a C multi-line comment, return the last byte read or EOF */
int m_cmnt(FILE *fp, int *lineno_p) {
FILE *np = stdout;
int prev, ch, replacement = ' ';
for (prev = 0; (ch = getc(fp)) != EOF; prev = ch) {
if (prev == '\\' && ch == 'n') {
replacement = '\n';
++*lineno_p;
}
if (prev == '*' && ch == '/')
return replacement;
}
return EOF;
}
int main(int argc, char *argv[]) {
FILE *fp = stdin, *np = stdout;
int ch,prev;
bool String = 0;
const char *filename = "<stdin>";
int lineno = 1;
fp = fopen(filename, "r");
np = fopen(argv[2], "w");
if (argc > 1) {
if ((fp = fopen(filename = argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open input file %s: \n",
filename);
exit(EXIT_FAILURE);
}
}
if (argc > 2) {
if ((np = fopen(argv[2], "w")) == NULL) {
fprintf(stderr, "Cannot open output file %s: \n",
argv[2]);
exit(EXIT_FAILURE);
}
}
while ((ch = getc(fp)) != EOF) {
if (ch == '\n')
lineno++;
/* file pointer currently not inside a string */
if (!String) {
if (ch == '/') {
ch = getc(fp);
if (ch == '\n')
lineno++;
if (ch == '*') {
int startline = lineno;
ch = m_cmnt(fp, &lineno);
if (ch == EOF) {
fprintf(stderr, "%s:%d: error: unterminated comment started on line %d\n",
filename, lineno, startline);
exit(EXIT_FAILURE);
break;
}
putc(ch, np);
} else {
putc('/', np);
putc(ch, np);
}
}
else if ( ch=='\\')/*to handle newline character*/
{
prev=ch ;
ch= getc(fp) ;
switch(ch)
{
case 'n' :
handle(np);
break ;
/*default :
putc(prev , np) ;
putc(ch , np) ;
break ;*/
}
}
else {
putc(ch, np);
}
} else {
putc(ch, np);
}
if (ch == '"' || ch == '\'')
String = !String;
}
fclose(fp);
fclose(np);
//remove(arr[1]);
//rename("temp.txt", arr[1]);
return EXIT_SUCCESS;
}
I have been working on this project for almost more than a week now. I have asked many questions on this site to help me get the desired result.The basics of this program is to remove multiline comments from source file and write the rest to some output file. It also need to to ignore any thing that is inside a string literal or character literal(like escaped characters). Now I have come to finalize it but I still need to achieve this two outputs shown below
INPUT1 = //*SOMECOMMENT*/
OUTPUT1 = /
INPUT2 = "this \"test"/*test*/
OUTOUT2 = "this \"test"
The current(erroneous) output is shown below
INPUT1 = //*SOMECOMMENT*/
OUTPUT1 = //*SOMECOMMENT*/ This is wrong.
INPUT2 = "this \"test"/*test*/
OUTOUT2 = "this \"test"/*test*/ This is also wrong.
The program don't work for the case where a comment comes after a forward slash(/) and the second failure of the program is it don't ignore escape character inside a string or character literal. I need a fix on this two problems please.
If your problem is that you want to read an input stream of characters, divide that stream into tokens, and then emit only a subset of those tokens, I think Lex is exactly the tool you're looking for.
If I understand your comment correctly, the file you're trying to read in and transform is itself C code. So you will need to build up a Lex definition of the C language rules.
A quick search turned up this Lex specification of the ANSI C grammar. I cannot vouch for its accuracy or speak to its licensing. At first glance it seems to only support C89. But it is probably enough to point you in the right direction.
i am working in file system in that i am counting paragraph from the file but
i am not getting please suggest me how can i do that i tried this but not getting what i want
int main()
{
FILE *fp=fopen("200_content.txt ","r");
int pCount=0;
char c;
while ((c=fgetc(fp))!=EOF)
{
if(c=='\n'){pCount++;}
else{continue;}
}
printf("%d",pCount);
return 0;
}
You should declare c as int instead of char.
Also, remember to fclose(fp); before main() returns.
A paragraph contains two subsequent '\n's, use a variable for counting the two '\n's, like this,
int main()
{
FILE *fp=fopen("200_content.txt ","r");
int pCount=0;
char c;
int newln_cnt=0;
while ((c=fgetc(fp))!=EOF)
{
if(c=='\n')
{
newln_cnt++;
if(newln_cnt==2)
{
pCount++;
newln_cnt=0;
}
}
else{continue;}
}
printf("%d",pCount);
return 0;
}
You code counts the number of newline '\n' characters, not empty line which demarcates the paragraphs. Use fgets to read lines from the file. I suggest this -
#include <stdio.h>
// maximum length a line can have in the file.
// +1 for the terminating null byte added by fgets
#define MAX_LEN 100+1
int main(void) {
char line[MAX_LEN];
FILE *fp = fopen("200_content.txt", "r");
if(fp == NULL) {
printf("error in opening the file\n");
return 1;
}
int pcount = 0;
int temp = 0;
while(fgets(line, sizeof line, fp) != NULL) {
if(line[0] == '\n') {
// if newline is found and temp is 1 then
// this means end of the paragraph. increase
// the paragraph counter pcount and set temp to 0
if(temp == 1)
pcount++;
temp = 0;
}
else {
// if a non-empty line is found, this means
// the start of the paragraph
temp = 1;
}
}
// if the last para doesn't end with empty line(s)
if(temp == 1)
pcount++;
printf("number of para in the file is %d\n", pcount);
return 0;
}
For starters, I assume that you consider a new line to be a new paragraph.
i.e.
This is line 1.
This is line 2.
has 2 paragraphs.
What your code does is neglect the case where there is an EOF and not a newline character (\n) after This is line 2.
One way to fix this is to use an extra char variable.
int main()
{
FILE *fp=fopen("200_content.txt ","r");
int pCount=0;
char c; // char that checks
char last_c; //record of the last character read in the loop
while ((c=fgetc(fp))!=EOF)
{
if(c=='\n'){pCount++;}
last_c = c;
else{continue;} //this line is redundant. You can remove it
}
if (last_c != '\n') pCount++; //if EOF at the end of line and not '\n'
printf("%d",pCount);
return 0;
}
void analyze_file(const char *filename) {
FILE* out_file;
out_file = fopen(filename,"r");
int size;
if(out_file == NULL)
{
printf("Error(analyze_file): Could not open file %s\n",filename);
return;
}
fseek(out_file,0,SEEK_SET);
char ch,ch1;
int alpha_count = 0,num_count = 0,non_alnum =0,charac=0;
int word_count =0,line=0;
int para=0;
while(!feof(out_file))
{
ch = fgetc(out_file);
if (isalpha(ch))
alpha_count++;
else if(isdigit(ch))
num_count++;
else if(!isalnum(ch) && ch!='\n' && !isspace(ch))
++non_alnum;
else if(ch=='\n')
{ line++;
ch1 = fgetc(out_file);// courser moves ahead , as we read
fseek(out_file,-1,SEEK_CUR); // bringing courser back
}
else if(ch == ch1)
{para++; //paragraph counter
word_count--;
}
if(ch==' '||ch=='\n')
{
word_count++;
}
if(ch==EOF)
{
word_count++;line++;para++;
}
}
non_alnum -=1;// EOF character subtracted.
charac = alpha_count + non_alnum + num_count;
fclose(out_file);
printf("#Paragraphs = %d\n",para);
printf("#lines = %d\n",line);
printf("#Words = %d\n",word_count);
printf("#Characters = %d\n",charac);
printf("Alpha = %d\n",alpha_count);
printf("Numerical = %d\n",num_count);
printf("Other = %d\n",non_alnum);
printf("\n");
return;
}
This is part of the program I am working on, it is copying the file opened and then put it into an array (file1). However, I am getting a segmentation fault when I try to print out the content of the file1.
I had tried to set the MAX_MAC_ADD to 50 and BIG_NUM to 30000 such that it is big enough to sustain the file from fgets().
The file which I am opening has 4 parts, each separate by a 'tab'
e.g. 1one 1two 1three 1four
2one 2two 2three 2four
char file1[MAX_MAC_ADD][BIG_NUM];
int num_MAC = 0;
char *Programe_Name;
int saperate_fields1(char line[])
{
int i = 0;
int f = 0;
while(line[i] != '\0' && line[i] != '\n')
{
int c = 0;
while(line[i] != '\t' && line[i] != '\0' && line[i] != '\n')
{
file1[f][c] = line[i];
++c;
++i;
}
file1[f][c] = '\0';
++f;
if(f == (MAX_MAC_ADD-1))
{
break;
}
++i;
}
return f,i;
}
void read_file1(char filename[])
{
//OPEN FOR READING
FILE *fp = fopen(filename,"r");
if(fp == NULL)
{
printf("%s: cannot open '%s'\n", Programe_Name, filename);
exit(EXIT_FAILURE);
}
char line[BUFSIZ];
while(fgets(line, sizeof line, fp) != NULL)
{
saperate_fields1(line); //SAPERATE INTO FIELDS
num_MAC = num_MAC + 1;
printf("%d times\n", num_MAC);
}
fclose(fp);
printf("line is:\n%s\n", line); //TO CHECK WHERE DO THE PROGRAM STOP READING
printf("file1 is:\n%s\n", file1);
}
You pass a pointer to an array of chars to the format specifier %s which expects a pointer to a char. If you want to print your array of arrays of char you need to print the elements individually, e.g.:
for (int i = 0; i != end; ++i) {
printf("file1[%d]='%s'\n", i, file1[i]);
}